summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorStar Rauchenberger <fefferburbia@gmail.com>2025-02-20 21:39:04 -0500
committerStar Rauchenberger <fefferburbia@gmail.com>2025-02-20 21:39:04 -0500
commitd1baf62bea385c75ad4e7612e5caa285400ffaa7 (patch)
tree79cc011c17eb3d6d19c1750834d95e4446744a12
parent6ffa77c6a55f181577d1c5dca88c96f9863cca08 (diff)
downloadmanifold-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.cs133
-rw-r--r--GameData.cs18
-rw-r--r--ManifoldGardenArchipelago.csproj1
-rw-r--r--Plugin.cs74
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 @@
1using Archipelago.MultiClient.Net;
2using Archipelago.MultiClient.Net.Enums;
3using Archipelago.MultiClient.Net.Models;
4using Archipelago.MultiClient.Net.Packets;
5using System;
6using System.Collections.Generic;
7using System.Linq;
8using System.Reflection;
9using System.Text;
10using System.Threading.Tasks;
11using UnityEngine.SceneManagement;
12using static ManifoldGardenArchipelago.GameData;
13
14namespace 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 @@
1using System.Collections.Generic;
2
3namespace 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 @@
1using BepInEx; 1using BepInEx;
2using BepInEx.Logging; 2using BepInEx.Logging;
3using HarmonyLib;
4using System.Linq;
5using System.Reflection;
3 6
4namespace ManifoldGardenArchipelago 7namespace 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}