using System; using System.Linq; using System.Reflection; using UnityEngine; using UnityEngine.SceneManagement; namespace ManifoldGardenArchipelago { public class GameState { public static LevelSystems GetLevelSystems(Component component) { return GetLevelSystems(component.gameObject.scene); } public static LevelSystems GetLevelSystems(Scene scene) { foreach (GameObject gameObject in scene.GetRootGameObjects()) { if (gameObject.name == "Level Systems") { return gameObject.GetComponent(); } } Plugin.Logger.LogWarning($"Could not find Level Systems for {scene.name}"); return null; } public static SceneItemReference GetChainListenerSceneReference(Component component) { LevelSystems levelSystem = GetLevelSystems(component); for (int i = 0; i < levelSystem.chainListeners.Count(); i++) { if (levelSystem.chainListeners[i] == component) { return new(component.gameObject.scene.name, i); } } Plugin.Logger.LogWarning($"Could not find SIR for chain listener {component.name}"); throw new Exception("Shouldn't happen"); } public static SceneItemReference GetGameplayComponentSceneReference(Component component) { LevelSystems levelSystem = GetLevelSystems(component); for (int i = 0; i < levelSystem.gameplayComponentsInLevel.Count(); i++) { if (levelSystem.gameplayComponentsInLevel[i] == component) { return new(component.gameObject.scene.name, i); } } Plugin.Logger.LogWarning($"Could not find SIR for gameplay component {component.name}"); throw new Exception("Shouldn't happen"); } public static SceneItemReference GetButtonSceneReference(ButtonLineActivator arg) { LevelSystems levelSystem = GetLevelSystems(arg); for (int i = 0; i < levelSystem.buttonLineActivators.Count(); i++) { if (levelSystem.buttonLineActivators[i] == arg) { return new(arg.gameObject.scene.name, i); } } Plugin.Logger.LogWarning($"Could not find SIR for button {arg.name}"); throw new Exception("Shouldn't happen"); } public static SceneItemReference GetPadSceneReference(CubeLineActivator arg) { LevelSystems levelSystem = GetLevelSystems(arg); for (int i = 0; i < levelSystem.cubeLineActivators.Count(); i++) { if (levelSystem.cubeLineActivators[i] == arg) { return new(arg.gameObject.scene.name, i); } } Plugin.Logger.LogWarning($"Could not find SIR for pad {arg.name}"); throw new Exception("Shouldn't happen"); } public static SceneItemReference GetSocketSceneReference(CubeReceiverController arg) { LevelSystems levelSystem = GetLevelSystems(arg); for (int i = 0; i < levelSystem.cubeReceiverControllers.Count(); i++) { if (levelSystem.cubeReceiverControllers[i] == arg) { return new(arg.gameObject.scene.name, i); } } Plugin.Logger.LogWarning($"Could not find SIR for socket {arg.name}"); throw new Exception("Shouldn't happen"); } public static SceneItemReference GetSphereSceneReference(SphereController arg) { LevelSystems levelSystem = GetLevelSystems(arg); for (int i = 0; i < levelSystem.sphereControllers.Count(); i++) { if (levelSystem.sphereControllers[i] == arg) { return new(arg.gameObject.scene.name, i); } } Plugin.Logger.LogWarning($"Could not find SIR for sphere {arg.name}"); throw new Exception("Shouldn't happen"); } public static SceneItemReference GetWaterwheelSceneReference(WaterDetector arg) { LevelSystems levelSystem = GetLevelSystems(arg); for (int i = 0; i < levelSystem.waterDetectors.Count(); i++) { if (levelSystem.waterDetectors[i] == arg) { return new(arg.gameObject.scene.name, i); } } Plugin.Logger.LogWarning($"Could not find SIR for waterwheel {arg.name}"); throw new Exception("Shouldn't happen"); } public static void EvaluateGameStateListeners(GameStateListeners listeners) { foreach (var location in listeners.locations) { if (location.Value.Check() == Requirement.Decision.Yes) { Plugin.archipelagoManager.CheckLocation(location.Key); } } foreach (var door in listeners.doors) { Requirement.Decision decision = door.Value.Check(); if (decision == Requirement.Decision.Maybe) { continue; } bool shouldOpen = (decision == Requirement.Decision.Yes); //Plugin.Logger.LogInfo($"{door.Key}: {door.Value} -> {shouldOpen}"); if (SceneManager.GetSceneByName(door.Key.scene) is Scene doorScene && doorScene.IsValid() && doorScene.isLoaded) { LevelSystems levelSystems = GetLevelSystems(doorScene); if (levelSystems.isActiveAndEnabled) { LineDoorController ldc = levelSystems.chainListeners[door.Key.index].GetComponent(); ldc.chains.Clear(); FieldInfo fieldInfo = typeof(LineDoorController).GetField("doorShouldOpenImmediatelyOnEnable", BindingFlags.Instance | BindingFlags.NonPublic); fieldInfo.SetValue(ldc, shouldOpen); MethodInfo methodInfo = typeof(LineDoorController).GetMethod("SetDoorOpenCloseStateAnimated", BindingFlags.NonPublic | BindingFlags.Instance); methodInfo.Invoke(ldc, [shouldOpen, false]); ldc.saveData.isOpen = shouldOpen; } } } foreach (var smokeWall in listeners.smokeWalls) { Requirement.Decision decision = smokeWall.Value.Check(); if (decision == Requirement.Decision.Maybe) { continue; } bool shouldOpen = (decision == Requirement.Decision.Yes); //Plugin.Logger.LogInfo($"{smokeWall.Key}: {smokeWall.Value} -> {shouldOpen}"); if (SceneManager.GetSceneByName(smokeWall.Key.scene) is Scene smokeScene && smokeScene.IsValid() && smokeScene.isLoaded) { LevelSystems levelSystems = GetLevelSystems(smokeScene); if (levelSystems.isActiveAndEnabled) { SolidStateController ldc = levelSystems.chainListeners[smokeWall.Key.index].GetComponent(); ldc.chains.Clear(); FieldInfo fieldInfo = typeof(SolidStateController).GetField("m_isSolid", BindingFlags.Instance | BindingFlags.NonPublic); fieldInfo.SetValue(ldc, !shouldOpen); } } } foreach (var worldGrow in listeners.worldGrows) { if (worldGrow.Value.Check() == Requirement.Decision.Yes) { if (SceneManager.GetSceneByName(worldGrow.Key.scene) is Scene gardenScene && gardenScene.IsValid() && gardenScene.isLoaded) { LevelSystems levelSystems = GetLevelSystems(gardenScene); if (levelSystems.isActiveAndEnabled) { DarkModeCollapsedCubeWorldGrow ldc = levelSystems.chainListeners[worldGrow.Key.index].GetComponent(); ldc.chains.Clear(); FieldInfo fieldInfo = typeof(DarkModeCollapsedCubeWorldGrow).GetField("m_grown", BindingFlags.Instance | BindingFlags.NonPublic); fieldInfo.SetValue(ldc, true); } } } } foreach (var laser in listeners.lasers) { Requirement.Decision decision = laser.Value.Check(); if (decision == Requirement.Decision.Maybe) { continue; } bool shouldOpen = (decision == Requirement.Decision.Yes); if (SceneManager.GetSceneByName(laser.Key.scene) is Scene laserScene && laserScene.IsValid() && laserScene.isLoaded) { LevelSystems levelSystems = GetLevelSystems(laserScene); if (levelSystems.isActiveAndEnabled) { DarkModeCageController ldc = levelSystems.gameplayComponentsInLevel[laser.Key.index].GetComponent(); if (shouldOpen) { MethodInfo methodInfo = typeof(DarkModeCageController).GetMethod("OpenLaserSource", BindingFlags.Instance | BindingFlags.NonPublic); methodInfo.Invoke(ldc, [false]); } else { MethodInfo methodInfo = typeof(DarkModeCageController).GetMethod("CloseLaserSource", BindingFlags.Instance | BindingFlags.NonPublic); methodInfo.Invoke(ldc, [false]); } } } } } } }