From f556cc81f5cc2e60b83a5eb8175017ecffd39cb4 Mon Sep 17 00:00:00 2001 From: Demonofpower Date: Sun, 12 Apr 2026 21:28:38 +0200 Subject: [PATCH 01/11] first android multiplayer edits --- src/Multiplayer/Multiplayer.cs | 51 ++++++++++++++++++++++++++++++++-- 1 file changed, 49 insertions(+), 2 deletions(-) diff --git a/src/Multiplayer/Multiplayer.cs b/src/Multiplayer/Multiplayer.cs index a06e021..be0921b 100644 --- a/src/Multiplayer/Multiplayer.cs +++ b/src/Multiplayer/Multiplayer.cs @@ -8,6 +8,7 @@ using PolytopiaBackendBase.Game.BindingModels; using UnityEngine; using Newtonsoft.Json; +using PolytopiaBackendBase.Auth; namespace PolyMod.Multiplayer; @@ -27,10 +28,53 @@ internal static void Init() Harmony.CreateAndPatchAll(typeof(Client)); BuildConfig buildConfig = BuildConfigHelper.GetSelectedBuildConfig(); buildConfig.buildServerURL = BuildServerURL.Custom; - buildConfig.customServerURL = LOCAL_SERVER_URL; + buildConfig.customServerURL = Plugin.config.backendUrl; + + // Update BackendUri and HttpClient.BaseAddress since PolytopiaBackendAdapter.Instance + // was statically initialized before plugins load, so it still points to polytopia-prod.net + var uri = new Il2CppSystem.Uri(Plugin.config.backendUrl); + PolytopiaBackendAdapter.Instance.UseBackendUri(uri); + PolytopiaBackendAdapter.Instance.BackendHttpClient.BaseAddress = uri; Plugin.logger.LogInfo($"Multiplayer> Server URL set to: {Plugin.config.backendUrl}"); - Plugin.logger.LogInfo("Multiplayer> GLD patches applied"); + } + + /// + /// On Android, bypass multiplayer requirements that depend on + /// Google Play login, push notifications, and purchases — none of which work + /// when running as a wrapper app with a different package identity. + /// + [HarmonyPrefix] + [HarmonyPatch(typeof(GameManager), nameof(GameManager.IsMultiplayerEnabled), MethodType.Getter)] + public static bool GameManager_IsMultiplayerEnabled(ref bool __result) + { + if (Application.platform != RuntimePlatform.Android) return true; + __result = true; + return false; + } + + /// + /// Replace the Android login flow to skip Google Play Games SDK entirely. + /// Uses deviceUniqueIdentifier as the auth code for the Polydystopia backend. + /// + [HarmonyPrefix] + [HarmonyPatch(typeof(PolytopiaBackendAdapter), "LoginPlatformAndroid")] + public static bool LoginPlatformAndroid_Prefix( + ref Il2CppSystem.Threading.Tasks.Task> __result, + PolytopiaBackendAdapter __instance) + { + if (Application.platform != RuntimePlatform.Android) return true; + + // Mark social login as cached so the post-login flow doesn't bail out + __instance.HasSocialLoginCached = true; + + var model = new LoginGooglePlayBindingModel(); + model.AuthCode = SystemInfo.deviceUniqueIdentifier; + model.DeviceId = SystemInfo.deviceUniqueIdentifier; + + Plugin.logger.LogInfo($"Multiplayer> Android login with DeviceId: {model.DeviceId}"); + __result = __instance.LoginGooglePlay(model); + return false; } [HarmonyPostfix] @@ -192,6 +236,9 @@ private static bool BackendAdapter_StartLobbyGame_Modded( BackendAdapter __instance, StartLobbyBindingModel model) { + // On Android, let the game's original StartLobbyGame handle it + if (Application.platform == RuntimePlatform.Android) return true; + Plugin.logger.LogInfo("Multiplayer> BackendAdapter_StartLobbyGame_Modded"); var taskCompletionSource = new Il2CppSystem.Threading.Tasks.TaskCompletionSource>(); From 56c1f1145135560aa9d66bb5c4826b6a9a26af0d Mon Sep 17 00:00:00 2001 From: Demonofpower Date: Mon, 6 Jul 2026 22:12:44 +0200 Subject: [PATCH 02/11] minor button arrange fix --- src/Multiplayer/Multiplayer.cs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/Multiplayer/Multiplayer.cs b/src/Multiplayer/Multiplayer.cs index 81c6355..fe855fe 100644 --- a/src/Multiplayer/Multiplayer.cs +++ b/src/Multiplayer/Multiplayer.cs @@ -92,6 +92,20 @@ private static void StartScreen_UI2_HideButtons(StartScreen_UI2 __instance) __instance.weeklyChallengeButton.gameObject.SetActive(false); } + [HarmonyPostfix] + [HarmonyPatch(typeof(StartScreen_UI2), nameof(StartScreen_UI2.RunLayout))] + private static void StartScreen_UI2_ReflowRoundButtons(StartScreen_UI2 __instance, ScreenBase_UI2.ScreenSize screenSize) + { + // RunLayout adds all four round buttons to a UITable unconditionally, so hiding the highscore button leaves a gap. Re-run the row without it so the rest recenter. + UITable table = new(); + table.AddCell(__instance.settingsButton); + table.AddCell(__instance.throneRoomButton); + table.AddCell(__instance.aboutButton); + table.SetBottom(screenSize.safeRect.Bottom + __instance.settingsButton.GetHalfHeight() + 15f); + table.margin = 20f; + table.RunLayout(); + } + [HarmonyPostfix] [HarmonyPatch(typeof(SystemInfo), nameof(SystemInfo.deviceUniqueIdentifier), MethodType.Getter)] public static void SteamClient_get_SteamId(ref string __result) From dc1d176509747d76d1e60e2cb15297fe22e6f241 Mon Sep 17 00:00:00 2001 From: Demonofpower Date: Thu, 9 Jul 2026 22:04:03 +0200 Subject: [PATCH 03/11] minor android refactoring --- src/Android/AndroidHandler.cs | 75 ++++++++++++++++++++++++++++++++++ src/Multiplayer/Multiplayer.cs | 45 ++------------------ src/Plugin.cs | 2 + 3 files changed, 80 insertions(+), 42 deletions(-) create mode 100644 src/Android/AndroidHandler.cs diff --git a/src/Android/AndroidHandler.cs b/src/Android/AndroidHandler.cs new file mode 100644 index 0000000..f8a9c7f --- /dev/null +++ b/src/Android/AndroidHandler.cs @@ -0,0 +1,75 @@ +using HarmonyLib; +using PolytopiaBackendBase; +using PolytopiaBackendBase.Auth; +using UnityEngine; + +namespace PolyMod.Android; + +public static class AndroidHandler +{ + internal static void Init() + { + if (Application.platform != RuntimePlatform.Android) return; + + Harmony.CreateAndPatchAll(typeof(AndroidHandler)); + } + + /// + /// On Android, bypass multiplayer requirements that depend on + /// Google Play login, push notifications, and purchases — none of which work + /// when running as a wrapper app with a different package identity. + /// + [HarmonyPrefix] + [HarmonyPatch(typeof(GameManager), nameof(GameManager.IsMultiplayerEnabled), MethodType.Getter)] + public static bool GameManager_IsMultiplayerEnabled(ref bool __result) + { + __result = true; + return false; + } + + /// + /// Replace the Android login flow to skip Google Play Games SDK entirely. + /// Uses deviceUniqueIdentifier as the auth code for the Polydystopia backend. + /// + [HarmonyPrefix] + [HarmonyPatch(typeof(PolytopiaBackendAdapter), "LoginPlatformAndroid")] + public static bool LoginPlatformAndroid_Prefix( + ref Il2CppSystem.Threading.Tasks.Task> __result, + PolytopiaBackendAdapter __instance) + { + // Mark social login as cached so the post-login flow doesn't bail out + __instance.HasSocialLoginCached = true; + + var model = new LoginGooglePlayBindingModel(); + model.AuthCode = SystemInfo.deviceUniqueIdentifier; + model.DeviceId = SystemInfo.deviceUniqueIdentifier; + + Plugin.logger.LogInfo($"Multiplayer> Android login with DeviceId: {model.DeviceId}"); + __result = __instance.LoginGooglePlay(model); + return false; + } + + /// + /// On android Firebase cannot initialize inside the launcher process (its config lives in the game APK's resources, and the native lib may be unreachable there). + /// We try to skip Firebase completely. + /// + [HarmonyPrefix] + [HarmonyPatch(typeof(AnalyticsManager), nameof(AnalyticsManager.IsAnalyticsEnabled))] + private static bool AnalyticsManager_IsAnalyticsEnabled(ref bool __result) + { + __result = false; + return false; + } + + /// + /// On android Firebase cannot initialize inside the launcher process (its config lives in the game APK's resources, and the native lib may be unreachable there). + /// We try to skip Firebase completely. + /// + [HarmonyPrefix] + [HarmonyPatch(typeof(FirebaseMessagingManager), nameof(FirebaseMessagingManager.Init))] + private static bool FirebaseMessagingManager_Init(FirebaseMessagingManager __instance) + { + __instance.isFirebaseInitialized = true; + return false; + } +} \ No newline at end of file diff --git a/src/Multiplayer/Multiplayer.cs b/src/Multiplayer/Multiplayer.cs index fe855fe..2058aa0 100644 --- a/src/Multiplayer/Multiplayer.cs +++ b/src/Multiplayer/Multiplayer.cs @@ -39,44 +39,6 @@ internal static void Init() Plugin.logger.LogInfo($"Multiplayer> Server URL set to: {Plugin.config.backendUrl}"); } - /// - /// On Android, bypass multiplayer requirements that depend on - /// Google Play login, push notifications, and purchases — none of which work - /// when running as a wrapper app with a different package identity. - /// - [HarmonyPrefix] - [HarmonyPatch(typeof(GameManager), nameof(GameManager.IsMultiplayerEnabled), MethodType.Getter)] - public static bool GameManager_IsMultiplayerEnabled(ref bool __result) - { - if (Application.platform != RuntimePlatform.Android) return true; - __result = true; - return false; - } - - /// - /// Replace the Android login flow to skip Google Play Games SDK entirely. - /// Uses deviceUniqueIdentifier as the auth code for the Polydystopia backend. - /// - [HarmonyPrefix] - [HarmonyPatch(typeof(PolytopiaBackendAdapter), "LoginPlatformAndroid")] - public static bool LoginPlatformAndroid_Prefix( - ref Il2CppSystem.Threading.Tasks.Task> __result, - PolytopiaBackendAdapter __instance) - { - if (Application.platform != RuntimePlatform.Android) return true; - - // Mark social login as cached so the post-login flow doesn't bail out - __instance.HasSocialLoginCached = true; - - var model = new LoginGooglePlayBindingModel(); - model.AuthCode = SystemInfo.deviceUniqueIdentifier; - model.DeviceId = SystemInfo.deviceUniqueIdentifier; - - Plugin.logger.LogInfo($"Multiplayer> Android login with DeviceId: {model.DeviceId}"); - __result = __instance.LoginGooglePlay(model); - return false; - } - [HarmonyPostfix] [HarmonyPatch(typeof(MultiplayerSelectionScreen), nameof(MultiplayerSelectionScreen.Awake))] public static void MultiplayerSelectionScreen_Awake(MultiplayerSelectionScreen __instance) @@ -98,9 +60,9 @@ private static void StartScreen_UI2_ReflowRoundButtons(StartScreen_UI2 __instanc { // RunLayout adds all four round buttons to a UITable unconditionally, so hiding the highscore button leaves a gap. Re-run the row without it so the rest recenter. UITable table = new(); - table.AddCell(__instance.settingsButton); - table.AddCell(__instance.throneRoomButton); - table.AddCell(__instance.aboutButton); + table.AddCell(__instance.settingsButton.Cast()); + table.AddCell(__instance.throneRoomButton.Cast()); + table.AddCell(__instance.aboutButton.Cast()); table.SetBottom(screenSize.safeRect.Bottom + __instance.settingsButton.GetHalfHeight() + 15f); table.margin = 20f; table.RunLayout(); @@ -116,7 +78,6 @@ public static void SteamClient_get_SteamId(ref string __result) } } - /// /// After GameState deserialization, check for trailing GLD version ID and set mockedGameLogicData. /// The server appends "##GLD:" + modGldVersion (int) after the normal serialized data. diff --git a/src/Plugin.cs b/src/Plugin.cs index 924944c..25a496c 100644 --- a/src/Plugin.cs +++ b/src/Plugin.cs @@ -3,6 +3,7 @@ using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; +using PolyMod.Android; using PolyMod.Managers; using UnityEngine; @@ -135,6 +136,7 @@ public override void Load() Main.Init(); Multiplayer.Client.Init(); + AndroidHandler.Init(); } /// From b70e321ca58a55a4f86ef116237c8391bb58cad6 Mon Sep 17 00:00:00 2001 From: Demonofpower Date: Thu, 9 Jul 2026 22:08:53 +0200 Subject: [PATCH 04/11] added default values to class vars to fix pipeline --- src/Multiplayer/ViewModels/SetupGameDataViewModel.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Multiplayer/ViewModels/SetupGameDataViewModel.cs b/src/Multiplayer/ViewModels/SetupGameDataViewModel.cs index 68f43f1..41274bd 100644 --- a/src/Multiplayer/ViewModels/SetupGameDataViewModel.cs +++ b/src/Multiplayer/ViewModels/SetupGameDataViewModel.cs @@ -2,9 +2,9 @@ namespace PolyMod.Multiplayer.ViewModels; public class SetupGameDataViewModel : IMonoServerResponseData { - public string lobbyId { get; set; } + public string lobbyId { get; set; } = string.Empty; - public byte[] serializedGameState { get; set; } + public byte[] serializedGameState { get; set; } = Array.Empty(); - public string gameSettingsJson { get; set; } + public string gameSettingsJson { get; set; } = string.Empty; } \ No newline at end of file From 19ac56e6b633b3727be8c533ebac7acde2b863a0 Mon Sep 17 00:00:00 2001 From: Demonofpower Date: Thu, 9 Jul 2026 22:19:09 +0200 Subject: [PATCH 05/11] more firebase fixes --- src/Android/AndroidHandler.cs | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/src/Android/AndroidHandler.cs b/src/Android/AndroidHandler.cs index f8a9c7f..18a8d9f 100644 --- a/src/Android/AndroidHandler.cs +++ b/src/Android/AndroidHandler.cs @@ -63,13 +63,27 @@ private static bool AnalyticsManager_IsAnalyticsEnabled(ref bool __result) /// /// On android Firebase cannot initialize inside the launcher process (its config lives in the game APK's resources, and the native lib may be unreachable there). - /// We try to skip Firebase completely. + /// We try to skip Firebase completely. isFirebaseInitialized deliberately stays false: + /// pretending Firebase is up could wake isFirebaseInitialized-guarded code paths + /// (e.g. HandleOpenedThroughNotification on every app resume). /// [HarmonyPrefix] [HarmonyPatch(typeof(FirebaseMessagingManager), nameof(FirebaseMessagingManager.Init))] - private static bool FirebaseMessagingManager_Init(FirebaseMessagingManager __instance) + private static bool FirebaseMessagingManager_Init() + { + return false; + } + + /// + /// RequestPushNotificationPermissions (the push-notification row in LoginDetails) calls + /// InitAsync directly, bypassing Init — with isFirebaseInitialized kept false that would + /// still reach Firebase, so hand back a completed task instead. + /// + [HarmonyPrefix] + [HarmonyPatch(typeof(FirebaseMessagingManager), nameof(FirebaseMessagingManager.InitAsync))] + private static bool FirebaseMessagingManager_InitAsync(ref Il2CppSystem.Threading.Tasks.Task __result) { - __instance.isFirebaseInitialized = true; + __result = Il2CppSystem.Threading.Tasks.Task.CompletedTask; return false; } } \ No newline at end of file From a76a1031f04a06394f63f58a23274603e56261d8 Mon Sep 17 00:00:00 2001 From: Demonofpower Date: Thu, 9 Jul 2026 23:05:24 +0200 Subject: [PATCH 06/11] bumped version to see in logs on android --- PolyMod.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PolyMod.csproj b/PolyMod.csproj index 2c165a4..783658f 100644 --- a/PolyMod.csproj +++ b/PolyMod.csproj @@ -11,7 +11,7 @@ IL2CPP PolyMod - 1.3.0-pre + 1.3.0-pre-android-1 2.17.2.16299 PolyModdingTeam The Battle of Polytopia's mod loader. From f43a1c82dcf00ed57cb3878153275cea3f960c30 Mon Sep 17 00:00:00 2001 From: Demonofpower Date: Wed, 22 Jul 2026 22:17:42 +0200 Subject: [PATCH 07/11] multiplayer refactoring + added client only helper --- src/Managers/Compatibility.cs | 9 ++ src/Multiplayer/ModMultiplayer.cs | 228 ++++++++++++++++++++++++++++++ src/Multiplayer/Multiplayer.cs | 197 +------------------------- src/Plugin.cs | 2 + 4 files changed, 241 insertions(+), 195 deletions(-) create mode 100644 src/Multiplayer/ModMultiplayer.cs diff --git a/src/Managers/Compatibility.cs b/src/Managers/Compatibility.cs index 1d55bb7..9359df3 100644 --- a/src/Managers/Compatibility.cs +++ b/src/Managers/Compatibility.cs @@ -21,6 +21,15 @@ internal static class Compatibility internal static bool shouldResetSettings = false; private static bool sawSignatureWarning; + /// + /// Whether all loaded mods are client only. If at least one non client only mod exists this returns false. + /// + /// + public static bool IsClientOnly() + { + return Registry.mods.Select(modPair => modPair.Value).All(mod => mod.client); + } + /// /// Hashes the signatures of all loaded mods to create a checksum. /// diff --git a/src/Multiplayer/ModMultiplayer.cs b/src/Multiplayer/ModMultiplayer.cs new file mode 100644 index 0000000..67fe011 --- /dev/null +++ b/src/Multiplayer/ModMultiplayer.cs @@ -0,0 +1,228 @@ +using HarmonyLib; +using Il2CppMicrosoft.AspNetCore.SignalR.Client; +using Newtonsoft.Json; +using PolyMod.Managers; +using PolyMod.Multiplayer.ViewModels; +using Polytopia.Data; +using PolytopiaBackendBase; +using PolytopiaBackendBase.Common; +using PolytopiaBackendBase.Game; +using PolytopiaBackendBase.Game.BindingModels; +using UnityEngine; + +namespace PolyMod.Multiplayer; + +public class ModMultiplayer +{ + internal static void Init() + { + if (Compatibility.IsClientOnly()) + { + Plugin.logger?.LogInfo($"All loaded mods are client only. Skipping modded multiplayer initialization."); + + return; + } + + Plugin.logger?.LogInfo($"Starting modded multiplayer initialization."); + + Harmony.CreateAndPatchAll(typeof(ModMultiplayer)); + + + Plugin.logger?.LogInfo($"Finished modded multiplayer initialization."); + } + + [HarmonyPrefix] + [HarmonyPatch(typeof(BackendAdapter), nameof(BackendAdapter.StartLobbyGame))] + private static bool BackendAdapter_StartLobbyGame_Modded( + ref Il2CppSystem.Threading.Tasks.Task> __result, + BackendAdapter __instance, + StartLobbyBindingModel model) + { + // On Android, let the game's original StartLobbyGame handle it + if (Application.platform == RuntimePlatform.Android) return true; + + Plugin.logger.LogInfo("Multiplayer> BackendAdapter_StartLobbyGame_Modded"); + var taskCompletionSource = new Il2CppSystem.Threading.Tasks.TaskCompletionSource>(); + + _ = HandleStartLobbyGameModded(taskCompletionSource, __instance, model); + + __result = taskCompletionSource.Task; + + return false; + } + + private static async System.Threading.Tasks.Task HandleStartLobbyGameModded( + Il2CppSystem.Threading.Tasks.TaskCompletionSource> tcs, + BackendAdapter instance, + StartLobbyBindingModel model) + { + try + { + var lobbyResponse = await PolytopiaBackendAdapter.Instance.GetLobby(new GetLobbyBindingModel + { + LobbyId = model.LobbyId + }); + + Plugin.logger.LogInfo($"Multiplayer> Lobby processed {lobbyResponse.Success}"); + LobbyGameViewModel lobbyGameViewModel = lobbyResponse.Data; + Plugin.logger.LogInfo("Multiplayer> Lobby received"); + + (byte[] serializedGameState, string gameSettingsJson) = CreateMultiplayerGame( + lobbyGameViewModel, + VersionManager.GameVersion, + VersionManager.GameLogicDataVersion + ); + + Plugin.logger.LogInfo("Multiplayer> GameState and Settings created"); + + var setupGameDataViewModel = new SetupGameDataViewModel + { + lobbyId = lobbyGameViewModel.Id.ToString(), + serializedGameState = serializedGameState, + gameSettingsJson = gameSettingsJson + }; + + var setupData = System.Text.Json.JsonSerializer.Serialize(setupGameDataViewModel); + + var serverResponse = await instance.HubConnection.InvokeAsync>( + "StartLobbyGameModded", + setupData, + Il2CppSystem.Threading.CancellationToken.None + ); + Plugin.logger.LogInfo("Multiplayer> Invoked StartLobbyGameModded"); + tcs.SetResult(serverResponse); + } + catch (Exception ex) + { + Plugin.logger.LogError("Multiplayer> Error during HandleStartLobbyGameModded: " + ex.Message); + tcs.SetException(new Il2CppSystem.Exception(ex.Message)); + } + } + + public static (byte[] serializedGameState, string gameSettingsJson) CreateMultiplayerGame(LobbyGameViewModel lobby, + int gameVersion, int gameLogicVersion) + { + var lobbyMapSize = lobby.MapSize; + var settings = new GameSettings(); + settings.ApplyLobbySettings(lobby); + if (settings.LiveGamePreset) + { + settings.SetLiveModePreset(); + } + foreach (var participatorViewModel in lobby.Participators) + { + var humanPlayer = new PlayerData + { + type = PlayerDataType.LocalUser, + state = PlayerDataFriendshipState.Accepted, + knownTribe = true, + tribe = (TribeType)participatorViewModel.SelectedTribe, + tribeMix = (TribeType)participatorViewModel.SelectedTribe, + skinType = (SkinType)participatorViewModel.SelectedTribeSkin, + defaultName = participatorViewModel.GetNameInternal() + }; + humanPlayer.profile.id = participatorViewModel.UserId; + humanPlayer.profile.SetName(participatorViewModel.GetNameInternal()); + SerializationHelpers.FromByteArray(participatorViewModel.AvatarStateData, out var avatarState); + humanPlayer.profile.avatarState = avatarState; + + settings.AddPlayer(humanPlayer); + } + + foreach (var botDifficulty in lobby.Bots) + { + var botGuid = Il2CppSystem.Guid.NewGuid(); + + var botPlayer = new PlayerData + { + type = PlayerDataType.Bot, + state = PlayerDataFriendshipState.Accepted, + knownTribe = true, + tribe = Enum.GetValues().Where(t => t != TribeType.None) + .OrderBy(x => Il2CppSystem.Guid.NewGuid()).First() + }; + ; + botPlayer.botDifficulty = (BotDifficulty)botDifficulty; + botPlayer.skinType = SkinType.Default; + botPlayer.defaultName = "Bot" + botGuid; + botPlayer.profile.id = botGuid; + + settings.AddPlayer(botPlayer); + } + + GameState gameState = new GameState() + { + Version = gameVersion, + Settings = settings, + PlayerStates = new Il2CppSystem.Collections.Generic.List() + }; + + for (int index = 0; index < settings.GetPlayerCount(); ++index) + { + PlayerData player = settings.GetPlayer(index); + if (player.type != PlayerDataType.Bot) + { + var nullableGuid = new Il2CppSystem.Nullable(player.profile.id); + if (!nullableGuid.HasValue) + { + throw new Exception("GUID was not set properly!"); + } + PlayerState playerState = new PlayerState() + { + Id = (byte)(index + 1), + AccountId = nullableGuid, + AutoPlay = player.type == PlayerDataType.Bot, + UserName = player.GetNameInternal(), + tribe = player.tribe, + tribeMix = player.tribeMix, + hasChosenTribe = true, + skinType = player.skinType + }; + gameState.PlayerStates.Add(playerState); + Plugin.logger.LogInfo($"Multiplayer> Created player: {playerState}"); + } + else + { + GameStateUtils.AddAIOpponent(gameState, GameStateUtils.GetRandomPickableTribe(gameState), + GameSettings.HandicapFromDifficulty(player.botDifficulty), player.skinType); + } + } + + GameStateUtils.SetPlayerColors(gameState); + GameStateUtils.AddNaturePlayer(gameState); + + Plugin.logger.LogInfo("Multiplayer> Creating world..."); + + ushort num = (ushort)Math.Max(lobbyMapSize, + (int)MapDataExtensions.GetMinimumMapSize(gameState.PlayerCount)); + gameState.Map = new MapData(num, num); + MapGeneratorSettings generatorSettings = settings.GetMapGeneratorSettings(); + new MapGenerator().Generate(gameState, generatorSettings); + + Plugin.logger.LogInfo($"Multiplayer> Creating initial state for {gameState.PlayerCount} players..."); + + foreach (PlayerState player in gameState.PlayerStates) + { + foreach (PlayerState otherPlayer in gameState.PlayerStates) + player.aggressions[otherPlayer.Id] = 0; + + if (player.Id != byte.MaxValue && gameState.GameLogicData.TryGetData(player.tribe, out TribeData tribeData)) + { + player.Currency = tribeData.startingStars; + TileData tile = gameState.Map.GetTile(player.startTile); + UnitState unitState = ActionUtils.TrainUnitScored(gameState, player, tile, tribeData.startingUnit); + unitState.attacked = false; + unitState.moved = false; + } + } + + Plugin.logger.LogInfo("Multiplayer> Session created successfully"); + + gameState.CommandStack.Add((CommandBase)new StartMatchCommand((byte)1)); + + var serializedGameState = SerializationHelpers.ToByteArray(gameState, gameState.Version); + + return (serializedGameState, + JsonConvert.SerializeObject(gameState.Settings)); + } +} \ No newline at end of file diff --git a/src/Multiplayer/Multiplayer.cs b/src/Multiplayer/Multiplayer.cs index 2058aa0..1520742 100644 --- a/src/Multiplayer/Multiplayer.cs +++ b/src/Multiplayer/Multiplayer.cs @@ -84,6 +84,7 @@ public static void SteamClient_get_SteamId(ref string __result) /// [HarmonyPostfix] [HarmonyPatch(typeof(GameState), nameof(GameState.Deserialize))] + [Obsolete("This will be succeeded by ModMultiplayer in the future.")] private static void Deserialize_Postfix(GameState __instance, BinaryReader __0) { if(!allowGldMods) return; @@ -171,6 +172,7 @@ private static void Deserialize_Postfix(GameState __instance, BinaryReader __0) /// /// Fetch GLD from server using ModGldVersion ID /// + [Obsolete("This will be succeeded by ModMultiplayer in the future.")] private static string? FetchGldById(int modGldVersion) { if(!allowGldMods) return null; @@ -203,199 +205,4 @@ private static void Deserialize_Postfix(GameState __instance, BinaryReader __0) } return null; } - - [HarmonyPrefix] - [HarmonyPatch(typeof(BackendAdapter), nameof(BackendAdapter.StartLobbyGame))] - private static bool BackendAdapter_StartLobbyGame_Modded( - ref Il2CppSystem.Threading.Tasks.Task> __result, - BackendAdapter __instance, - StartLobbyBindingModel model) - { - // On Android, let the game's original StartLobbyGame handle it - if (Application.platform == RuntimePlatform.Android) return true; - - Plugin.logger.LogInfo("Multiplayer> BackendAdapter_StartLobbyGame_Modded"); - var taskCompletionSource = new Il2CppSystem.Threading.Tasks.TaskCompletionSource>(); - - _ = HandleStartLobbyGameModded(taskCompletionSource, __instance, model); - - __result = taskCompletionSource.Task; - - return false; - } - - private static async System.Threading.Tasks.Task HandleStartLobbyGameModded( - Il2CppSystem.Threading.Tasks.TaskCompletionSource> tcs, - BackendAdapter instance, - StartLobbyBindingModel model) - { - try - { - var lobbyResponse = await PolytopiaBackendAdapter.Instance.GetLobby(new GetLobbyBindingModel - { - LobbyId = model.LobbyId - }); - - Plugin.logger.LogInfo($"Multiplayer> Lobby processed {lobbyResponse.Success}"); - LobbyGameViewModel lobbyGameViewModel = lobbyResponse.Data; - Plugin.logger.LogInfo("Multiplayer> Lobby received"); - - (byte[] serializedGameState, string gameSettingsJson) = CreateMultiplayerGame( - lobbyGameViewModel, - VersionManager.GameVersion, - VersionManager.GameLogicDataVersion - ); - - Plugin.logger.LogInfo("Multiplayer> GameState and Settiings created"); - - var setupGameDataViewModel = new SetupGameDataViewModel - { - lobbyId = lobbyGameViewModel.Id.ToString(), - serializedGameState = serializedGameState, - gameSettingsJson = gameSettingsJson - }; - - var setupData = System.Text.Json.JsonSerializer.Serialize(setupGameDataViewModel); - - var serverResponse = await instance.HubConnection.InvokeAsync>( - "StartLobbyGameModded", - setupData, - Il2CppSystem.Threading.CancellationToken.None - ); - Plugin.logger.LogInfo("Multiplayer> Invoked StartLobbyGameModded"); - tcs.SetResult(serverResponse); - } - catch (Exception ex) - { - Plugin.logger.LogError("Multiplayer> Error during HandleStartLobbyGameModded: " + ex.Message); - tcs.SetException(new Il2CppSystem.Exception(ex.Message)); - } - } - - public static (byte[] serializedGameState, string gameSettingsJson) CreateMultiplayerGame(LobbyGameViewModel lobby, - int gameVersion, int gameLogicVersion) - { - var lobbyMapSize = lobby.MapSize; - var settings = new GameSettings(); - settings.ApplyLobbySettings(lobby); - if (settings.LiveGamePreset) - { - settings.SetLiveModePreset(); - } - foreach (var participatorViewModel in lobby.Participators) - { - var humanPlayer = new PlayerData - { - type = PlayerDataType.LocalUser, - state = PlayerDataFriendshipState.Accepted, - knownTribe = true, - tribe = (TribeType)participatorViewModel.SelectedTribe, - tribeMix = (TribeType)participatorViewModel.SelectedTribe, - skinType = (SkinType)participatorViewModel.SelectedTribeSkin, - defaultName = participatorViewModel.GetNameInternal() - }; - humanPlayer.profile.id = participatorViewModel.UserId; - humanPlayer.profile.SetName(participatorViewModel.GetNameInternal()); - SerializationHelpers.FromByteArray(participatorViewModel.AvatarStateData, out var avatarState); - humanPlayer.profile.avatarState = avatarState; - - settings.AddPlayer(humanPlayer); - } - - foreach (var botDifficulty in lobby.Bots) - { - var botGuid = Il2CppSystem.Guid.NewGuid(); - - var botPlayer = new PlayerData - { - type = PlayerDataType.Bot, - state = PlayerDataFriendshipState.Accepted, - knownTribe = true, - tribe = Enum.GetValues().Where(t => t != TribeType.None) - .OrderBy(x => Il2CppSystem.Guid.NewGuid()).First() - }; - ; - botPlayer.botDifficulty = (BotDifficulty)botDifficulty; - botPlayer.skinType = SkinType.Default; - botPlayer.defaultName = "Bot" + botGuid; - botPlayer.profile.id = botGuid; - - settings.AddPlayer(botPlayer); - } - - GameState gameState = new GameState() - { - Version = gameVersion, - Settings = settings, - PlayerStates = new Il2CppSystem.Collections.Generic.List() - }; - - for (int index = 0; index < settings.GetPlayerCount(); ++index) - { - PlayerData player = settings.GetPlayer(index); - if (player.type != PlayerDataType.Bot) - { - var nullableGuid = new Il2CppSystem.Nullable(player.profile.id); - if (!nullableGuid.HasValue) - { - throw new Exception("GUID was not set properly!"); - } - PlayerState playerState = new PlayerState() - { - Id = (byte)(index + 1), - AccountId = nullableGuid, - AutoPlay = player.type == PlayerDataType.Bot, - UserName = player.GetNameInternal(), - tribe = player.tribe, - tribeMix = player.tribeMix, - hasChosenTribe = true, - skinType = player.skinType - }; - gameState.PlayerStates.Add(playerState); - Plugin.logger.LogInfo($"Multiplayer> Created player: {playerState}"); - } - else - { - GameStateUtils.AddAIOpponent(gameState, GameStateUtils.GetRandomPickableTribe(gameState), - GameSettings.HandicapFromDifficulty(player.botDifficulty), player.skinType); - } - } - - GameStateUtils.SetPlayerColors(gameState); - GameStateUtils.AddNaturePlayer(gameState); - - Plugin.logger.LogInfo("Multiplayer> Creating world..."); - - ushort num = (ushort)Math.Max(lobbyMapSize, - (int)MapDataExtensions.GetMinimumMapSize(gameState.PlayerCount)); - gameState.Map = new MapData(num, num); - MapGeneratorSettings generatorSettings = settings.GetMapGeneratorSettings(); - new MapGenerator().Generate(gameState, generatorSettings); - - Plugin.logger.LogInfo($"Multiplayer> Creating initial state for {gameState.PlayerCount} players..."); - - foreach (PlayerState player in gameState.PlayerStates) - { - foreach (PlayerState otherPlayer in gameState.PlayerStates) - player.aggressions[otherPlayer.Id] = 0; - - if (player.Id != byte.MaxValue && gameState.GameLogicData.TryGetData(player.tribe, out TribeData tribeData)) - { - player.Currency = tribeData.startingStars; - TileData tile = gameState.Map.GetTile(player.startTile); - UnitState unitState = ActionUtils.TrainUnitScored(gameState, player, tile, tribeData.startingUnit); - unitState.attacked = false; - unitState.moved = false; - } - } - - Plugin.logger.LogInfo("Multiplayer> Session created successfully"); - - gameState.CommandStack.Add((CommandBase)new StartMatchCommand((byte)1)); - - var serializedGameState = SerializationHelpers.ToByteArray(gameState, gameState.Version); - - return (serializedGameState, - JsonConvert.SerializeObject(gameState.Settings)); - } } diff --git a/src/Plugin.cs b/src/Plugin.cs index 25a496c..fc5ceb6 100644 --- a/src/Plugin.cs +++ b/src/Plugin.cs @@ -5,6 +5,7 @@ using BepInEx.Logging; using PolyMod.Android; using PolyMod.Managers; +using PolyMod.Multiplayer; using UnityEngine; namespace PolyMod; @@ -136,6 +137,7 @@ public override void Load() Main.Init(); Multiplayer.Client.Init(); + ModMultiplayer.Init(); AndroidHandler.Init(); } From 1d09078f20010da2467904aa20c78c7c532a853b Mon Sep 17 00:00:00 2001 From: Demonofpower Date: Sat, 8 Aug 2026 21:00:09 +0200 Subject: [PATCH 08/11] linux crash fix --- src/Plugin.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Plugin.cs b/src/Plugin.cs index fc5ceb6..b9fcd22 100644 --- a/src/Plugin.cs +++ b/src/Plugin.cs @@ -170,8 +170,9 @@ internal static void UpdateConsole() { ConsoleManager.CreateConsole(); } - else + else if (OperatingSystem.IsWindows()) { + // BepInEx's Unix console driver throws unsupported on detach. Off-Windows there is no separate console window, so there is nothing to detach. ConsoleManager.DetachConsole(); } } From 0fbafab1c36f810187d35e9742736a82c061dc11 Mon Sep 17 00:00:00 2001 From: Demonofpower Date: Sat, 8 Aug 2026 21:16:12 +0200 Subject: [PATCH 09/11] added dystopia server changer --- resources/dystopia_icon.png | Bin 0 -> 95320 bytes src/Managers/Visual.cs | 94 ++++++++++++++- src/Multiplayer/Dystopia.cs | 234 ++++++++++++++++++++++++++++++++++++ src/Plugin.cs | 3 +- 4 files changed, 328 insertions(+), 3 deletions(-) create mode 100644 resources/dystopia_icon.png create mode 100644 src/Multiplayer/Dystopia.cs diff --git a/resources/dystopia_icon.png b/resources/dystopia_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..512162a33c13f239f257b02c92620e45f3cc2da8 GIT binary patch literal 95320 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 Wh&2oZH75e#m%Ox!RE>mL=>Gw2fBiZD literal 0 HcmV?d00001 diff --git a/src/Managers/Visual.cs b/src/Managers/Visual.cs index bccc5fc..d786dec 100644 --- a/src/Managers/Visual.cs +++ b/src/Managers/Visual.cs @@ -55,6 +55,10 @@ public record SkinInfo(int idx, string id, SkinData? skinData); /// A dictionary of custom widths for basic popups. public static Dictionary basicPopupWidths = new(); + /// Original font sizes of popup buttons, so relayouts rescale from the prefab size. + private static readonly Dictionary popupButtonFontSizes = new(); + /// Original scroll viewport bottom offsets of popups, so relayouts don't compound. + private static readonly Dictionary popupScrollBottoms = new(); /// Represents information about a unit prefab. public struct UnitPrefabInfo { @@ -778,7 +782,86 @@ private static void UpdateWidth(PopupBase __instance) { int id = __instance.GetInstanceID(); if (basicPopupWidths.ContainsKey(id)) - __instance.rectTransform.SetWidth(basicPopupWidths[id]); + { + float maxWidth = UIManager.GetUIWidth() - 40f; + float width = Mathf.Min(basicPopupWidths[id], maxWidth); + __instance.rectTransform.SetWidth(width); + LayoutPopupButtons(__instance, width); + } + } + + private const float BUTTON_GAP = 10f; + private const float BUTTON_ROW_PADDING = 40f; + + private static void LayoutPopupButtons(PopupBase popup, float popupWidth) + { + var legacy = popup.TryCast(); + if (legacy == null || legacy.buttonContainer == null) return; + var buttons = legacy.buttonContainer.Buttons; + if (buttons == null || buttons.Length < 2) return; + + float rowWidth = popupWidth - BUTTON_ROW_PADDING; + + foreach (UITextButton button in buttons) + { + int id = button.GetInstanceID(); + if (!popupButtonFontSizes.ContainsKey(id)) + popupButtonFontSizes[id] = button.FontSize; + else + button.FontSize = popupButtonFontSizes[id]; + button.UpdateSize(); + float width = button.rectTransform.GetWidth(); + if (width > rowWidth) + { + button.FontSize *= rowWidth / width; + button.UpdateSize(); + } + } + + List> rows = new(); + float cursor = 0f; + foreach (UITextButton button in buttons) + { + float width = button.rectTransform.GetWidth(); + if (rows.Count == 0 || cursor + width > rowWidth) + { + rows.Add(new()); + cursor = 0f; + } + rows[^1].Add(button); + cursor += width + BUTTON_GAP; + } + + float rowHeight = buttons[0].rectTransform.GetHeight() + BUTTON_GAP; + for (int r = 0; r < rows.Count; r++) + { + float total = -BUTTON_GAP; + foreach (UITextButton button in rows[r]) + total += button.rectTransform.GetWidth() + BUTTON_GAP; + float x = -total / 2f; + float y = (rows.Count - 1 - r) * rowHeight; + foreach (UITextButton button in rows[r]) + { + button.rectTransform.anchorMin = new Vector2(0.5f, 0.5f); + button.rectTransform.anchorMax = new Vector2(0.5f, 0.5f); + button.rectTransform.pivot = new Vector2(0f, 0.5f); + button.rectTransform.anchoredPosition = new Vector2(x, y); + x += button.rectTransform.GetWidth() + BUTTON_GAP; + } + } + + float extra = (rows.Count - 1) * rowHeight; + float maxHeight = (ScreenManager.SafeHeight - 20f) * UICanvasScalerHelper.GetInvertedUIScale(); + popup.rectTransform.SetHeight(Mathf.Min(popup.rectTransform.GetHeight() + extra, maxHeight)); + + if (popup.scrollRect != null) + { + var viewport = popup.scrollRect.GetComponent(); + int popupId = popup.GetInstanceID(); + if (!popupScrollBottoms.ContainsKey(popupId)) + popupScrollBottoms[popupId] = viewport.offsetMin.y; + viewport.offsetMin = new Vector2(viewport.offsetMin.x, popupScrollBottoms[popupId] + extra); + } } /// Sets the attacker's tribe before a unit attacks. @@ -809,12 +892,19 @@ private static void WeaponGFX_SetSkin(WeaponGFX __instance, SkinType skinType) } } - /// Removes a popup's custom width when it is hidden. + /// Removes a popup's custom width and cached button font sizes when it is hidden. [HarmonyPostfix] [HarmonyPatch(typeof(PopupBase), nameof(PopupBase.Hide))] private static void PopupBase_Hide(PopupBase __instance) { basicPopupWidths.Remove(__instance.GetInstanceID()); + popupScrollBottoms.Remove(__instance.GetInstanceID()); + var legacy = __instance.TryCast(); + if (legacy != null && legacy.buttonContainer != null && legacy.buttonContainer.Buttons != null) + { + foreach (UITextButton button in legacy.buttonContainer.Buttons) + popupButtonFontSizes.Remove(button.GetInstanceID()); + } } [HarmonyPrefix] diff --git a/src/Multiplayer/Dystopia.cs b/src/Multiplayer/Dystopia.cs new file mode 100644 index 0000000..9848f3d --- /dev/null +++ b/src/Multiplayer/Dystopia.cs @@ -0,0 +1,234 @@ +using Cpp2IL.Core.Extensions; +using HarmonyLib; +using Il2CppInterop.Runtime; +using PolyMod.Managers; +using PolytopiaBackendBase; +using TMPro; +using UnityEngine; + +namespace PolyMod.Multiplayer; + +/// +/// Adds a "Dystopia" start-screen button with a popup to switch the backend server at runtime. +/// +public static class Dystopia +{ + private const int POPUP_WIDTH = 1400; + + internal const string OFFICIAL_SERVER_URL = "https://polytopia-prod.net/"; + + private record ServerEntry(string name, string url, bool official = false); + + private static readonly ServerEntry[] SERVERS = + { + new("Official", OFFICIAL_SERVER_URL, official: true), + new("Dystopia", "https://polydystopia.xyz"), + new("Dystopia Dev", "https://dev.polydystopia.xyz"), + }; + + /// + /// Default backend: the official server, except on Android + /// + internal static string DefaultServerUrl() + { + return Application.platform == RuntimePlatform.Android + ? Client.DEFAULT_SERVER_URL + : OFFICIAL_SERVER_URL; + } + + private static UIRoundButton_UI2? dystopiaButton = null; + + internal static void Init() + { + Harmony.CreateAndPatchAll(typeof(Dystopia)); + } + + [HarmonyPostfix] + [HarmonyPatch(typeof(StartScreen_UI2), nameof(StartScreen_UI2.Init))] + private static void StartScreen_UI2_Init(StartScreen_UI2 __instance, RectTransform transform) + { + if (dystopiaButton != null) + { + UnityEngine.Object.Destroy(dystopiaButton.gameObject); + } + dystopiaButton = UILibrary.NewRoundButton(transform).SetStyle(UIButtonBase_UI2.ButtonStyle.Suggested); + dystopiaButton.bg.sprite = Visual.BuildSprite(Plugin.GetResource("dystopia_icon.png").ReadBytes()); + dystopiaButton.OnClickedSignal.Add(DelegateSupport.ConvertDelegate(ShowDystopiaPopup)); + } + + [HarmonyPostfix] + [HarmonyPatch(typeof(StartScreen_UI2), nameof(StartScreen_UI2.RunLayout))] + private static void StartScreen_UI2_RunLayout(StartScreen_UI2 __instance, ScreenBase_UI2.ScreenSize screenSize) + { + if (dystopiaButton == null) + { + Plugin.logger.LogWarning("Dystopia button is null when running layout!"); + return; + } + dystopiaButton.iconContainer.gameObject.SetActive(false); + dystopiaButton.outline.gameObject.SetActive(false); + dystopiaButton.bg.color = Color.white; + dystopiaButton.Text = "Dystopia"; + float num = 50f; + + dystopiaButton.SetPosition(screenSize.safeRect.Right - (num * 4.0f), screenSize.safeRect.Top - num); + } + + internal static void ShowDystopiaPopup() + { + string current = Normalize(Plugin.config.backendUrl); + + BasicPopupLegacy popup = Visual.GetBasicPopupLegacy(); + popup.Header = "Dystopia"; + popup.Description = $"Current server:\n{Plugin.config.backendUrl}"; + + List buttons = new() + { + new("buttons.back"), + }; + foreach (ServerEntry server in SERVERS) + { + bool isActive = Normalize(server.url) == current; + // The official server rejects our DeviceId login, so it stays greyed out on Android. + bool isDisabled = isActive || (server.official && Application.platform == RuntimePlatform.Android); + string url = server.url; + buttons.Add(new( + isActive ? server.name + " (active)" : server.name, + isDisabled ? PopupBase.PopupButtonData.States.Disabled : PopupBase.PopupButtonData.States.None, + DelegateSupport.ConvertDelegate((System.Action)(() => SwitchServer(url))) + )); + } + buttons.Add(new( + "Custom...", + callback: DelegateSupport.ConvertDelegate(ShowCustomServerPopup) + )); + popup.buttonData = buttons.ToArray(); + popup.ShowSetWidth(POPUP_WIDTH); + } + + private static void ShowCustomServerPopup() + { + SearchFriendCodePopup popup = PopupManager.GetPopup("dystopiaCustomServerPopup"); + TMP_InputField input = popup.inputfield; + + input.onSubmit = new TMP_InputField.SubmitEvent(); + input.onEndEdit = new TMP_InputField.SubmitEvent(); + input.onValueChanged = new TMP_InputField.OnChangeEvent(); + input.onSelect = new TMP_InputField.SelectionEvent(); + input.onDeselect = new TMP_InputField.SelectionEvent(); + input.contentType = TMP_InputField.ContentType.Standard; + input.characterLimit = 200; + + var placeholder = input.placeholder != null ? input.placeholder.TryCast() : null; + if (placeholder != null) + { + placeholder.text = "Server URL or IP"; + } + + void OnConnect() + { + string url = input.text?.Trim() ?? ""; + if (url.Length == 0) + { + return; + } + if (!url.StartsWith("http://") && !url.StartsWith("https://")) + { + url = "https://" + url; + } + if (!System.Uri.TryCreate(url, System.UriKind.Absolute, out _)) + { + NotificationManager.Notify("Invalid server URL"); + return; + } + popup.Hide(); + SwitchServer(url); + } + + popup.Show(); + popup.Header = "Custom server"; + popup.Description = "Enter the server URL or IP:"; + popup.buttonContainer.ResetContainer(); + popup.buttonData = new PopupBase.PopupButtonData[] + { + new("buttons.back"), + new( + "Connect", + callback: DelegateSupport.ConvertDelegate(OnConnect), + closesPopup: false + ), + }; + input.SetTextWithoutNotify(Plugin.config.backendUrl); + } + + private static async void SwitchServer(string url) + { + Plugin.logger.LogInfo($"Dystopia> Switching server to {url}"); + Plugin.config = Plugin.config with { backendUrl = url }; + Plugin.WriteConfig(); + + PolytopiaBackendAdapter adapter = PolytopiaBackendAdapter.Instance; + + await adapter.CloseConnection(); + + BuildConfig buildConfig = BuildConfigHelper.GetSelectedBuildConfig(); + buildConfig.buildServerURL = BuildServerURL.Custom; + buildConfig.customServerURL = url; + + adapter.UseBackendUri(new Il2CppSystem.Uri(url)); + adapter.UseHttpClient(); + + PurgeServerCaches(); + + adapter.ConnectionStatus = ConnectionStatus.None; + BackendEvents.BackendConnectionChanged(ConnectionStatus.Disconnected, false); + + GameManager.GetLoginManager().Login(false, true); + Plugin.logger.LogInfo($"Dystopia> Reconnect to {url} initiated"); + } + + private static void PurgeServerCaches() + { + try + { + var remote = GameManager.GetRemoteGameDataManager(); + remote.gameDataCache.Clear(); + remote.matchmakingGameDataCache?.Clear(); + remote.gameIdCache.Clear(); + remote.hasLoadedGameDataCache = false; + + var lobbies = GameManager.GetLobbyManager(); + lobbies.cachedLobbies.Clear(); + lobbies.hasCachedLobbies = false; + + AccountManager.currentPlayerData = null; + AccountManager.friends = null; + AccountManager.friendViewModels = null; + AccountManager.playersStatuses?.Clear(); + AccountManager.ClearCachedPlayerId(); + + DeleteIfExists(Paths.GetUserProfileCachePath()); + DeleteIfExists(Paths.GetStartupDataPath()); + + GameManager.GetWeeklyChallengeModel().ClearData(); + GameManager.ActionableGamesCount = 0; + } + catch (System.Exception e) + { + Plugin.logger.LogWarning($"Dystopia> Failed to purge some server caches: {e}"); + } + } + + private static void DeleteIfExists(string path) + { + if (File.Exists(path)) + { + File.Delete(path); + } + } + + private static string Normalize(string url) + { + return url.TrimEnd('/').ToLowerInvariant(); + } +} diff --git a/src/Plugin.cs b/src/Plugin.cs index b9fcd22..148e2ae 100644 --- a/src/Plugin.cs +++ b/src/Plugin.cs @@ -119,7 +119,7 @@ public override void Load() } catch { - config = new(); + config = new(backendUrl: Multiplayer.Dystopia.DefaultServerUrl()); } WriteConfig(); UpdateConsole(); @@ -138,6 +138,7 @@ public override void Load() Main.Init(); Multiplayer.Client.Init(); ModMultiplayer.Init(); + Multiplayer.Dystopia.Init(); AndroidHandler.Init(); } From 459b574fc16656323cbb14ea2ca106287fbfdb3a Mon Sep 17 00:00:00 2001 From: Demonofpower Date: Sat, 8 Aug 2026 21:17:38 +0200 Subject: [PATCH 10/11] minor refactoring --- src/Plugin.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Plugin.cs b/src/Plugin.cs index 148e2ae..ee514f8 100644 --- a/src/Plugin.cs +++ b/src/Plugin.cs @@ -136,9 +136,9 @@ public override void Load() Hub.Init(); Main.Init(); - Multiplayer.Client.Init(); + Client.Init(); ModMultiplayer.Init(); - Multiplayer.Dystopia.Init(); + Dystopia.Init(); AndroidHandler.Init(); } From 2b78e8dc3773c60a3f12bf714725c1371a3547f1 Mon Sep 17 00:00:00 2001 From: Demonofpower Date: Sat, 8 Aug 2026 22:29:33 +0200 Subject: [PATCH 11/11] added mod lobby creation flags in createlobby backend call --- src/Multiplayer/ModMultiplayer.cs | 44 +++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/src/Multiplayer/ModMultiplayer.cs b/src/Multiplayer/ModMultiplayer.cs index 67fe011..115c09f 100644 --- a/src/Multiplayer/ModMultiplayer.cs +++ b/src/Multiplayer/ModMultiplayer.cs @@ -1,6 +1,7 @@ using HarmonyLib; using Il2CppMicrosoft.AspNetCore.SignalR.Client; using Newtonsoft.Json; +using Newtonsoft.Json.Linq; using PolyMod.Managers; using PolyMod.Multiplayer.ViewModels; using Polytopia.Data; @@ -31,6 +32,49 @@ internal static void Init() Plugin.logger?.LogInfo($"Finished modded multiplayer initialization."); } + [HarmonyPrefix] + [HarmonyPatch(typeof(BackendAdapter), nameof(BackendAdapter.CreateLobby))] + private static bool BackendAdapter_CreateLobby( + ref Il2CppSystem.Threading.Tasks.Task> __result, + BackendAdapter __instance, + CreateLobbyBindingModel model) + { + Plugin.logger.LogInfo("Multiplayer> BackendAdapter_CreateLobby"); + var taskCompletionSource = new Il2CppSystem.Threading.Tasks.TaskCompletionSource>(); + + _ = HandleCreateLobbyModded(taskCompletionSource, __instance, model); + + __result = taskCompletionSource.Task; + + return false; + } + + private static async System.Threading.Tasks.Task HandleCreateLobbyModded( + Il2CppSystem.Threading.Tasks.TaskCompletionSource> tcs, + BackendAdapter instance, + CreateLobbyBindingModel model) + { + try + { + var payload = JObject.FromObject(model); + payload["IsModded"] = new JValue(true); + payload["Checksum"] = new JValue(Compatibility.checksum); + + var serverResponse = await instance.HubConnection.InvokeAsync>( + "CreateLobby", + payload, + Il2CppSystem.Threading.CancellationToken.None + ); + Plugin.logger.LogInfo("Multiplayer> Invoked CreateLobby with mod info"); + tcs.SetResult(serverResponse); + } + catch (Exception ex) + { + Plugin.logger.LogError("Multiplayer> Error during HandleCreateLobbyModded: " + ex.Message); + tcs.SetException(new Il2CppSystem.Exception(ex.Message)); + } + } + [HarmonyPrefix] [HarmonyPatch(typeof(BackendAdapter), nameof(BackendAdapter.StartLobbyGame))] private static bool BackendAdapter_StartLobbyGame_Modded(