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 component.gameObject.scene.GetRootGameObjects().Single((obj) => obj.name == "Level Systems").GetComponent(); } public static LevelSystems GetLevelSystems(Scene scene) { return scene.GetRootGameObjects().Single((obj) => obj.name == "Level Systems").GetComponent(); } 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); } } 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); } } 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); } } 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); } } 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); } } 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); } } throw new Exception("Shouldn't happen"); } public static void EvaluateGameStateListeners(GameStateListeners listeners) { foreach (var location in listeners.locations) { if (location.Value.Check()) { Plugin.archipelagoManager.CheckLocation(location.Key); } } foreach (var door in listeners.doors) { bool shouldOpen = door.Value.Check(); Plugin.Logger.LogInfo($"{door.Key}: {door.Value} -> {shouldOpen}"); if (SceneManager.GetSceneByName(door.Key.scene) is Scene doorScene && 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 worldGrow in listeners.worldGrows) { if (worldGrow.Value.Check()) { if (SceneManager.GetSceneByName(worldGrow.Key.scene) is Scene gardenScene && 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); } } } } } } }