From e1f48422c3c48bfa50f17332c7a3ef24f61e8fb1 Mon Sep 17 00:00:00 2001 From: kmyuhkyuk <72241714+kmyuhkyuk@users.noreply.github.com> Date: Tue, 17 Mar 2026 10:42:57 +0800 Subject: [PATCH] Added supports other game mode LAN (Daily, Custom) Now game cannot start before all players are present --- .../Components/LanMultiplayerHostSubmenu.cs | 102 +++++++++++++ .../Helpers/LanHostHelper.cs | 7 +- .../Helpers/LanMapDrawingsHelper.cs | 9 -- .../Helpers/LanPlayerNameHelper.cs | 119 --------------- .../NMultiplayerSubmenuButtonHelpers.cs | 13 -- .../Models/LanPlayerNameResponseMessage.cs | 10 +- .../Models/LanPlayerNames.cs | 9 -- .../Models/PlayerNames.cs | 9 ++ .../Patchs/JoinFlowPatch.cs | 24 +-- .../Patchs/NullPlatformUtilStrategyPatch.cs | 4 +- .../Patchs/RunLobbyPatchs.cs | 57 +++++-- .../Patchs/RunManagerPatch.cs | 6 +- .../Patchs/RunSaveManagerPatch.cs | 16 +- .../Screens/NCharacterSelectScreenPatchs.cs | 32 ---- .../Patchs/Screens/NJoinFriendScreenPatch.cs | 10 +- .../Screens/NMainMenuSubmenuStackPatch.cs | 41 +++++ .../Patchs/Screens/NMapDrawingsPatch.cs | 4 +- .../NMultiplayerLoadGameScreenPatch.cs | 32 ---- .../NMultiplayerPlayerExpandedStatePatch.cs | 34 ++--- .../Screens/NMultiplayerSubmenuPatch.cs | 48 ++++-- .../Patchs/Screens/NSettingsScreenPatch.cs | 28 ++-- .../Patchs/Screens/RunLoadScreenPatchs.cs | 90 +++++++++++ .../Patchs/Screens/RunScreenPatchs.cs | 51 +++++++ .../Services/LanMapDrawingsService.cs | 17 +++ .../LanMultiplayerSubmenuButtonService.cs | 22 +++ .../Services/LanPlayerNameService.cs | 143 ++++++++++++++++++ .../LanRunSaveManagerService.cs} | 44 +++--- .../Services/RunScreenService.cs | 67 ++++++++ .../SettingsService.cs} | 10 +- .../SlayTheSpire2.LAN.Multiplayer.csproj | 4 +- 30 files changed, 727 insertions(+), 335 deletions(-) create mode 100644 SlayTheSpire2.LAN.Multiplayer/Components/LanMultiplayerHostSubmenu.cs delete mode 100644 SlayTheSpire2.LAN.Multiplayer/Helpers/LanMapDrawingsHelper.cs delete mode 100644 SlayTheSpire2.LAN.Multiplayer/Helpers/LanPlayerNameHelper.cs delete mode 100644 SlayTheSpire2.LAN.Multiplayer/Helpers/NMultiplayerSubmenuButtonHelpers.cs delete mode 100644 SlayTheSpire2.LAN.Multiplayer/Models/LanPlayerNames.cs create mode 100644 SlayTheSpire2.LAN.Multiplayer/Models/PlayerNames.cs delete mode 100644 SlayTheSpire2.LAN.Multiplayer/Patchs/Screens/NCharacterSelectScreenPatchs.cs create mode 100644 SlayTheSpire2.LAN.Multiplayer/Patchs/Screens/NMainMenuSubmenuStackPatch.cs delete mode 100644 SlayTheSpire2.LAN.Multiplayer/Patchs/Screens/NMultiplayerLoadGameScreenPatch.cs create mode 100644 SlayTheSpire2.LAN.Multiplayer/Patchs/Screens/RunLoadScreenPatchs.cs create mode 100644 SlayTheSpire2.LAN.Multiplayer/Patchs/Screens/RunScreenPatchs.cs create mode 100644 SlayTheSpire2.LAN.Multiplayer/Services/LanMapDrawingsService.cs create mode 100644 SlayTheSpire2.LAN.Multiplayer/Services/LanMultiplayerSubmenuButtonService.cs create mode 100644 SlayTheSpire2.LAN.Multiplayer/Services/LanPlayerNameService.cs rename SlayTheSpire2.LAN.Multiplayer/{Helpers/LanRunSaveManagerHelper.cs => Services/LanRunSaveManagerService.cs} (68%) create mode 100644 SlayTheSpire2.LAN.Multiplayer/Services/RunScreenService.cs rename SlayTheSpire2.LAN.Multiplayer/{Helpers/SettingsHelper.cs => Services/SettingsService.cs} (77%) diff --git a/SlayTheSpire2.LAN.Multiplayer/Components/LanMultiplayerHostSubmenu.cs b/SlayTheSpire2.LAN.Multiplayer/Components/LanMultiplayerHostSubmenu.cs new file mode 100644 index 0000000..2d36934 --- /dev/null +++ b/SlayTheSpire2.LAN.Multiplayer/Components/LanMultiplayerHostSubmenu.cs @@ -0,0 +1,102 @@ +using Godot; +using HarmonyLib; +using MegaCrit.Sts2.Core.Assets; +using MegaCrit.Sts2.Core.Helpers; +using MegaCrit.Sts2.Core.Nodes.GodotExtensions; +using MegaCrit.Sts2.Core.Nodes.Screens.MainMenu; +using MegaCrit.Sts2.Core.Runs; +using MegaCrit.Sts2.Core.TestSupport; +using SlayTheSpire2.LAN.Multiplayer.Helpers; +using SlayTheSpire2.LAN.Multiplayer.Services; + +namespace SlayTheSpire2.LAN.Multiplayer.Components +{ + internal class LanMultiplayerHostSubmenu : NMultiplayerHostSubmenu + { + private static readonly string ScenePath = SceneHelper.GetScenePath("screens/multiplayer_host_submenu"); + + public static LanMultiplayerHostSubmenu? Instance { get; private set; } + + private Control? _loadingOverlay; + + public new static NMultiplayerHostSubmenu? Create() + { + if (Instance != null) + return Instance; + + if (TestMode.IsOn) + return null; + + var multiplayerHostSubmenu = + PreloadManager.Cache.GetScene(ScenePath).Instantiate(); + + var lanMultiplayerHostSubmenu = new LanMultiplayerHostSubmenu(); + + lanMultiplayerHostSubmenu.SetAnchorsAndOffsetsPreset(LayoutPreset.FullRect); + + foreach (var child in multiplayerHostSubmenu.GetChildren()) + { + child.Reparent(lanMultiplayerHostSubmenu, false); + } + + multiplayerHostSubmenu.QueueFree(); + + Instance = lanMultiplayerHostSubmenu; + + return lanMultiplayerHostSubmenu; + } + + public override void _Ready() + { + ConnectSignals(); + + var loadingOverlay = GetNode("LoadingOverlay"); + Traverse.Create(this).Field("_loadingOverlay").SetValue(loadingOverlay); + _loadingOverlay = loadingOverlay; + + var standardButton = GetNode("StandardButton"); + Traverse.Create(this).Field("_standardButton").SetValue(standardButton); + + standardButton.Connect(NClickableControl.SignalName.Released, Callable.From(OnStandardPressed)); + standardButton.SetIconAndLocalization("STANDARD_MP"); + + var dailyButton = GetNode("DailyButton"); + Traverse.Create(this).Field("_dailyButton").SetValue(dailyButton); + + dailyButton.Connect(NClickableControl.SignalName.Released, Callable.From(OnDailyPressed)); + dailyButton.SetIconAndLocalization("DAILY_MP"); + + var customButton = GetNode("CustomRunButton"); + Traverse.Create(this).Field("_customButton").SetValue(customButton); + + customButton.Connect(NClickableControl.SignalName.Released, Callable.From(OnCustomPressed)); + customButton.SetIconAndLocalization("CUSTOM_MP"); + } + + private void OnStandardPressed(NButton _) + { + StartHost(GameMode.Standard); + } + + private void OnDailyPressed(NButton _) + { + StartHost(GameMode.Daily); + } + + private void OnCustomPressed(NButton _) + { + StartHost(GameMode.Custom); + } + + private new void StartHost(GameMode gameMode) + { + if (_loadingOverlay != null) + { + var settingsModel = SettingsService.Instance.SettingsModel; + + LanHostHelper.StartHost(gameMode, _loadingOverlay, _stack, settingsModel.HostPort, + settingsModel.HostMaxPlayers); + } + } + } +} \ No newline at end of file diff --git a/SlayTheSpire2.LAN.Multiplayer/Helpers/LanHostHelper.cs b/SlayTheSpire2.LAN.Multiplayer/Helpers/LanHostHelper.cs index dcd8033..11381ac 100644 --- a/SlayTheSpire2.LAN.Multiplayer/Helpers/LanHostHelper.cs +++ b/SlayTheSpire2.LAN.Multiplayer/Helpers/LanHostHelper.cs @@ -14,6 +14,7 @@ using MegaCrit.Sts2.Core.Nodes.Screens.MainMenu; using MegaCrit.Sts2.Core.Platform; using MegaCrit.Sts2.Core.Runs; using MegaCrit.Sts2.Core.Saves; +using SlayTheSpire2.LAN.Multiplayer.Services; // ReSharper disable MemberCanBePrivate.Global // ReSharper disable UnusedType.Global @@ -138,7 +139,7 @@ namespace SlayTheSpire2.LAN.Multiplayer.Helpers ushort port, int maxPlayers) { var readSaveResult = - LanRunSaveManagerHelper.LoadAndCanonicalizeMultiplayerRunSave( + LanRunSaveManagerService.Instance.LoadAndCanonicalizeMultiplayerRunSave( PlatformUtil.GetLocalPlayerId(PlatformType.None)); if (!readSaveResult.Success || readSaveResult.SaveData == null) { @@ -177,7 +178,7 @@ namespace SlayTheSpire2.LAN.Multiplayer.Helpers return; var readSaveResult = - LanRunSaveManagerHelper.LoadAndCanonicalizeMultiplayerRunSave( + LanRunSaveManagerService.Instance.LoadAndCanonicalizeMultiplayerRunSave( PlatformUtil.GetLocalPlayerId(PlatformType.None)); if (readSaveResult is { Success: true, SaveData: not null }) { @@ -206,7 +207,7 @@ namespace SlayTheSpire2.LAN.Multiplayer.Helpers $"ERROR: Failed to load multiplayer run save: status={readSaveResult.Status}. Deleting current run..."); } - LanRunSaveManagerHelper.DeleteCurrentMultiplayerRun(); + LanRunSaveManagerService.Instance.DeleteCurrentMultiplayerRun(); updateButtons(); } } diff --git a/SlayTheSpire2.LAN.Multiplayer/Helpers/LanMapDrawingsHelper.cs b/SlayTheSpire2.LAN.Multiplayer/Helpers/LanMapDrawingsHelper.cs deleted file mode 100644 index 2867644..0000000 --- a/SlayTheSpire2.LAN.Multiplayer/Helpers/LanMapDrawingsHelper.cs +++ /dev/null @@ -1,9 +0,0 @@ -// ReSharper disable ClassNeverInstantiated.Global - -namespace SlayTheSpire2.LAN.Multiplayer.Helpers -{ - internal class LanMapDrawingsHelper - { - public static readonly HashSet DisableDrawingHashSet = []; - } -} \ No newline at end of file diff --git a/SlayTheSpire2.LAN.Multiplayer/Helpers/LanPlayerNameHelper.cs b/SlayTheSpire2.LAN.Multiplayer/Helpers/LanPlayerNameHelper.cs deleted file mode 100644 index 43f0049..0000000 --- a/SlayTheSpire2.LAN.Multiplayer/Helpers/LanPlayerNameHelper.cs +++ /dev/null @@ -1,119 +0,0 @@ -using Godot; -using HarmonyLib; -using MegaCrit.Sts2.addons.mega_text; -using MegaCrit.Sts2.Core.Multiplayer; -using MegaCrit.Sts2.Core.Multiplayer.Game; -using MegaCrit.Sts2.Core.Nodes.Multiplayer; -using MegaCrit.Sts2.Core.Nodes.Screens.CharacterSelect; -using MegaCrit.Sts2.Core.Platform; -using SlayTheSpire2.LAN.Multiplayer.Components; -using SlayTheSpire2.LAN.Multiplayer.Models; - -// ReSharper disable ClassNeverInstantiated.Global - -namespace SlayTheSpire2.LAN.Multiplayer.Helpers -{ - internal class LanPlayerNameHelper - { - public static LanPlayerNames PlayerNameDictionary = DefaultPlayerNameDictionary; - - public static INetGameService? NetService; - - public static NCharacterSelectScreen? CharacterSelectScreen; - - public static NMultiplayerLoadGameScreen? MultiplayerLoadGameScreen; - - public static TaskCompletionSource? LanPlayerNameCompletion; - - private static LanPlayerNames DefaultPlayerNameDictionary => - !PlayerNameLineEdit.GetPlayerNameIsInvalid(SettingsHelper.Instance.SettingsModel.PlayerName) - ? new LanPlayerNames - { - { 1u, SettingsHelper.Instance.SettingsModel.PlayerName } - } - : new LanPlayerNames(); - - public static void SetHostPlayerName() - { - if (!PlayerNameLineEdit.GetPlayerNameIsInvalid(SettingsHelper.Instance.SettingsModel.PlayerName)) - { - PlayerNameDictionary[1u] = SettingsHelper.Instance.SettingsModel.PlayerName; - } - else - { - PlayerNameDictionary.Remove(1u); - } - } - - public static void SetDefaultPlayerNameDictionary() - { - PlayerNameDictionary = DefaultPlayerNameDictionary; - } - - public static void HandleLanPlayerNameResponseMessage(LanPlayerNameResponseMessage lanPlayerNameResponseMessage, - ulong senderId) - { - PlayerNameDictionary = lanPlayerNameResponseMessage.playerNameDictionary; - - UpdatePlayerName(); - - LanPlayerNameCompletion?.SetResult(lanPlayerNameResponseMessage); - } - - public static void HandleLanPlayerNameRequestMessage(LanPlayerNameRequestMessage lanPlayerNameRequestMessage, - ulong senderId) - { - if (PlayerNameLineEdit.GetPlayerNameIsInvalid(lanPlayerNameRequestMessage.playerName)) - { - NetService?.SendMessage( - new LanPlayerNameResponseMessage { playerNameDictionary = PlayerNameDictionary }, senderId); - return; - } - - PlayerNameDictionary[senderId] = lanPlayerNameRequestMessage.playerName; - - UpdatePlayerName(); - - NetService?.SendMessage(new LanPlayerNameResponseMessage { playerNameDictionary = PlayerNameDictionary }); - } - - public static async Task AttemptPlayerName(NetClientGameService gameService) - { - LanPlayerNameCompletion = new TaskCompletionSource(); - var message = new LanPlayerNameRequestMessage - { playerName = SettingsHelper.Instance.SettingsModel.PlayerName }; - gameService.SendMessage(message); - await LanPlayerNameCompletion.Task; - LanPlayerNameCompletion = null; - } - - private static void UpdatePlayerName() - { - if (CharacterSelectScreen != null) - { - UpdateNameplateLabel(CharacterSelectScreen); - } - - if (MultiplayerLoadGameScreen != null) - { - UpdateNameplateLabel(MultiplayerLoadGameScreen); - } - } - - private static void UpdateNameplateLabel(Control container) - { - var nodes = Traverse.Create(container).Field("_remotePlayerContainer") - .Field("_nodes").GetValue>(); - - foreach (var node in nodes) - { - var megaLabel = Traverse.Create(node).Field("_nameplateLabel").GetValue(); - - if (!GodotObject.IsInstanceValid(megaLabel)) - continue; - - megaLabel.SetTextAutoSize(PlatformUtil.GetPlayerName(PlatformType.None, node.PlayerId)); - } - } - } -} \ No newline at end of file diff --git a/SlayTheSpire2.LAN.Multiplayer/Helpers/NMultiplayerSubmenuButtonHelpers.cs b/SlayTheSpire2.LAN.Multiplayer/Helpers/NMultiplayerSubmenuButtonHelpers.cs deleted file mode 100644 index 13a51b6..0000000 --- a/SlayTheSpire2.LAN.Multiplayer/Helpers/NMultiplayerSubmenuButtonHelpers.cs +++ /dev/null @@ -1,13 +0,0 @@ -using MegaCrit.Sts2.Core.Nodes.Screens.MainMenu; - -// ReSharper disable ClassNeverInstantiated.Global - -namespace SlayTheSpire2.LAN.Multiplayer.Helpers -{ - internal class NMultiplayerSubmenuButtonHelpers - { - public static NSubmenuButton? LanHostButton; - public static NSubmenuButton? LanLoadButton; - public static NSubmenuButton? LanAbandonButton; - } -} \ No newline at end of file diff --git a/SlayTheSpire2.LAN.Multiplayer/Models/LanPlayerNameResponseMessage.cs b/SlayTheSpire2.LAN.Multiplayer/Models/LanPlayerNameResponseMessage.cs index 51c1c07..b8a5f00 100644 --- a/SlayTheSpire2.LAN.Multiplayer/Models/LanPlayerNameResponseMessage.cs +++ b/SlayTheSpire2.LAN.Multiplayer/Models/LanPlayerNameResponseMessage.cs @@ -6,7 +6,7 @@ namespace SlayTheSpire2.LAN.Multiplayer.Models { public struct LanPlayerNameResponseMessage : INetMessage { - public LanPlayerNames playerNameDictionary; + public PlayerNames playerNames; public bool ShouldBroadcast => false; public NetTransferMode Mode => NetTransferMode.Reliable; @@ -14,8 +14,8 @@ namespace SlayTheSpire2.LAN.Multiplayer.Models public void Serialize(PacketWriter writer) { - writer.WriteInt(playerNameDictionary.Count); - foreach (var keyValue in playerNameDictionary) + writer.WriteInt(playerNames.Count); + foreach (var keyValue in playerNames) { writer.WriteULong(keyValue.Key); writer.WriteString(keyValue.Value); @@ -25,10 +25,10 @@ namespace SlayTheSpire2.LAN.Multiplayer.Models public void Deserialize(PacketReader reader) { var count = reader.ReadInt(); - playerNameDictionary = new LanPlayerNames(); + playerNames = new PlayerNames(); for (var i = 0; i < count; i++) { - playerNameDictionary.Add(reader.ReadULong(), reader.ReadString()); + playerNames.Add(reader.ReadULong(), reader.ReadString()); } } } diff --git a/SlayTheSpire2.LAN.Multiplayer/Models/LanPlayerNames.cs b/SlayTheSpire2.LAN.Multiplayer/Models/LanPlayerNames.cs deleted file mode 100644 index c4070fb..0000000 --- a/SlayTheSpire2.LAN.Multiplayer/Models/LanPlayerNames.cs +++ /dev/null @@ -1,9 +0,0 @@ -using System.Text.Json.Serialization; - -namespace SlayTheSpire2.LAN.Multiplayer.Models -{ - [JsonSerializable(typeof(LanPlayerNames))] - public partial class LanPlayerNamesContext : JsonSerializerContext; - - public class LanPlayerNames : Dictionary; -} \ No newline at end of file diff --git a/SlayTheSpire2.LAN.Multiplayer/Models/PlayerNames.cs b/SlayTheSpire2.LAN.Multiplayer/Models/PlayerNames.cs new file mode 100644 index 0000000..643ec6f --- /dev/null +++ b/SlayTheSpire2.LAN.Multiplayer/Models/PlayerNames.cs @@ -0,0 +1,9 @@ +using System.Text.Json.Serialization; + +namespace SlayTheSpire2.LAN.Multiplayer.Models +{ + [JsonSerializable(typeof(PlayerNames))] + public partial class PlayerNamesContext : JsonSerializerContext; + + public class PlayerNames : Dictionary; +} \ No newline at end of file diff --git a/SlayTheSpire2.LAN.Multiplayer/Patchs/JoinFlowPatch.cs b/SlayTheSpire2.LAN.Multiplayer/Patchs/JoinFlowPatch.cs index e8327d3..2b35b09 100644 --- a/SlayTheSpire2.LAN.Multiplayer/Patchs/JoinFlowPatch.cs +++ b/SlayTheSpire2.LAN.Multiplayer/Patchs/JoinFlowPatch.cs @@ -3,8 +3,8 @@ using MegaCrit.Sts2.Core.Entities.Multiplayer; using MegaCrit.Sts2.Core.Multiplayer.Connection; using MegaCrit.Sts2.Core.Multiplayer.Game; using MegaCrit.Sts2.Core.Multiplayer.Messages.Lobby; -using SlayTheSpire2.LAN.Multiplayer.Helpers; using SlayTheSpire2.LAN.Multiplayer.Models; +using SlayTheSpire2.LAN.Multiplayer.Services; // ReSharper disable UnusedMember.Global // ReSharper disable UnusedType.Global @@ -27,10 +27,12 @@ namespace SlayTheSpire2.LAN.Multiplayer.Patchs if (joinFlow.NetService == null) return result; - joinFlow.NetService.RegisterMessageHandler(LanPlayerNameHelper + var lanPlayerNameService = LanPlayerNameService.Instance; + + joinFlow.NetService.RegisterMessageHandler(lanPlayerNameService .HandleLanPlayerNameResponseMessage); - await LanPlayerNameHelper.AttemptPlayerName(joinFlow.NetService); + await lanPlayerNameService.AttemptPlayerName(joinFlow.NetService); return result; } @@ -52,10 +54,12 @@ namespace SlayTheSpire2.LAN.Multiplayer.Patchs if (joinFlow.NetService == null) return result; - joinFlow.NetService.RegisterMessageHandler(LanPlayerNameHelper + var lanPlayerNameService = LanPlayerNameService.Instance; + + joinFlow.NetService.RegisterMessageHandler(lanPlayerNameService .HandleLanPlayerNameResponseMessage); - await LanPlayerNameHelper.AttemptPlayerName(joinFlow.NetService); + await lanPlayerNameService.AttemptPlayerName(joinFlow.NetService); return result; } @@ -77,10 +81,12 @@ namespace SlayTheSpire2.LAN.Multiplayer.Patchs if (joinFlow.NetService == null) return result; - joinFlow.NetService.RegisterMessageHandler(LanPlayerNameHelper + var lanPlayerNameService = LanPlayerNameService.Instance; + + joinFlow.NetService.RegisterMessageHandler(lanPlayerNameService .HandleLanPlayerNameResponseMessage); - await LanPlayerNameHelper.AttemptPlayerName(joinFlow.NetService); + await lanPlayerNameService.AttemptPlayerName(joinFlow.NetService); return result; } @@ -95,7 +101,7 @@ namespace SlayTheSpire2.LAN.Multiplayer.Patchs new ClientConnectionFailedException( $"Unexpectedly disconnected from host while joining. Reason: {info.GetReason()}", info); - var lanPlayerNameCompletion = LanPlayerNameHelper.LanPlayerNameCompletion; + var lanPlayerNameCompletion = LanPlayerNameService.Instance.LanPlayerNameCompletion; if (lanPlayerNameCompletion?.Task is { IsCompleted: false }) { @@ -109,7 +115,7 @@ namespace SlayTheSpire2.LAN.Multiplayer.Patchs { private static void Postfix() { - var lanPlayerNameCompletion = LanPlayerNameHelper.LanPlayerNameCompletion; + var lanPlayerNameCompletion = LanPlayerNameService.Instance.LanPlayerNameCompletion; if (lanPlayerNameCompletion?.Task is { IsCompleted: false }) { diff --git a/SlayTheSpire2.LAN.Multiplayer/Patchs/NullPlatformUtilStrategyPatch.cs b/SlayTheSpire2.LAN.Multiplayer/Patchs/NullPlatformUtilStrategyPatch.cs index b26fb93..16fbd50 100644 --- a/SlayTheSpire2.LAN.Multiplayer/Patchs/NullPlatformUtilStrategyPatch.cs +++ b/SlayTheSpire2.LAN.Multiplayer/Patchs/NullPlatformUtilStrategyPatch.cs @@ -1,6 +1,6 @@ using HarmonyLib; using MegaCrit.Sts2.Core.Platform.Null; -using SlayTheSpire2.LAN.Multiplayer.Helpers; +using SlayTheSpire2.LAN.Multiplayer.Services; // ReSharper disable UnusedMember.Global // ReSharper disable UnusedType.Global @@ -24,7 +24,7 @@ namespace SlayTheSpire2.LAN.Multiplayer.Patchs } } - if (LanPlayerNameHelper.PlayerNameDictionary.TryGetValue(playerId, out var playerName)) + if (LanPlayerNameService.Instance.PlayerNames.TryGetValue(playerId, out var playerName)) { __result = playerName; return false; diff --git a/SlayTheSpire2.LAN.Multiplayer/Patchs/RunLobbyPatchs.cs b/SlayTheSpire2.LAN.Multiplayer/Patchs/RunLobbyPatchs.cs index cb7f4eb..b80bdd4 100644 --- a/SlayTheSpire2.LAN.Multiplayer/Patchs/RunLobbyPatchs.cs +++ b/SlayTheSpire2.LAN.Multiplayer/Patchs/RunLobbyPatchs.cs @@ -5,8 +5,8 @@ using MegaCrit.Sts2.Core.Multiplayer.Game.Lobby; using MegaCrit.Sts2.Core.Platform; using MegaCrit.Sts2.Core.Runs; using MegaCrit.Sts2.Core.Saves; -using SlayTheSpire2.LAN.Multiplayer.Helpers; using SlayTheSpire2.LAN.Multiplayer.Models; +using SlayTheSpire2.LAN.Multiplayer.Services; // ReSharper disable UnusedMember.Global // ReSharper disable UnusedType.Global @@ -34,14 +34,16 @@ namespace SlayTheSpire2.LAN.Multiplayer.Patchs { if (netService.Platform == PlatformType.None) { - LanPlayerNameHelper.NetService = netService; + var lanPlayerNameService = LanPlayerNameService.Instance; - netService.RegisterMessageHandler(LanPlayerNameHelper + lanPlayerNameService.NetService = netService; + + netService.RegisterMessageHandler(lanPlayerNameService .HandleLanPlayerNameResponseMessage); if (netService.Type == NetGameType.Host) { - netService.RegisterMessageHandler(LanPlayerNameHelper + netService.RegisterMessageHandler(lanPlayerNameService .HandleLanPlayerNameRequestMessage); } } @@ -53,30 +55,57 @@ namespace SlayTheSpire2.LAN.Multiplayer.Patchs { private static IEnumerable TargetMethods() { - yield return typeof(StartRunLobby).GetMethod("CleanUp", BindingFlags.Instance | BindingFlags.Public)!; - yield return typeof(RunLobby).GetMethod("Dispose", BindingFlags.Instance | BindingFlags.Public)!; - yield return typeof(LoadRunLobby).GetMethod("CleanUp", BindingFlags.Instance | BindingFlags.Public)!; + const BindingFlags flags = BindingFlags.Instance | BindingFlags.Public; + + yield return typeof(StartRunLobby).GetMethod("CleanUp", flags)!; + yield return typeof(LoadRunLobby).GetMethod("CleanUp", flags)!; } - private static void Prefix(object __instance) + private static void Prefix(object __instance, bool disconnectSession) { - var netService = __instance is StartRunLobby or LoadRunLobby - ? Traverse.Create(__instance).Property("NetService").GetValue() - : Traverse.Create(__instance).Field("_netService").GetValue(); + var netService = Traverse.Create(__instance).Property("NetService").GetValue(); if (netService.Platform == PlatformType.None) { - LanPlayerNameHelper.SetDefaultPlayerNameDictionary(); + var lanPlayerNameService = LanPlayerNameService.Instance; - netService.UnregisterMessageHandler(LanPlayerNameHelper + if (disconnectSession) + { + lanPlayerNameService.SetDefaultPlayerNames(); + } + + netService.UnregisterMessageHandler(lanPlayerNameService .HandleLanPlayerNameResponseMessage); if (netService.Type == NetGameType.Host) { - netService.UnregisterMessageHandler(LanPlayerNameHelper + netService.UnregisterMessageHandler(lanPlayerNameService .HandleLanPlayerNameRequestMessage); } } } + + [HarmonyPatch(typeof(RunLobby), "Dispose")] + internal class RunLobbyDisposePatch + { + private static void Prefix(INetGameService ____netService) + { + if (____netService.Platform == PlatformType.None) + { + var lanPlayerNameService = LanPlayerNameService.Instance; + + lanPlayerNameService.SetDefaultPlayerNames(); + + ____netService.UnregisterMessageHandler(lanPlayerNameService + .HandleLanPlayerNameResponseMessage); + + if (____netService.Type == NetGameType.Host) + { + ____netService.UnregisterMessageHandler(lanPlayerNameService + .HandleLanPlayerNameRequestMessage); + } + } + } + } } } \ No newline at end of file diff --git a/SlayTheSpire2.LAN.Multiplayer/Patchs/RunManagerPatch.cs b/SlayTheSpire2.LAN.Multiplayer/Patchs/RunManagerPatch.cs index 2c49779..4cdf9ed 100644 --- a/SlayTheSpire2.LAN.Multiplayer/Patchs/RunManagerPatch.cs +++ b/SlayTheSpire2.LAN.Multiplayer/Patchs/RunManagerPatch.cs @@ -1,6 +1,6 @@ using HarmonyLib; using MegaCrit.Sts2.Core.Runs; -using SlayTheSpire2.LAN.Multiplayer.Helpers; +using SlayTheSpire2.LAN.Multiplayer.Services; // ReSharper disable UnusedMember.Global // ReSharper disable UnusedType.Global @@ -12,8 +12,8 @@ namespace SlayTheSpire2.LAN.Multiplayer.Patchs { private static void Postfix() { - LanMapDrawingsHelper.DisableDrawingHashSet.Clear(); - LanPlayerNameHelper.SetDefaultPlayerNameDictionary(); + LanMapDrawingsService.Instance.DisableDrawingHashSet.Clear(); + LanPlayerNameService.Instance.SetDefaultPlayerNames(); } } } \ No newline at end of file diff --git a/SlayTheSpire2.LAN.Multiplayer/Patchs/RunSaveManagerPatch.cs b/SlayTheSpire2.LAN.Multiplayer/Patchs/RunSaveManagerPatch.cs index 338dc41..e3d0eb3 100644 --- a/SlayTheSpire2.LAN.Multiplayer/Patchs/RunSaveManagerPatch.cs +++ b/SlayTheSpire2.LAN.Multiplayer/Patchs/RunSaveManagerPatch.cs @@ -7,8 +7,8 @@ using MegaCrit.Sts2.Core.Rooms; using MegaCrit.Sts2.Core.Runs; using MegaCrit.Sts2.Core.Saves; using MegaCrit.Sts2.Core.Saves.Managers; -using SlayTheSpire2.LAN.Multiplayer.Helpers; using SlayTheSpire2.LAN.Multiplayer.Models; +using SlayTheSpire2.LAN.Multiplayer.Services; // ReSharper disable UnusedMember.Global // ReSharper disable UnusedType.Global @@ -42,7 +42,7 @@ namespace SlayTheSpire2.LAN.Multiplayer.Patchs var savePath = isMultiplayer ? isNonePlatform - ? LanRunSaveManagerHelper.CurrentMultiplayerRunSavePath + ? LanRunSaveManagerService.Instance.CurrentMultiplayerRunSavePath : Traverse.Create(runSaveManager).Property("CurrentMultiplayerRunSavePath").GetValue() : Traverse.Create(runSaveManager).Property("CurrentRunSavePath").GetValue(); using var stream = new MemoryStream(); @@ -62,20 +62,22 @@ namespace SlayTheSpire2.LAN.Multiplayer.Patchs if (isMultiplayer && isNonePlatform) { + var lanPlayerNameService = LanPlayerNameService.Instance; + using var playerNamesStream = new MemoryStream(); if (!forceSynchronous) { - await JsonSerializer.SerializeAsync(playerNamesStream, LanPlayerNameHelper.PlayerNameDictionary, - LanPlayerNamesContext.Default.LanPlayerNames, CancellationToken.None); + await JsonSerializer.SerializeAsync(playerNamesStream, lanPlayerNameService.PlayerNames, + PlayerNamesContext.Default.PlayerNames, CancellationToken.None); } else { - await JsonSerializer.SerializeAsync(playerNamesStream, LanPlayerNameHelper.PlayerNameDictionary, - LanPlayerNamesContext.Default.LanPlayerNames); + await JsonSerializer.SerializeAsync(playerNamesStream, lanPlayerNameService.PlayerNames, + PlayerNamesContext.Default.PlayerNames); } playerNamesStream.Seek(0L, SeekOrigin.Begin); - await saveStore.WriteFileAsync(LanRunSaveManagerHelper.CurrentMultiplayerRunPlayerNamesPath, + await saveStore.WriteFileAsync(LanRunSaveManagerService.Instance.CurrentMultiplayerRunPlayerNamesPath, playerNamesStream.ToArray()); } diff --git a/SlayTheSpire2.LAN.Multiplayer/Patchs/Screens/NCharacterSelectScreenPatchs.cs b/SlayTheSpire2.LAN.Multiplayer/Patchs/Screens/NCharacterSelectScreenPatchs.cs deleted file mode 100644 index f4a44fd..0000000 --- a/SlayTheSpire2.LAN.Multiplayer/Patchs/Screens/NCharacterSelectScreenPatchs.cs +++ /dev/null @@ -1,32 +0,0 @@ -using System.Reflection; -using HarmonyLib; -using MegaCrit.Sts2.Core.Multiplayer.Game; -using MegaCrit.Sts2.Core.Nodes.Screens.CharacterSelect; -using MegaCrit.Sts2.Core.Platform; -using SlayTheSpire2.LAN.Multiplayer.Helpers; - -// ReSharper disable UnusedMember.Global -// ReSharper disable UnusedType.Global - -namespace SlayTheSpire2.LAN.Multiplayer.Patchs.Screens -{ - [HarmonyPatch] - internal class NCharacterSelectScreenInitializeMultiplayerPatchs - { - private static IEnumerable TargetMethods() - { - yield return typeof(NCharacterSelectScreen).GetMethod("InitializeMultiplayerAsClient", - BindingFlags.Instance | BindingFlags.Public)!; - yield return typeof(NCharacterSelectScreen).GetMethod("InitializeMultiplayerAsHost", - BindingFlags.Instance | BindingFlags.Public)!; - } - - private static void Prefix(NCharacterSelectScreen __instance, INetGameService gameService) - { - if (gameService.Platform == PlatformType.None) - { - LanPlayerNameHelper.CharacterSelectScreen = __instance; - } - } - } -} \ No newline at end of file diff --git a/SlayTheSpire2.LAN.Multiplayer/Patchs/Screens/NJoinFriendScreenPatch.cs b/SlayTheSpire2.LAN.Multiplayer/Patchs/Screens/NJoinFriendScreenPatch.cs index 324bd2e..d5f9af7 100644 --- a/SlayTheSpire2.LAN.Multiplayer/Patchs/Screens/NJoinFriendScreenPatch.cs +++ b/SlayTheSpire2.LAN.Multiplayer/Patchs/Screens/NJoinFriendScreenPatch.cs @@ -7,7 +7,7 @@ using MegaCrit.Sts2.Core.Multiplayer.Connection; using MegaCrit.Sts2.Core.Nodes.GodotExtensions; using MegaCrit.Sts2.Core.Nodes.Screens.MainMenu; using SlayTheSpire2.LAN.Multiplayer.Components; -using SlayTheSpire2.LAN.Multiplayer.Helpers; +using SlayTheSpire2.LAN.Multiplayer.Services; // ReSharper disable UnusedMember.Global // ReSharper disable UnusedType.Global @@ -61,7 +61,7 @@ namespace SlayTheSpire2.LAN.Multiplayer.Patchs.Screens vBoxContainer.AddChild(addressLineEdit); - addressLineEdit.Text = SettingsHelper.Instance.SettingsModel.IPAddress; + addressLineEdit.Text = SettingsService.Instance.SettingsModel.IPAddress; addressLineEdit.Alignment = HorizontalAlignment.Center; addressLineEdit.CustomMinimumSize = new Vector2(300, 50); addressLineEdit.SizeFlagsHorizontal = Control.SizeFlags.ShrinkCenter; @@ -83,8 +83,8 @@ namespace SlayTheSpire2.LAN.Multiplayer.Patchs.Screens if (!addressInfo.IsValid) return; - SettingsHelper.Instance.SettingsModel.IPAddress = addressLineEdit.Text; - SettingsHelper.Instance.WriteSettings(); + SettingsService.Instance.SettingsModel.IPAddress = addressLineEdit.Text; + SettingsService.Instance.WriteSettings(); ushort port = 33771; @@ -98,7 +98,7 @@ namespace SlayTheSpire2.LAN.Multiplayer.Patchs.Screens { TaskHelper.RunSafely( __instance.JoinGameAsync(new ENetClientConnectionInitializer( - SettingsHelper.Instance.SettingsModel.NetId, addressInfo.Address, port))); + SettingsService.Instance.SettingsModel.NetId, addressInfo.Address, port))); } })); diff --git a/SlayTheSpire2.LAN.Multiplayer/Patchs/Screens/NMainMenuSubmenuStackPatch.cs b/SlayTheSpire2.LAN.Multiplayer/Patchs/Screens/NMainMenuSubmenuStackPatch.cs new file mode 100644 index 0000000..3f2f01c --- /dev/null +++ b/SlayTheSpire2.LAN.Multiplayer/Patchs/Screens/NMainMenuSubmenuStackPatch.cs @@ -0,0 +1,41 @@ +using HarmonyLib; +using MegaCrit.Sts2.Core.Helpers; +using MegaCrit.Sts2.Core.Nodes.Screens.MainMenu; +using SlayTheSpire2.LAN.Multiplayer.Components; + +// ReSharper disable UnusedMember.Global +// ReSharper disable UnusedType.Global + +namespace SlayTheSpire2.LAN.Multiplayer.Patchs.Screens +{ + [HarmonyPatch(typeof(NMainMenuSubmenuStack), "GetSubmenuType", typeof(Type))] + internal class NMainMenuSubmenuStackGetSubmenuTypePatch + { + private static bool Prefix(NMainMenuSubmenuStack __instance, Type type, ref NSubmenu __result) + { + if (type == typeof(LanMultiplayerHostSubmenu)) + { + if (LanMultiplayerHostSubmenu.Instance == null) + { + var lanMultiplayerHostSubmenu = LanMultiplayerHostSubmenu.Create(); + + if (lanMultiplayerHostSubmenu != null) + { + lanMultiplayerHostSubmenu.Visible = false; + __instance.AddChildSafely(lanMultiplayerHostSubmenu); + + __result = lanMultiplayerHostSubmenu; + } + } + else + { + __result = LanMultiplayerHostSubmenu.Instance; + } + + return false; + } + + return true; + } + } +} \ No newline at end of file diff --git a/SlayTheSpire2.LAN.Multiplayer/Patchs/Screens/NMapDrawingsPatch.cs b/SlayTheSpire2.LAN.Multiplayer/Patchs/Screens/NMapDrawingsPatch.cs index d99bd6a..51ec03e 100644 --- a/SlayTheSpire2.LAN.Multiplayer/Patchs/Screens/NMapDrawingsPatch.cs +++ b/SlayTheSpire2.LAN.Multiplayer/Patchs/Screens/NMapDrawingsPatch.cs @@ -2,7 +2,7 @@ using HarmonyLib; using MegaCrit.Sts2.Core.Entities.Players; using MegaCrit.Sts2.Core.Nodes.Screens.Map; -using SlayTheSpire2.LAN.Multiplayer.Helpers; +using SlayTheSpire2.LAN.Multiplayer.Services; // ReSharper disable UnusedMember.Global // ReSharper disable UnusedType.Global @@ -14,7 +14,7 @@ namespace SlayTheSpire2.LAN.Multiplayer.Patchs.Screens { private static void Postfix(Player player, Line2D __result) { - if (LanMapDrawingsHelper.DisableDrawingHashSet.Contains(player.NetId)) + if (LanMapDrawingsService.Instance.DisableDrawingHashSet.Contains(player.NetId)) { __result.Visible = false; } diff --git a/SlayTheSpire2.LAN.Multiplayer/Patchs/Screens/NMultiplayerLoadGameScreenPatch.cs b/SlayTheSpire2.LAN.Multiplayer/Patchs/Screens/NMultiplayerLoadGameScreenPatch.cs deleted file mode 100644 index 2ac2cc9..0000000 --- a/SlayTheSpire2.LAN.Multiplayer/Patchs/Screens/NMultiplayerLoadGameScreenPatch.cs +++ /dev/null @@ -1,32 +0,0 @@ -using System.Reflection; -using HarmonyLib; -using MegaCrit.Sts2.Core.Multiplayer.Game; -using MegaCrit.Sts2.Core.Nodes.Screens.CharacterSelect; -using MegaCrit.Sts2.Core.Platform; -using SlayTheSpire2.LAN.Multiplayer.Helpers; - -// ReSharper disable UnusedMember.Global -// ReSharper disable UnusedType.Global - -namespace SlayTheSpire2.LAN.Multiplayer.Patchs.Screens -{ - [HarmonyPatch] - internal class NMultiplayerLoadGameScreenInitializePatchs - { - private static IEnumerable TargetMethods() - { - yield return typeof(NMultiplayerLoadGameScreen).GetMethod("InitializeAsHost", - BindingFlags.Instance | BindingFlags.Public)!; - yield return typeof(NMultiplayerLoadGameScreen).GetMethod("InitializeAsClient", - BindingFlags.Instance | BindingFlags.Public)!; - } - - private static void Prefix(NMultiplayerLoadGameScreen __instance, INetGameService gameService) - { - if (gameService.Platform == PlatformType.None) - { - LanPlayerNameHelper.MultiplayerLoadGameScreen = __instance; - } - } - } -} \ No newline at end of file diff --git a/SlayTheSpire2.LAN.Multiplayer/Patchs/Screens/NMultiplayerPlayerExpandedStatePatch.cs b/SlayTheSpire2.LAN.Multiplayer/Patchs/Screens/NMultiplayerPlayerExpandedStatePatch.cs index 24e8e37..6d99806 100644 --- a/SlayTheSpire2.LAN.Multiplayer/Patchs/Screens/NMultiplayerPlayerExpandedStatePatch.cs +++ b/SlayTheSpire2.LAN.Multiplayer/Patchs/Screens/NMultiplayerPlayerExpandedStatePatch.cs @@ -7,7 +7,7 @@ using MegaCrit.Sts2.Core.Nodes.Multiplayer; using MegaCrit.Sts2.Core.Nodes.Screens.CardLibrary; using MegaCrit.Sts2.Core.Nodes.Screens.Map; using MegaCrit.Sts2.Core.Runs; -using SlayTheSpire2.LAN.Multiplayer.Helpers; +using SlayTheSpire2.LAN.Multiplayer.Services; // ReSharper disable UnusedMember.Global // ReSharper disable UnusedType.Global @@ -21,32 +21,30 @@ namespace SlayTheSpire2.LAN.Multiplayer.Patchs.Screens { if (____player.NetId != RunManager.Instance.NetService.NetId) { - var lanPanel = new HBoxContainer { Name = "LANPanel" }; - __instance.AddChild(lanPanel); - - lanPanel.AnchorLeft = 0.5f; - lanPanel.AnchorTop = 0; - lanPanel.AnchorRight = 0.5f; - lanPanel.AnchorBottom = 0; - - lanPanel.OffsetLeft = -162; - lanPanel.OffsetTop = 100; - lanPanel.OffsetRight = 162; - lanPanel.OffsetBottom = 100; + var container = __instance.GetNode("ScreenContents/Container"); var disableDrawing = PreloadManager.Cache .GetScene(SceneHelper.GetScenePath("screens/card_library/card_library_tickbox")) .Instantiate(); - if (disableDrawing is NLibraryStatTickbox cardLibraryTickBox) + if (disableDrawing is NLibraryStatTickbox cardLibraryTickBox && + container.GetNode("MarginContainer") is MarginContainer marginContainer) { disableDrawing.Name = "DisableDrawing"; - lanPanel.AddChild(cardLibraryTickBox); + container.AddChild(cardLibraryTickBox); + container.MoveChild(cardLibraryTickBox, 0); + + marginContainer.RemoveThemeConstantOverride("margin_top"); + + cardLibraryTickBox.SizeFlagsHorizontal = Control.SizeFlags.ShrinkCenter; cardLibraryTickBox.SetLabel("Disable drawing"); - cardLibraryTickBox.IsTicked = LanMapDrawingsHelper.DisableDrawingHashSet.Contains(____player.NetId); + var lanMapDrawingsService = LanMapDrawingsService.Instance; + + cardLibraryTickBox.IsTicked = + lanMapDrawingsService.DisableDrawingHashSet.Contains(____player.NetId); cardLibraryTickBox.Toggled += tickBox => { @@ -64,7 +62,7 @@ namespace SlayTheSpire2.LAN.Multiplayer.Patchs.Screens } } - LanMapDrawingsHelper.DisableDrawingHashSet.Add(____player.NetId); + lanMapDrawingsService.DisableDrawingHashSet.Add(____player.NetId); } else { @@ -76,7 +74,7 @@ namespace SlayTheSpire2.LAN.Multiplayer.Patchs.Screens } } - LanMapDrawingsHelper.DisableDrawingHashSet.Remove(____player.NetId); + lanMapDrawingsService.DisableDrawingHashSet.Remove(____player.NetId); } }; } diff --git a/SlayTheSpire2.LAN.Multiplayer/Patchs/Screens/NMultiplayerSubmenuPatch.cs b/SlayTheSpire2.LAN.Multiplayer/Patchs/Screens/NMultiplayerSubmenuPatch.cs index b7898eb..0dcc613 100644 --- a/SlayTheSpire2.LAN.Multiplayer/Patchs/Screens/NMultiplayerSubmenuPatch.cs +++ b/SlayTheSpire2.LAN.Multiplayer/Patchs/Screens/NMultiplayerSubmenuPatch.cs @@ -5,7 +5,10 @@ using MegaCrit.Sts2.Core.Helpers; using MegaCrit.Sts2.Core.Nodes.GodotExtensions; using MegaCrit.Sts2.Core.Nodes.Screens.MainMenu; using MegaCrit.Sts2.Core.Runs; +using MegaCrit.Sts2.Core.Saves; +using SlayTheSpire2.LAN.Multiplayer.Components; using SlayTheSpire2.LAN.Multiplayer.Helpers; +using SlayTheSpire2.LAN.Multiplayer.Services; // ReSharper disable UnusedMember.Global // ReSharper disable UnusedType.Global @@ -30,11 +33,20 @@ namespace SlayTheSpire2.LAN.Multiplayer.Patchs.Screens { var traverse = Traverse.Create(__instance); - var settingsModel = SettingsHelper.Instance.SettingsModel; + var settingsModel = SettingsService.Instance.SettingsModel; - LanHostHelper.StartHost(GameMode.Standard, traverse.Field("_loadingOverlay").GetValue(), - traverse.Field("_stack").GetValue(), - settingsModel.HostPort, settingsModel.HostMaxPlayers); + var stack = traverse.Field("_stack").GetValue(); + + if (SaveManager.Instance.Progress.NumberOfRuns > 0) + { + stack.PushSubmenuType(); + } + else + { + LanHostHelper.StartHost(GameMode.Standard, + traverse.Field("_loadingOverlay").GetValue(), stack, settingsModel.HostPort, + settingsModel.HostMaxPlayers); + } })); lanHostButton.SetIconAndLocalization("HOST"); var lanHostTitle = Traverse.Create(lanHostButton).Field("_title").GetValue(); @@ -42,7 +54,9 @@ namespace SlayTheSpire2.LAN.Multiplayer.Patchs.Screens NSubmenuButtonDuplicateMaterial(lanHostButton); - NMultiplayerSubmenuButtonHelpers.LanHostButton = lanHostButton; + var lanMultiplayerSubmenuButtonService = LanMultiplayerSubmenuButtonService.Instance; + + lanMultiplayerSubmenuButtonService.LanHostButton = lanHostButton; if (buttonContainerNode.GetNode("LoadButton").Duplicate() is not NSubmenuButton lanLoadButton) return; @@ -55,7 +69,7 @@ namespace SlayTheSpire2.LAN.Multiplayer.Patchs.Screens { var traverse = Traverse.Create(__instance); - var settingsModel = SettingsHelper.Instance.SettingsModel; + var settingsModel = SettingsService.Instance.SettingsModel; LanHostHelper.StartLoad(lanLoadButton, traverse.Field("_loadingOverlay").GetValue(), traverse.Field("_stack").GetValue(), @@ -67,7 +81,7 @@ namespace SlayTheSpire2.LAN.Multiplayer.Patchs.Screens NSubmenuButtonDuplicateMaterial(lanLoadButton); - NMultiplayerSubmenuButtonHelpers.LanLoadButton = lanLoadButton; + lanMultiplayerSubmenuButtonService.LanLoadButton = lanLoadButton; if (buttonContainerNode.GetNode("AbandonButton").Duplicate() is not NSubmenuButton lanAbandonButton) return; @@ -89,7 +103,7 @@ namespace SlayTheSpire2.LAN.Multiplayer.Patchs.Screens NSubmenuButtonDuplicateMaterial(lanAbandonButton); - NMultiplayerSubmenuButtonHelpers.LanAbandonButton = lanAbandonButton; + lanMultiplayerSubmenuButtonService.LanAbandonButton = lanAbandonButton; } private static void NSubmenuButtonDuplicateMaterial(NSubmenuButton nSubmenuButton) @@ -108,20 +122,24 @@ namespace SlayTheSpire2.LAN.Multiplayer.Patchs.Screens { private static void Postfix() { - if (NMultiplayerSubmenuButtonHelpers.LanHostButton != null) + var lanMultiplayerSubmenuButtonService = LanMultiplayerSubmenuButtonService.Instance; + + if (lanMultiplayerSubmenuButtonService.LanHostButton != null) { - NMultiplayerSubmenuButtonHelpers.LanHostButton.Visible = !LanRunSaveManagerHelper.HasMultiplayerRunSave; + lanMultiplayerSubmenuButtonService.LanHostButton.Visible = + !LanRunSaveManagerService.Instance.HasMultiplayerRunSave; } - if (NMultiplayerSubmenuButtonHelpers.LanLoadButton != null) + if (lanMultiplayerSubmenuButtonService.LanLoadButton != null) { - NMultiplayerSubmenuButtonHelpers.LanLoadButton.Visible = LanRunSaveManagerHelper.HasMultiplayerRunSave; + lanMultiplayerSubmenuButtonService.LanLoadButton.Visible = + LanRunSaveManagerService.Instance.HasMultiplayerRunSave; } - if (NMultiplayerSubmenuButtonHelpers.LanAbandonButton != null) + if (lanMultiplayerSubmenuButtonService.LanAbandonButton != null) { - NMultiplayerSubmenuButtonHelpers.LanAbandonButton.Visible = - LanRunSaveManagerHelper.HasMultiplayerRunSave; + lanMultiplayerSubmenuButtonService.LanAbandonButton.Visible = + LanRunSaveManagerService.Instance.HasMultiplayerRunSave; } } } diff --git a/SlayTheSpire2.LAN.Multiplayer/Patchs/Screens/NSettingsScreenPatch.cs b/SlayTheSpire2.LAN.Multiplayer/Patchs/Screens/NSettingsScreenPatch.cs index 352bef6..e541f4c 100644 --- a/SlayTheSpire2.LAN.Multiplayer/Patchs/Screens/NSettingsScreenPatch.cs +++ b/SlayTheSpire2.LAN.Multiplayer/Patchs/Screens/NSettingsScreenPatch.cs @@ -2,7 +2,7 @@ using HarmonyLib; using MegaCrit.Sts2.Core.Nodes.Screens.Settings; using SlayTheSpire2.LAN.Multiplayer.Components; -using SlayTheSpire2.LAN.Multiplayer.Helpers; +using SlayTheSpire2.LAN.Multiplayer.Services; // ReSharper disable UnusedMember.Global // ReSharper disable UnusedType.Global @@ -50,11 +50,11 @@ namespace SlayTheSpire2.LAN.Multiplayer.Patchs.Screens hostPortLineEdit.Step = 1; hostPortLineEdit.MinValue = 0; hostPortLineEdit.MaxValue = 65535; - hostPortLineEdit.Value = SettingsHelper.Instance.SettingsModel.HostPort; + hostPortLineEdit.Value = SettingsService.Instance.SettingsModel.HostPort; hostPortLineEdit.ValueChanged += value => { - SettingsHelper.Instance.SettingsModel.HostPort = (ushort)value; - SettingsHelper.Instance.WriteSettings(); + SettingsService.Instance.SettingsModel.HostPort = (ushort)value; + SettingsService.Instance.WriteSettings(); }; hostPortLabel.Text = "Host Port"; @@ -90,11 +90,11 @@ namespace SlayTheSpire2.LAN.Multiplayer.Patchs.Screens hostMaxPlayersInput.Step = 1; hostMaxPlayersInput.MinValue = 2; - hostMaxPlayersInput.Value = SettingsHelper.Instance.SettingsModel.HostMaxPlayers; + hostMaxPlayersInput.Value = SettingsService.Instance.SettingsModel.HostMaxPlayers; hostMaxPlayersInput.ValueChanged += value => { - SettingsHelper.Instance.SettingsModel.HostMaxPlayers = (int)value; - SettingsHelper.Instance.WriteSettings(); + SettingsService.Instance.SettingsModel.HostMaxPlayers = (int)value; + SettingsService.Instance.WriteSettings(); }; hostMaxPlayersLabel.Text = "Host Max Players"; @@ -129,14 +129,14 @@ namespace SlayTheSpire2.LAN.Multiplayer.Patchs.Screens playerNameInput.Alignment = HorizontalAlignment.Center; playerNameInput.MaxLength = 16; - playerNameInput.Text = SettingsHelper.Instance.SettingsModel.PlayerName; + playerNameInput.Text = SettingsService.Instance.SettingsModel.PlayerName; playerNameInput.TextChanged += value => { if (playerNameInput.IsEmpty || !playerNameInput.IsInvalid) { - SettingsHelper.Instance.SettingsModel.PlayerName = value; - LanPlayerNameHelper.SetHostPlayerName(); - SettingsHelper.Instance.WriteSettings(); + SettingsService.Instance.SettingsModel.PlayerName = value; + LanPlayerNameService.Instance.SetHostPlayerName(); + SettingsService.Instance.WriteSettings(); } }; @@ -174,11 +174,11 @@ namespace SlayTheSpire2.LAN.Multiplayer.Patchs.Screens netIdInput.Step = 1; netIdInput.MinValue = 2; netIdInput.MaxValue = ulong.MaxValue; - netIdInput.Value = SettingsHelper.Instance.SettingsModel.NetId; + netIdInput.Value = SettingsService.Instance.SettingsModel.NetId; netIdInput.ValueChanged += value => { - SettingsHelper.Instance.SettingsModel.NetId = (ulong)value; - SettingsHelper.Instance.WriteSettings(); + SettingsService.Instance.SettingsModel.NetId = (ulong)value; + SettingsService.Instance.WriteSettings(); }; netIdLabel.Text = "NetID"; diff --git a/SlayTheSpire2.LAN.Multiplayer/Patchs/Screens/RunLoadScreenPatchs.cs b/SlayTheSpire2.LAN.Multiplayer/Patchs/Screens/RunLoadScreenPatchs.cs new file mode 100644 index 0000000..38437a0 --- /dev/null +++ b/SlayTheSpire2.LAN.Multiplayer/Patchs/Screens/RunLoadScreenPatchs.cs @@ -0,0 +1,90 @@ +using System.Reflection; +using HarmonyLib; +using MegaCrit.Sts2.Core.Multiplayer.Game; +using MegaCrit.Sts2.Core.Multiplayer.Game.Lobby; +using MegaCrit.Sts2.Core.Nodes.Screens.CharacterSelect; +using MegaCrit.Sts2.Core.Nodes.Screens.CustomRun; +using MegaCrit.Sts2.Core.Nodes.Screens.DailyRun; +using MegaCrit.Sts2.Core.Platform; +using SlayTheSpire2.LAN.Multiplayer.Services; + +// ReSharper disable UnusedMember.Global +// ReSharper disable UnusedType.Global + +namespace SlayTheSpire2.LAN.Multiplayer.Patchs.Screens +{ + [HarmonyPatch] + internal class RunLoadScreenInitializePatchs + { + private static IEnumerable TargetMethods() + { + const BindingFlags flags = BindingFlags.Instance | BindingFlags.Public; + + yield return typeof(NMultiplayerLoadGameScreen).GetMethod("InitializeAsHost", flags)!; + yield return typeof(NMultiplayerLoadGameScreen).GetMethod("InitializeAsClient", flags)!; + yield return typeof(NDailyRunLoadScreen).GetMethod("InitializeAsHost", flags)!; + yield return typeof(NDailyRunLoadScreen).GetMethod("InitializeAsClient", flags)!; + yield return typeof(NCustomRunLoadScreen).GetMethod("InitializeAsHost", flags)!; + yield return typeof(NCustomRunLoadScreen).GetMethod("InitializeAsClient", flags)!; + } + + private static void Prefix(object __instance, INetGameService gameService) + { + if (gameService.Platform == PlatformType.None) + { + var runScreenService = RunScreenService.Instance; + + switch (__instance) + { + case NMultiplayerLoadGameScreen multiplayerLoadGameScreen: + runScreenService.MultiplayerLoadGameScreen = multiplayerLoadGameScreen; + break; + case NDailyRunLoadScreen dailyRunLoadScreen: + runScreenService.DailyRunLoadScreen = dailyRunLoadScreen; + break; + case NCustomRunLoadScreen customRunLoadScreen: + runScreenService.CustomRunLoadScreen = customRunLoadScreen; + break; + } + } + } + } + + [HarmonyPatch] + internal class RunLoadScreenShouldAllowRunToBeginPatchs + { + private static IEnumerable TargetMethods() + { + const BindingFlags flags = BindingFlags.Instance | BindingFlags.Public; + + yield return typeof(NDailyRunLoadScreen).GetMethod("ShouldAllowRunToBegin", flags)!; + yield return typeof(NCustomRunLoadScreen).GetMethod("ShouldAllowRunToBegin", flags)!; + } + + private static bool Prefix(LoadRunLobby ____lobby, ref Task __result) + { + if (____lobby.NetService.Platform == PlatformType.None) + { + __result = RunScreenService.ShouldAllowRunToBegin(____lobby); + return false; + } + + return true; + } + } + + [HarmonyPatch(typeof(NMultiplayerLoadGameScreen), "ShouldAllowRunToBegin")] + internal class RunLoadScreenShouldAllowRunToBeginPatch + { + private static bool Prefix(LoadRunLobby ____runLobby, ref Task __result) + { + if (____runLobby.NetService.Platform == PlatformType.None) + { + __result = RunScreenService.ShouldAllowRunToBegin(____runLobby); + return false; + } + + return true; + } + } +} \ No newline at end of file diff --git a/SlayTheSpire2.LAN.Multiplayer/Patchs/Screens/RunScreenPatchs.cs b/SlayTheSpire2.LAN.Multiplayer/Patchs/Screens/RunScreenPatchs.cs new file mode 100644 index 0000000..cbb25a3 --- /dev/null +++ b/SlayTheSpire2.LAN.Multiplayer/Patchs/Screens/RunScreenPatchs.cs @@ -0,0 +1,51 @@ +using System.Reflection; +using HarmonyLib; +using MegaCrit.Sts2.Core.Multiplayer.Game; +using MegaCrit.Sts2.Core.Nodes.Screens.CharacterSelect; +using MegaCrit.Sts2.Core.Nodes.Screens.CustomRun; +using MegaCrit.Sts2.Core.Nodes.Screens.DailyRun; +using MegaCrit.Sts2.Core.Platform; +using SlayTheSpire2.LAN.Multiplayer.Services; + +// ReSharper disable UnusedMember.Global +// ReSharper disable UnusedType.Global + +namespace SlayTheSpire2.LAN.Multiplayer.Patchs.Screens +{ + [HarmonyPatch] + internal class RunScreenInitializePatchs + { + private static IEnumerable TargetMethods() + { + const BindingFlags flags = BindingFlags.Instance | BindingFlags.Public; + + yield return typeof(NCharacterSelectScreen).GetMethod("InitializeMultiplayerAsClient", flags)!; + yield return typeof(NCharacterSelectScreen).GetMethod("InitializeMultiplayerAsHost", flags)!; + yield return typeof(NDailyRunScreen).GetMethod("InitializeMultiplayerAsClient", flags)!; + yield return typeof(NDailyRunScreen).GetMethod("InitializeMultiplayerAsHost", flags)!; + yield return typeof(NCustomRunScreen).GetMethod("InitializeMultiplayerAsClient", flags)!; + yield return typeof(NCustomRunScreen).GetMethod("InitializeMultiplayerAsHost", flags)!; + } + + private static void Prefix(object __instance, INetGameService gameService) + { + if (gameService.Platform == PlatformType.None) + { + var runScreenService = RunScreenService.Instance; + + switch (__instance) + { + case NCharacterSelectScreen characterSelectScreen: + runScreenService.CharacterSelectScreen = characterSelectScreen; + break; + case NDailyRunScreen dailyRunScreen: + runScreenService.DailyRunScreen = dailyRunScreen; + break; + case NCustomRunScreen customRunScreen: + runScreenService.CustomRunScreen = customRunScreen; + break; + } + } + } + } +} \ No newline at end of file diff --git a/SlayTheSpire2.LAN.Multiplayer/Services/LanMapDrawingsService.cs b/SlayTheSpire2.LAN.Multiplayer/Services/LanMapDrawingsService.cs new file mode 100644 index 0000000..dd1bf20 --- /dev/null +++ b/SlayTheSpire2.LAN.Multiplayer/Services/LanMapDrawingsService.cs @@ -0,0 +1,17 @@ +// ReSharper disable ClassNeverInstantiated.Global + +namespace SlayTheSpire2.LAN.Multiplayer.Services +{ + internal class LanMapDrawingsService + { + private static readonly Lazy Lazy = new(() => new LanMapDrawingsService()); + + public static LanMapDrawingsService Instance => Lazy.Value; + + public readonly HashSet DisableDrawingHashSet = []; + + private LanMapDrawingsService() + { + } + } +} \ No newline at end of file diff --git a/SlayTheSpire2.LAN.Multiplayer/Services/LanMultiplayerSubmenuButtonService.cs b/SlayTheSpire2.LAN.Multiplayer/Services/LanMultiplayerSubmenuButtonService.cs new file mode 100644 index 0000000..36c281d --- /dev/null +++ b/SlayTheSpire2.LAN.Multiplayer/Services/LanMultiplayerSubmenuButtonService.cs @@ -0,0 +1,22 @@ +using MegaCrit.Sts2.Core.Nodes.Screens.MainMenu; + +// ReSharper disable ClassNeverInstantiated.Global + +namespace SlayTheSpire2.LAN.Multiplayer.Services +{ + internal class LanMultiplayerSubmenuButtonService + { + private static readonly Lazy Lazy = new(() => + new LanMultiplayerSubmenuButtonService()); + + public static LanMultiplayerSubmenuButtonService Instance => Lazy.Value; + + public NSubmenuButton? LanHostButton; + public NSubmenuButton? LanLoadButton; + public NSubmenuButton? LanAbandonButton; + + private LanMultiplayerSubmenuButtonService() + { + } + } +} \ No newline at end of file diff --git a/SlayTheSpire2.LAN.Multiplayer/Services/LanPlayerNameService.cs b/SlayTheSpire2.LAN.Multiplayer/Services/LanPlayerNameService.cs new file mode 100644 index 0000000..01ab1fb --- /dev/null +++ b/SlayTheSpire2.LAN.Multiplayer/Services/LanPlayerNameService.cs @@ -0,0 +1,143 @@ +using Godot; +using HarmonyLib; +using MegaCrit.Sts2.addons.mega_text; +using MegaCrit.Sts2.Core.Multiplayer; +using MegaCrit.Sts2.Core.Multiplayer.Game; +using MegaCrit.Sts2.Core.Nodes.Multiplayer; +using MegaCrit.Sts2.Core.Platform; +using SlayTheSpire2.LAN.Multiplayer.Components; +using SlayTheSpire2.LAN.Multiplayer.Models; + +// ReSharper disable ClassNeverInstantiated.Global + +namespace SlayTheSpire2.LAN.Multiplayer.Services +{ + internal class LanPlayerNameService + { + private static readonly Lazy Lazy = new(() => new LanPlayerNameService()); + + public static LanPlayerNameService Instance => Lazy.Value; + + public PlayerNames PlayerNames = GetDefaultPlayerNames(); + + public INetGameService? NetService; + + public TaskCompletionSource? LanPlayerNameCompletion; + + private LanPlayerNameService() + { + } + + public void SetHostPlayerName() + { + if (!PlayerNameLineEdit.GetPlayerNameIsInvalid(SettingsService.Instance.SettingsModel.PlayerName)) + { + PlayerNames[1u] = SettingsService.Instance.SettingsModel.PlayerName; + } + else + { + PlayerNames.Remove(1u); + } + } + + public void SetDefaultPlayerNames() + { + PlayerNames = GetDefaultPlayerNames(); + } + + private static PlayerNames GetDefaultPlayerNames() + { + return !PlayerNameLineEdit.GetPlayerNameIsInvalid(SettingsService.Instance.SettingsModel.PlayerName) + ? new PlayerNames { { 1u, SettingsService.Instance.SettingsModel.PlayerName } } + : new PlayerNames(); + } + + public void HandleLanPlayerNameResponseMessage(LanPlayerNameResponseMessage lanPlayerNameResponseMessage, + ulong senderId) + { + PlayerNames = lanPlayerNameResponseMessage.playerNames; + + UpdatePlayerName(); + + LanPlayerNameCompletion?.SetResult(lanPlayerNameResponseMessage); + } + + public void HandleLanPlayerNameRequestMessage(LanPlayerNameRequestMessage lanPlayerNameRequestMessage, + ulong senderId) + { + if (PlayerNameLineEdit.GetPlayerNameIsInvalid(lanPlayerNameRequestMessage.playerName)) + { + NetService?.SendMessage( + new LanPlayerNameResponseMessage { playerNames = PlayerNames }, senderId); + return; + } + + PlayerNames[senderId] = lanPlayerNameRequestMessage.playerName; + + UpdatePlayerName(); + + NetService?.SendMessage(new LanPlayerNameResponseMessage { playerNames = PlayerNames }); + } + + public async Task AttemptPlayerName(NetClientGameService gameService) + { + LanPlayerNameCompletion = new TaskCompletionSource(); + var message = new LanPlayerNameRequestMessage + { playerName = SettingsService.Instance.SettingsModel.PlayerName }; + gameService.SendMessage(message); + await LanPlayerNameCompletion.Task; + LanPlayerNameCompletion = null; + } + + private static void UpdatePlayerName() + { + var runScreenService = RunScreenService.Instance; + + if (runScreenService.CharacterSelectScreen != null) + { + UpdateNameplateLabel(runScreenService.CharacterSelectScreen); + } + + if (runScreenService.DailyRunScreen != null) + { + UpdateNameplateLabel(runScreenService.DailyRunScreen); + } + + if (runScreenService.CustomRunScreen != null) + { + UpdateNameplateLabel(runScreenService.CustomRunScreen); + } + + if (runScreenService.MultiplayerLoadGameScreen != null) + { + UpdateNameplateLabel(runScreenService.MultiplayerLoadGameScreen); + } + + if (runScreenService.DailyRunLoadScreen != null) + { + UpdateNameplateLabel(runScreenService.DailyRunLoadScreen); + } + + if (runScreenService.CustomRunLoadScreen != null) + { + UpdateNameplateLabel(runScreenService.CustomRunLoadScreen); + } + } + + private static void UpdateNameplateLabel(Control container) + { + var nodes = Traverse.Create(container).Field("_remotePlayerContainer") + .Field("_nodes").GetValue>(); + + foreach (var node in nodes) + { + var megaLabel = Traverse.Create(node).Field("_nameplateLabel").GetValue(); + + if (!GodotObject.IsInstanceValid(megaLabel)) + continue; + + megaLabel.SetTextAutoSize(PlatformUtil.GetPlayerName(PlatformType.None, node.PlayerId)); + } + } + } +} \ No newline at end of file diff --git a/SlayTheSpire2.LAN.Multiplayer/Helpers/LanRunSaveManagerHelper.cs b/SlayTheSpire2.LAN.Multiplayer/Services/LanRunSaveManagerService.cs similarity index 68% rename from SlayTheSpire2.LAN.Multiplayer/Helpers/LanRunSaveManagerHelper.cs rename to SlayTheSpire2.LAN.Multiplayer/Services/LanRunSaveManagerService.cs index 87d9c74..7862e07 100644 --- a/SlayTheSpire2.LAN.Multiplayer/Helpers/LanRunSaveManagerHelper.cs +++ b/SlayTheSpire2.LAN.Multiplayer/Services/LanRunSaveManagerService.cs @@ -7,45 +7,55 @@ using MegaCrit.Sts2.Core.Saves.Managers; using MegaCrit.Sts2.Core.Saves.Migrations; using SlayTheSpire2.LAN.Multiplayer.Models; +// ReSharper disable MemberCanBeMadeStatic.Local // ReSharper disable MemberCanBePrivate.Global // ReSharper disable ClassNeverInstantiated.Global -namespace SlayTheSpire2.LAN.Multiplayer.Helpers +namespace SlayTheSpire2.LAN.Multiplayer.Services { - internal class LanRunSaveManagerHelper + internal class LanRunSaveManagerService { - public static ISaveStore SaveStore => - Traverse.Create(SaveManager.Instance).Field("_saveStore").GetValue(); + private static readonly Lazy Lazy = new(() => new LanRunSaveManagerService()); - public static MigrationManager MigrationManager => Traverse.Create(SaveManager.Instance) - .Field("_migrationManager").GetValue(); + public static LanRunSaveManagerService Instance => Lazy.Value; - public static IProfileIdProvider ProfileIdProvider => SaveManager.Instance; + private SaveManager ProfileIdProvider => SaveManager.Instance; - public static string CurrentMultiplayerRunSavePath => + private ISaveStore SaveStore => Traverse.Create(ProfileIdProvider).Field("_saveStore").GetValue(); + + private MigrationManager MigrationManager => Traverse.Create(ProfileIdProvider).Field("_migrationManager") + .GetValue(); + + public string CurrentMultiplayerRunSavePath => RunSaveManager.GetRunSavePath(ProfileIdProvider.CurrentProfileId, "current_lan_run_mp.save"); - public static string CurrentMultiplayerRunPlayerNamesPath => + public string CurrentMultiplayerRunPlayerNamesPath => RunSaveManager.GetRunSavePath(ProfileIdProvider.CurrentProfileId, "current_lan_run_mp_player_names.json"); - public static bool HasMultiplayerRunSave => SaveStore.FileExists(CurrentMultiplayerRunSavePath); + public bool HasMultiplayerRunSave => SaveStore.FileExists(CurrentMultiplayerRunSavePath); - public static ReadSaveResult LoadAndCanonicalizeMultiplayerRunSave(ulong localPlayerId) + private LanRunSaveManagerService() + { + } + + public ReadSaveResult LoadAndCanonicalizeMultiplayerRunSave(ulong localPlayerId) { var readSaveResult = LoadMultiplayerRunSave(); if (readSaveResult is { Success: true, SaveData: not null }) { try { + var lanPlayerNameService = LanPlayerNameService.Instance; + var data = RunManager.CanonicalizeSave(readSaveResult.SaveData, localPlayerId); var playerNamesJson = SaveStore.ReadFile(CurrentMultiplayerRunPlayerNamesPath); if (!string.IsNullOrEmpty(playerNamesJson)) { - LanPlayerNameHelper.PlayerNameDictionary = - JsonSerializer.Deserialize(playerNamesJson) ?? new LanPlayerNames(); + lanPlayerNameService.PlayerNames = JsonSerializer.Deserialize(playerNamesJson) ?? + new PlayerNames(); } - LanPlayerNameHelper.SetHostPlayerName(); + lanPlayerNameService.SetHostPlayerName(); return new ReadSaveResult(data, ReadSaveStatus.Success); } catch (Exception value) @@ -60,7 +70,7 @@ namespace SlayTheSpire2.LAN.Multiplayer.Helpers return readSaveResult; } - public static ReadSaveResult LoadMultiplayerRunSave() + public ReadSaveResult LoadMultiplayerRunSave() { var readSaveResult = MigrationManager.LoadSave(CurrentMultiplayerRunSavePath); if (readSaveResult.Success) @@ -86,13 +96,13 @@ namespace SlayTheSpire2.LAN.Multiplayer.Helpers return readSaveResult; } - public static void DeleteCurrentMultiplayerRun() + public void DeleteCurrentMultiplayerRun() { SaveStore.DeleteFile(CurrentMultiplayerRunSavePath); SaveStore.DeleteFile(CurrentMultiplayerRunPlayerNamesPath); } - public static void RenameBrokenMultiplayerRunSave(ReadSaveStatus status) + public void RenameBrokenMultiplayerRunSave(ReadSaveStatus status) { try { diff --git a/SlayTheSpire2.LAN.Multiplayer/Services/RunScreenService.cs b/SlayTheSpire2.LAN.Multiplayer/Services/RunScreenService.cs new file mode 100644 index 0000000..668a995 --- /dev/null +++ b/SlayTheSpire2.LAN.Multiplayer/Services/RunScreenService.cs @@ -0,0 +1,67 @@ +using Godot; +using HarmonyLib; +using MegaCrit.Sts2.Core.Localization; +using MegaCrit.Sts2.Core.Multiplayer.Game.Lobby; +using MegaCrit.Sts2.Core.Nodes.CommonUi; +using MegaCrit.Sts2.Core.Nodes.Multiplayer; +using MegaCrit.Sts2.Core.Nodes.Screens.CharacterSelect; +using MegaCrit.Sts2.Core.Nodes.Screens.CustomRun; +using MegaCrit.Sts2.Core.Nodes.Screens.DailyRun; + +namespace SlayTheSpire2.LAN.Multiplayer.Services +{ + internal class RunScreenService + { + private static readonly Lazy Lazy = new(() => new RunScreenService()); + + public static RunScreenService Instance => Lazy.Value; + + public NCharacterSelectScreen? CharacterSelectScreen; + + public NDailyRunScreen? DailyRunScreen; + + public NCustomRunScreen? CustomRunScreen; + + public NMultiplayerLoadGameScreen? MultiplayerLoadGameScreen; + + public NDailyRunLoadScreen? DailyRunLoadScreen; + + public NCustomRunLoadScreen? CustomRunLoadScreen; + + private RunScreenService() + { + } + + public static async Task ShouldAllowRunToBegin(LoadRunLobby runLobby) + { + if (runLobby.ConnectedPlayerIds.Count >= runLobby.Run.Players.Count) + return true; + + var locString = new LocString("gameplay_ui", "CONFIRM_LOAD_SAVE.body"); + locString.Add("MissingCount", runLobby.Run.Players.Count - runLobby.ConnectedPlayerIds.Count); + + var nGenericPopup = NGenericPopup.Create(); + if (nGenericPopup != null) + { + NModalContainer.Instance?.Add(nGenericPopup); + + var nVerticalPopup = Traverse.Create(nGenericPopup).Field("_verticalPopup").GetValue(); + + nVerticalPopup.NoButton.SetAnchorsPreset(Control.LayoutPreset.CenterBottom); + nVerticalPopup.NoButton.OffsetLeft = -90; + nVerticalPopup.NoButton.OffsetTop = -152; + nVerticalPopup.NoButton.OffsetRight = 90; + nVerticalPopup.NoButton.OffsetBottom = -80; + + nVerticalPopup.YesButton.Visible = false; + + return await nGenericPopup.WaitForConfirmation(locString, + new LocString("gameplay_ui", "CONFIRM_LOAD_SAVE.header"), + new LocString("gameplay_ui", "CONFIRM_LOAD_SAVE.cancel"), + new LocString("gameplay_ui", "CONFIRM_LOAD_SAVE.confirm")); + } + + return false; + } + } +} \ No newline at end of file diff --git a/SlayTheSpire2.LAN.Multiplayer/Helpers/SettingsHelper.cs b/SlayTheSpire2.LAN.Multiplayer/Services/SettingsService.cs similarity index 77% rename from SlayTheSpire2.LAN.Multiplayer/Helpers/SettingsHelper.cs rename to SlayTheSpire2.LAN.Multiplayer/Services/SettingsService.cs index f7739be..abb086d 100644 --- a/SlayTheSpire2.LAN.Multiplayer/Helpers/SettingsHelper.cs +++ b/SlayTheSpire2.LAN.Multiplayer/Services/SettingsService.cs @@ -2,20 +2,20 @@ using MegaCrit.Sts2.Core.Saves; using SlayTheSpire2.LAN.Multiplayer.Models; -namespace SlayTheSpire2.LAN.Multiplayer.Helpers +namespace SlayTheSpire2.LAN.Multiplayer.Services { - internal class SettingsHelper + internal class SettingsService { - private static readonly Lazy Lazy = new(() => new SettingsHelper()); + private static readonly Lazy Lazy = new(() => new SettingsService()); - public static SettingsHelper Instance => Lazy.Value; + public static SettingsService Instance => Lazy.Value; public readonly SettingsModel SettingsModel; private readonly GodotFileIo _modsDir = new(Path.Combine(UserDataPathProvider.GetAccountScopedBasePath(null), "mods")); - private SettingsHelper() + private SettingsService() { if (_modsDir.FileExists("lan_settings.json")) { diff --git a/SlayTheSpire2.LAN.Multiplayer/SlayTheSpire2.LAN.Multiplayer.csproj b/SlayTheSpire2.LAN.Multiplayer/SlayTheSpire2.LAN.Multiplayer.csproj index f796386..3bc861d 100644 --- a/SlayTheSpire2.LAN.Multiplayer/SlayTheSpire2.LAN.Multiplayer.csproj +++ b/SlayTheSpire2.LAN.Multiplayer/SlayTheSpire2.LAN.Multiplayer.csproj @@ -4,8 +4,8 @@ net9.0 enable enable - 1.3.0.0 - 1.3.0.0 + 1.5.0.0 + 1.5.0.0