diff options
author | Star Rauchenberger <fefferburbia@gmail.com> | 2025-02-20 21:39:04 -0500 |
---|---|---|
committer | Star Rauchenberger <fefferburbia@gmail.com> | 2025-02-20 21:39:04 -0500 |
commit | d1baf62bea385c75ad4e7612e5caa285400ffaa7 (patch) | |
tree | 79cc011c17eb3d6d19c1750834d95e4446744a12 | |
parent | 6ffa77c6a55f181577d1c5dca88c96f9863cca08 (diff) | |
download | manifold-garden-archipelago-d1baf62bea385c75ad4e7612e5caa285400ffaa7.tar.gz manifold-garden-archipelago-d1baf62bea385c75ad4e7612e5caa285400ffaa7.tar.bz2 manifold-garden-archipelago-d1baf62bea385c75ad4e7612e5caa285400ffaa7.zip |
Opening a door via an item!
-rw-r--r-- | ArchipelagoManager.cs | 133 | ||||
-rw-r--r-- | GameData.cs | 18 | ||||
-rw-r--r-- | ManifoldGardenArchipelago.csproj | 1 | ||||
-rw-r--r-- | Plugin.cs | 74 |
4 files changed, 226 insertions, 0 deletions
diff --git a/ArchipelagoManager.cs b/ArchipelagoManager.cs new file mode 100644 index 0000000..7affa64 --- /dev/null +++ b/ArchipelagoManager.cs | |||
@@ -0,0 +1,133 @@ | |||
1 | using Archipelago.MultiClient.Net; | ||
2 | using Archipelago.MultiClient.Net.Enums; | ||
3 | using Archipelago.MultiClient.Net.Models; | ||
4 | using Archipelago.MultiClient.Net.Packets; | ||
5 | using System; | ||
6 | using System.Collections.Generic; | ||
7 | using System.Linq; | ||
8 | using System.Reflection; | ||
9 | using System.Text; | ||
10 | using System.Threading.Tasks; | ||
11 | using UnityEngine.SceneManagement; | ||
12 | using static ManifoldGardenArchipelago.GameData; | ||
13 | |||
14 | namespace ManifoldGardenArchipelago | ||
15 | { | ||
16 | public class ArchipelagoManager | ||
17 | { | ||
18 | private ArchipelagoSession _session; | ||
19 | private int _itemIndex = 0; | ||
20 | |||
21 | public Dictionary<string, Dictionary<int, bool>> chainListenersByScene = new(); | ||
22 | |||
23 | public ArchipelagoManager() | ||
24 | { | ||
25 | foreach (var item in GameData.door_by_item) | ||
26 | { | ||
27 | foreach (var chainListenerReference in item.Value) | ||
28 | { | ||
29 | if (!chainListenersByScene.TryGetValue(chainListenerReference.scene, out var listenersInScene)) | ||
30 | { | ||
31 | listenersInScene = []; | ||
32 | chainListenersByScene.Add(chainListenerReference.scene, listenersInScene); | ||
33 | } | ||
34 | |||
35 | listenersInScene[chainListenerReference.index] = false; | ||
36 | } | ||
37 | } | ||
38 | } | ||
39 | |||
40 | public async Task<LoginResult> Connect(string url, string slotName, string password) | ||
41 | { | ||
42 | LoginResult result; | ||
43 | try | ||
44 | { | ||
45 | _session = ArchipelagoSessionFactory.CreateSession(url); | ||
46 | |||
47 | RoomInfoPacket roomInfoPacket = await _session.ConnectAsync(); | ||
48 | |||
49 | result = await _session.LoginAsync("Manifold Garden", slotName, ItemsHandlingFlags.AllItems, null, null, null, password == "" ? null : password); | ||
50 | } | ||
51 | catch (Exception ex) | ||
52 | { | ||
53 | return new LoginFailure(ex.GetBaseException().Message); | ||
54 | } | ||
55 | |||
56 | return result; | ||
57 | } | ||
58 | |||
59 | ~ArchipelagoManager() | ||
60 | { | ||
61 | Disconnect(); | ||
62 | } | ||
63 | |||
64 | public void Disconnect() | ||
65 | { | ||
66 | if (_session == null) | ||
67 | { | ||
68 | return; | ||
69 | } | ||
70 | |||
71 | _session.Socket.DisconnectAsync(); | ||
72 | _session = null; | ||
73 | } | ||
74 | |||
75 | public void Update() | ||
76 | { | ||
77 | if (_session == null) | ||
78 | { | ||
79 | return; | ||
80 | } | ||
81 | |||
82 | if (_session.Items.AllItemsReceived.Count > _itemIndex) | ||
83 | { | ||
84 | for (int i = _itemIndex; i < _session.Items.AllItemsReceived.Count; i++) | ||
85 | { | ||
86 | ItemInfo item = _session.Items.AllItemsReceived[i]; | ||
87 | string itemName = item.ItemName; | ||
88 | |||
89 | if (GameData.door_by_item.TryGetValue(itemName, out List<GameData.ChainListenerReference> door)) | ||
90 | { | ||
91 | foreach (GameData.ChainListenerReference chainListenerReference in door) | ||
92 | { | ||
93 | chainListenersByScene[chainListenerReference.scene][chainListenerReference.index] = true; | ||
94 | |||
95 | if (SceneManager.GetSceneByName(chainListenerReference.scene) is Scene doorScene && doorScene.isLoaded) | ||
96 | { | ||
97 | LevelSystems levelSystems = doorScene.GetRootGameObjects().Single((obj) => obj.name == "Level Systems").GetComponent<LevelSystems>(); | ||
98 | if (levelSystems.isActiveAndEnabled) | ||
99 | { | ||
100 | LineDoorController ldc = levelSystems.chainListeners[chainListenerReference.index].GetComponent<LineDoorController>(); | ||
101 | ldc.chains.Clear(); | ||
102 | |||
103 | FieldInfo fieldInfo = typeof(LineDoorController).GetField("doorShouldOpenImmediatelyOnEnable", BindingFlags.Instance | BindingFlags.NonPublic); | ||
104 | fieldInfo.SetValue(ldc, true); | ||
105 | |||
106 | MethodInfo methodInfo = typeof(LineDoorController).GetMethod("SetDoorOpenCloseStateAnimated", BindingFlags.NonPublic | BindingFlags.Instance); | ||
107 | methodInfo.Invoke(ldc, [true, false]); | ||
108 | } | ||
109 | } | ||
110 | } | ||
111 | } | ||
112 | } | ||
113 | |||
114 | _itemIndex = _session.Items.AllItemsReceived.Count; | ||
115 | |||
116 | /* | ||
117 | var hi = new StringBuilder(); | ||
118 | foreach (var thing in chainListenersByScene) | ||
119 | { | ||
120 | hi.AppendLine(thing.Key); | ||
121 | |||
122 | foreach (var thing2 in thing.Value) | ||
123 | { | ||
124 | hi.AppendLine($" {thing2.Key}: {thing2.Value}"); | ||
125 | } | ||
126 | } | ||
127 | |||
128 | Plugin.Logger.LogInfo( hi.ToString() ); | ||
129 | */ | ||
130 | } | ||
131 | } | ||
132 | } | ||
133 | } | ||
diff --git a/GameData.cs b/GameData.cs new file mode 100644 index 0000000..87278ac --- /dev/null +++ b/GameData.cs | |||
@@ -0,0 +1,18 @@ | |||
1 | using System.Collections.Generic; | ||
2 | |||
3 | namespace ManifoldGardenArchipelago | ||
4 | { | ||
5 | public class GameData | ||
6 | { | ||
7 | public readonly struct ChainListenerReference(string scene_arg, int index_arg) | ||
8 | { | ||
9 | public readonly string scene = scene_arg; | ||
10 | public readonly int index = index_arg; | ||
11 | } | ||
12 | |||
13 | public static readonly Dictionary<string, List<ChainListenerReference>> door_by_item = new() | ||
14 | { | ||
15 | {"Blue Secret Path", [new ChainListenerReference("World_000_Optimized", 16)] } | ||
16 | }; | ||
17 | } | ||
18 | } | ||
diff --git a/ManifoldGardenArchipelago.csproj b/ManifoldGardenArchipelago.csproj index e19509b..5d20001 100644 --- a/ManifoldGardenArchipelago.csproj +++ b/ManifoldGardenArchipelago.csproj | |||
@@ -20,6 +20,7 @@ | |||
20 | </PropertyGroup> | 20 | </PropertyGroup> |
21 | 21 | ||
22 | <ItemGroup> | 22 | <ItemGroup> |
23 | <PackageReference Include="Archipelago.MultiClient.Net" Version="6.5.0" /> | ||
23 | <PackageReference Include="BepInEx.Analyzers" Version="1.*" PrivateAssets="all" /> | 24 | <PackageReference Include="BepInEx.Analyzers" Version="1.*" PrivateAssets="all" /> |
24 | <PackageReference Include="BepInEx.Core" Version="5.*" /> | 25 | <PackageReference Include="BepInEx.Core" Version="5.*" /> |
25 | <PackageReference Include="BepInEx.PluginInfoProps" Version="2.*" /> | 26 | <PackageReference Include="BepInEx.PluginInfoProps" Version="2.*" /> |
diff --git a/Plugin.cs b/Plugin.cs index 5f49f5f..50e6e2b 100644 --- a/Plugin.cs +++ b/Plugin.cs | |||
@@ -1,5 +1,8 @@ | |||
1 | using BepInEx; | 1 | using BepInEx; |
2 | using BepInEx.Logging; | 2 | using BepInEx.Logging; |
3 | using HarmonyLib; | ||
4 | using System.Linq; | ||
5 | using System.Reflection; | ||
3 | 6 | ||
4 | namespace ManifoldGardenArchipelago | 7 | namespace ManifoldGardenArchipelago |
5 | { | 8 | { |
@@ -8,11 +11,82 @@ namespace ManifoldGardenArchipelago | |||
8 | { | 11 | { |
9 | internal static new ManualLogSource Logger; | 12 | internal static new ManualLogSource Logger; |
10 | 13 | ||
14 | public static ArchipelagoManager archipelagoManager = new(); | ||
15 | |||
11 | private void Awake() | 16 | private void Awake() |
12 | { | 17 | { |
13 | // Plugin startup logic | 18 | // Plugin startup logic |
14 | Logger = base.Logger; | 19 | Logger = base.Logger; |
15 | Logger.LogInfo($"Plugin {MyPluginInfo.PLUGIN_GUID} is loaded!"); | 20 | Logger.LogInfo($"Plugin {MyPluginInfo.PLUGIN_GUID} is loaded!"); |
21 | |||
22 | Harmony.CreateAndPatchAll(Assembly.GetExecutingAssembly()); | ||
23 | |||
24 | archipelagoManager.Connect("localhost:38281", "Manifold", "").RunSynchronously(); | ||
25 | } | ||
26 | } | ||
27 | |||
28 | [HarmonyPatch(typeof(GameManager), "Update")] | ||
29 | static class GameManagerUpdatePatch | ||
30 | { | ||
31 | static void Postfix() | ||
32 | { | ||
33 | Plugin.archipelagoManager.Update(); | ||
16 | } | 34 | } |
17 | } | 35 | } |
36 | |||
37 | [HarmonyPatch(typeof(LineDoorController), "SetDoorOpenCloseStateAnimated")] | ||
38 | static class LineDoorControllerSetDoorOpenCloseStateAnimatedPatch | ||
39 | { | ||
40 | static bool Prefix(LineDoorController __instance, bool open) | ||
41 | { | ||
42 | if (Plugin.archipelagoManager.chainListenersByScene.TryGetValue(__instance.gameObject.scene.name, out var activatedChainListeners)) | ||
43 | { | ||
44 | LevelSystems levelSystem = __instance.gameObject.scene.GetRootGameObjects().Single((obj) => obj.name == "Level Systems").GetComponent<LevelSystems>(); | ||
45 | |||
46 | foreach (var listener in activatedChainListeners) | ||
47 | { | ||
48 | if (levelSystem.chainListeners[listener.Key] == __instance) | ||
49 | { | ||
50 | if (open != listener.Value) | ||
51 | { | ||
52 | return false; | ||
53 | } | ||
54 | } | ||
55 | } | ||
56 | } | ||
57 | |||
58 | return true; | ||
59 | } | ||
60 | } | ||
61 | |||
62 | [HarmonyPatch(typeof(LineDoorController), nameof(LineDoorController.OnLevelEnable))] | ||
63 | static class LineDoorControllerOnLevelEnablePatch | ||
64 | { | ||
65 | static void Prefix(LineDoorController __instance) | ||
66 | { | ||
67 | if (Plugin.archipelagoManager.chainListenersByScene.TryGetValue(__instance.gameObject.scene.name, out var activatedChainListeners)) | ||
68 | { | ||
69 | LevelSystems levelSystem = __instance.gameObject.scene.GetRootGameObjects().Single((obj) => obj.name == "Level Systems").GetComponent<LevelSystems>(); | ||
70 | |||
71 | foreach (var listener in activatedChainListeners) | ||
72 | { | ||
73 | if (levelSystem.chainListeners[listener.Key] == __instance) | ||
74 | { | ||
75 | FieldInfo fieldInfo = typeof(LineDoorController).GetField("doorShouldOpenImmediatelyOnEnable", BindingFlags.Instance | BindingFlags.NonPublic); | ||
76 | fieldInfo.SetValue(__instance, listener.Value); | ||
77 | } | ||
78 | } | ||
79 | } | ||
80 | } | ||
81 | } | ||
82 | |||
83 | [HarmonyPatch(typeof(ButtonLineActivator), nameof(ButtonLineActivator.OnInteract))] | ||
84 | static class ButtonLineActivatorOnInteractPatch | ||
85 | { | ||
86 | public static void Postfix(ButtonLineActivator __instance) | ||
87 | { | ||
88 | Plugin.Logger.LogInfo($"Interacted with {__instance.name} in {__instance.gameObject.scene.name}: {__instance.isButtonPressed}"); | ||
89 | } | ||
90 | } | ||
91 | |||
18 | } | 92 | } |