diff options
| -rw-r--r-- | AnodyneArchipelago/AnodyneArchipelago.csproj | 3 | ||||
| -rw-r--r-- | AnodyneArchipelago/ArchipelagoManager.cs | 110 | ||||
| -rw-r--r-- | AnodyneArchipelago/ArchipelagoTreasure.cs | 21 | ||||
| -rw-r--r-- | AnodyneArchipelago/Locations.cs | 20 | ||||
| -rw-r--r-- | AnodyneArchipelago/Plugin.cs | 51 |
5 files changed, 203 insertions, 2 deletions
| diff --git a/AnodyneArchipelago/AnodyneArchipelago.csproj b/AnodyneArchipelago/AnodyneArchipelago.csproj index 5ad5e82..abe6c23 100644 --- a/AnodyneArchipelago/AnodyneArchipelago.csproj +++ b/AnodyneArchipelago/AnodyneArchipelago.csproj | |||
| @@ -32,5 +32,8 @@ | |||
| 32 | <Reference Include="BepInEx.NET.Common"> | 32 | <Reference Include="BepInEx.NET.Common"> |
| 33 | <HintPath>..\..\BepInEx\bin\NET.Framework\net462\BepInEx.NET.Common.dll</HintPath> | 33 | <HintPath>..\..\BepInEx\bin\NET.Framework\net462\BepInEx.NET.Common.dll</HintPath> |
| 34 | </Reference> | 34 | </Reference> |
| 35 | <Reference Include="FNA"> | ||
| 36 | <HintPath>..\..\..\SteamLibrary\steamapps\common\Anodyne\Remake\FNA.dll</HintPath> | ||
| 37 | </Reference> | ||
| 35 | </ItemGroup> | 38 | </ItemGroup> |
| 36 | </Project> | 39 | </Project> |
| diff --git a/AnodyneArchipelago/ArchipelagoManager.cs b/AnodyneArchipelago/ArchipelagoManager.cs index 8c107a3..4ffa3af 100644 --- a/AnodyneArchipelago/ArchipelagoManager.cs +++ b/AnodyneArchipelago/ArchipelagoManager.cs | |||
| @@ -1,12 +1,21 @@ | |||
| 1 | using Archipelago.MultiClient.Net; | 1 | using AnodyneSharp.Entities; |
| 2 | using AnodyneSharp.Registry; | ||
| 3 | using Archipelago.MultiClient.Net; | ||
| 2 | using Archipelago.MultiClient.Net.Enums; | 4 | using Archipelago.MultiClient.Net.Enums; |
| 5 | using Archipelago.MultiClient.Net.Models; | ||
| 6 | using Archipelago.MultiClient.Net.Packets; | ||
| 3 | using System; | 7 | using System; |
| 8 | using System.Collections.Generic; | ||
| 9 | using System.Linq; | ||
| 4 | 10 | ||
| 5 | namespace AnodyneArchipelago | 11 | namespace AnodyneArchipelago |
| 6 | { | 12 | { |
| 7 | internal class ArchipelagoManager | 13 | internal class ArchipelagoManager |
| 8 | { | 14 | { |
| 9 | private static ArchipelagoSession _session; | 15 | private static ArchipelagoSession _session; |
| 16 | private static int _itemIndex = 0; | ||
| 17 | |||
| 18 | private static readonly Queue<NetworkItem> _itemsToCollect = new(); | ||
| 10 | 19 | ||
| 11 | public static void Connect(string url, string slotName, string password) | 20 | public static void Connect(string url, string slotName, string password) |
| 12 | { | 21 | { |
| @@ -38,6 +47,105 @@ namespace AnodyneArchipelago | |||
| 38 | 47 | ||
| 39 | return; | 48 | return; |
| 40 | } | 49 | } |
| 50 | |||
| 51 | _itemIndex = 0; | ||
| 52 | _itemsToCollect.Clear(); | ||
| 53 | } | ||
| 54 | |||
| 55 | public static void Disconnect() | ||
| 56 | { | ||
| 57 | if (_session == null) | ||
| 58 | { | ||
| 59 | return; | ||
| 60 | } | ||
| 61 | |||
| 62 | _session.Socket.DisconnectAsync(); | ||
| 63 | _session = null; | ||
| 64 | } | ||
| 65 | |||
| 66 | public static void SendLocation(string location) | ||
| 67 | { | ||
| 68 | if (_session == null) | ||
| 69 | { | ||
| 70 | Plugin.Instance.Log.LogError("Attempted to send location while disconnected"); | ||
| 71 | return; | ||
| 72 | } | ||
| 73 | |||
| 74 | _session.Locations.CompleteLocationChecks(_session.Locations.GetLocationIdFromName("Anodyne", location)); | ||
| 75 | } | ||
| 76 | |||
| 77 | public static void Update() | ||
| 78 | { | ||
| 79 | if (_session == null) | ||
| 80 | { | ||
| 81 | // We're not connected. | ||
| 82 | return; | ||
| 83 | } | ||
| 84 | |||
| 85 | if (_session.Items.AllItemsReceived.Count > _itemIndex) | ||
| 86 | { | ||
| 87 | for (int i = _itemIndex; i < _session.Items.AllItemsReceived.Count; i++) | ||
| 88 | { | ||
| 89 | string itemKey = $"ArchipelagoItem-{i}"; | ||
| 90 | if (GlobalState.events.GetEvent(itemKey) != 0) | ||
| 91 | { | ||
| 92 | continue; | ||
| 93 | } | ||
| 94 | |||
| 95 | GlobalState.events.SetEvent(itemKey, 1); | ||
| 96 | |||
| 97 | NetworkItem item = _session.Items.AllItemsReceived[i]; | ||
| 98 | _itemsToCollect.Enqueue(item); | ||
| 99 | } | ||
| 100 | } | ||
| 101 | |||
| 102 | if (_itemsToCollect.Count > 0) | ||
| 103 | { | ||
| 104 | NetworkItem item = _itemsToCollect.Dequeue(); | ||
| 105 | HandleItem(item); | ||
| 106 | } | ||
| 107 | } | ||
| 108 | |||
| 109 | private static string GetMapNameForDungeon(string dungeon) | ||
| 110 | { | ||
| 111 | switch (dungeon) | ||
| 112 | { | ||
| 113 | case "Temple of the Seeing One": return "BEDROOM"; | ||
| 114 | case "Apartment": return "APARTMENT"; | ||
| 115 | case "Mountain Cavern": return "CROWD"; | ||
| 116 | case "Hotel": return "HOTEL"; | ||
| 117 | case "Red Grotto": return "REDCAVE"; | ||
| 118 | case "Circus": return "CIRCUS"; | ||
| 119 | default: return "STREET"; | ||
| 120 | } | ||
| 121 | } | ||
| 122 | |||
| 123 | private static void HandleItem(NetworkItem item) | ||
| 124 | { | ||
| 125 | string itemName = _session.Items.GetItemName(item.Item); | ||
| 126 | |||
| 127 | if (itemName.StartsWith("Small Key")) | ||
| 128 | { | ||
| 129 | string dungeonName = itemName.Substring(11); | ||
| 130 | dungeonName = dungeonName.Substring(0, dungeonName.Length - 1); | ||
| 131 | |||
| 132 | string mapName = GetMapNameForDungeon(dungeonName); | ||
| 133 | GlobalState.inventory.AddMapKey(mapName, 1); | ||
| 134 | } else if (itemName == "Green Key") | ||
| 135 | { | ||
| 136 | GlobalState.inventory.BigKeyStatus[0] = true; | ||
| 137 | } | ||
| 138 | else if (itemName == "Blue Key") | ||
| 139 | { | ||
| 140 | GlobalState.inventory.BigKeyStatus[2] = true; | ||
| 141 | } | ||
| 142 | else if (itemName == "Red Key") | ||
| 143 | { | ||
| 144 | GlobalState.inventory.BigKeyStatus[1] = true; | ||
| 145 | } else if (itemName == "Jump Shoes") | ||
| 146 | { | ||
| 147 | GlobalState.inventory.CanJump = true; | ||
| 148 | } | ||
| 41 | } | 149 | } |
| 42 | } | 150 | } |
| 43 | } | 151 | } |
| diff --git a/AnodyneArchipelago/ArchipelagoTreasure.cs b/AnodyneArchipelago/ArchipelagoTreasure.cs new file mode 100644 index 0000000..6d000e8 --- /dev/null +++ b/AnodyneArchipelago/ArchipelagoTreasure.cs | |||
| @@ -0,0 +1,21 @@ | |||
| 1 | using AnodyneSharp.Entities.Gadget.Treasures; | ||
| 2 | using Microsoft.Xna.Framework; | ||
| 3 | |||
| 4 | namespace AnodyneArchipelago | ||
| 5 | { | ||
| 6 | internal class ArchipelagoTreasure : Treasure | ||
| 7 | { | ||
| 8 | private string _location; | ||
| 9 | |||
| 10 | public ArchipelagoTreasure(string location, Vector2 pos) : base("item_jump_shoes", pos, 0, -1) | ||
| 11 | { | ||
| 12 | _location = location; | ||
| 13 | } | ||
| 14 | |||
| 15 | public override void GetTreasure() | ||
| 16 | { | ||
| 17 | base.GetTreasure(); | ||
| 18 | ArchipelagoManager.SendLocation(_location); | ||
| 19 | } | ||
| 20 | } | ||
| 21 | } | ||
| diff --git a/AnodyneArchipelago/Locations.cs b/AnodyneArchipelago/Locations.cs new file mode 100644 index 0000000..46e2471 --- /dev/null +++ b/AnodyneArchipelago/Locations.cs | |||
| @@ -0,0 +1,20 @@ | |||
| 1 | | ||
| 2 | using System; | ||
| 3 | using System.Collections.Generic; | ||
| 4 | |||
| 5 | namespace AnodyneArchipelago | ||
| 6 | { | ||
| 7 | internal class Locations | ||
| 8 | { | ||
| 9 | public static Dictionary<Guid, string> LocationsByGuid = new() | ||
| 10 | { | ||
| 11 | {new Guid("40de36cf-9238-f8b0-7a57-c6c8ca465cc2"), "Temple of the Seeing One - Entrance Chest" }, | ||
| 12 | {new Guid("621c284f-cbd0-74c3-f51b-2a9fdde8d4d7"), "Temple of the Seeing One - Rock-Surrounded Chest" }, | ||
| 13 | {new Guid("401939a4-41ba-e07e-3ba2-dc22513dcc5c"), "Temple of the Seeing One - Dark Room Chest" }, | ||
| 14 | {new Guid("88d0a7b8-eeab-c45f-324e-f1c7885c41ce"), "Temple of the Seeing One - Shieldy Room Chest" }, | ||
| 15 | {new Guid("0bce5346-48a2-47f9-89cb-3f59d9d0b7d2"), "Temple of the Seeing One - Boss Chest" }, | ||
| 16 | {new Guid("d41f2750-e3c7-bbb4-d650-fafc190ebd32"), "Temple of the Seeing One - After Statue Left Chest" }, | ||
| 17 | {new Guid("3167924e-5d52-1cd6-d6f4-b8e0e328215b"), "Temple of the Seeing One - After Statue Right Chest" }, | ||
| 18 | }; | ||
| 19 | } | ||
| 20 | } | ||
| diff --git a/AnodyneArchipelago/Plugin.cs b/AnodyneArchipelago/Plugin.cs index 7375503..f49ba35 100644 --- a/AnodyneArchipelago/Plugin.cs +++ b/AnodyneArchipelago/Plugin.cs | |||
| @@ -1,7 +1,12 @@ | |||
| 1 | using BepInEx; | 1 | using AnodyneSharp; |
| 2 | using AnodyneSharp.Entities; | ||
| 3 | using AnodyneSharp.Entities.Gadget; | ||
| 4 | using AnodyneSharp.Entities.Gadget.Treasures; | ||
| 5 | using BepInEx; | ||
| 2 | using BepInEx.NET.Common; | 6 | using BepInEx.NET.Common; |
| 3 | using HarmonyLib; | 7 | using HarmonyLib; |
| 4 | using HarmonyLib.Tools; | 8 | using HarmonyLib.Tools; |
| 9 | using System; | ||
| 5 | using System.Reflection; | 10 | using System.Reflection; |
| 6 | 11 | ||
| 7 | namespace AnodyneArchipelago | 12 | namespace AnodyneArchipelago |
| @@ -26,6 +31,15 @@ namespace AnodyneArchipelago | |||
| 26 | } | 31 | } |
| 27 | } | 32 | } |
| 28 | 33 | ||
| 34 | [HarmonyPatch(typeof(AnodyneGame), "Update")] | ||
| 35 | class GameUpdatePatch | ||
| 36 | { | ||
| 37 | static void Postfix() | ||
| 38 | { | ||
| 39 | ArchipelagoManager.Update(); | ||
| 40 | } | ||
| 41 | } | ||
| 42 | |||
| 29 | [HarmonyPatch(typeof(AnodyneSharp.States.PlayState), nameof(AnodyneSharp.States.PlayState.Create))] | 43 | [HarmonyPatch(typeof(AnodyneSharp.States.PlayState), nameof(AnodyneSharp.States.PlayState.Create))] |
| 30 | class PlayStateCreatePatch | 44 | class PlayStateCreatePatch |
| 31 | { | 45 | { |
| @@ -36,4 +50,39 @@ namespace AnodyneArchipelago | |||
| 36 | ArchipelagoManager.Connect("localhost:38281", "Anodyne", ""); | 50 | ArchipelagoManager.Connect("localhost:38281", "Anodyne", ""); |
| 37 | } | 51 | } |
| 38 | } | 52 | } |
| 53 | |||
| 54 | [HarmonyPatch(typeof(TreasureChest), nameof(TreasureChest.PlayerInteraction))] | ||
| 55 | class ChestInteractPatch | ||
| 56 | { | ||
| 57 | static void Prefix(TreasureChest __instance) | ||
| 58 | { | ||
| 59 | Type chestType = typeof(TreasureChest); | ||
| 60 | FieldInfo presetField = chestType.GetField("_preset", BindingFlags.NonPublic | BindingFlags.Instance); | ||
| 61 | EntityPreset preset = presetField.GetValue(__instance) as EntityPreset; | ||
| 62 | Plugin.Instance.Log.LogInfo($"Touched chest: {preset.EntityID.ToString()}"); | ||
| 63 | } | ||
| 64 | } | ||
| 65 | |||
| 66 | [HarmonyPatch(typeof(TreasureChest), "SetTreasure")] | ||
| 67 | class ChestSetTreasurePatch | ||
| 68 | { | ||
| 69 | static bool Prefix(TreasureChest __instance) | ||
| 70 | { | ||
| 71 | Type chestType = typeof(TreasureChest); | ||
| 72 | FieldInfo presetField = chestType.GetField("_preset", BindingFlags.NonPublic | BindingFlags.Instance); | ||
| 73 | EntityPreset preset = presetField.GetValue(__instance) as EntityPreset; | ||
| 74 | |||
| 75 | if (Locations.LocationsByGuid.ContainsKey(preset.EntityID)) | ||
| 76 | { | ||
| 77 | BaseTreasure treasure = new ArchipelagoTreasure(Locations.LocationsByGuid[preset.EntityID], __instance.Position); | ||
| 78 | |||
| 79 | FieldInfo treasureField = chestType.GetField("_treasure", BindingFlags.NonPublic | BindingFlags.Instance); | ||
| 80 | treasureField.SetValue(__instance, treasure); | ||
| 81 | |||
| 82 | return false; | ||
| 83 | } | ||
| 84 | |||
| 85 | return true; | ||
| 86 | } | ||
| 87 | } | ||
| 39 | } | 88 | } |
