diff --git a/PolyMod.csproj b/PolyMod.csproj index a09c089..54dc82f 100644 --- a/PolyMod.csproj +++ b/PolyMod.csproj @@ -11,8 +11,8 @@ IL2CPP PolyMod - 1.2.13 - 2.16.8.15757 + 1.2.14 + 2.17.0.16256 PolyModdingTeam The Battle of Polytopia's mod loader. IDE0130 diff --git a/src/Managers/AutoUpdate.cs b/src/Managers/AutoUpdate.cs index 1f94fb8..6384616 100644 --- a/src/Managers/AutoUpdate.cs +++ b/src/Managers/AutoUpdate.cs @@ -15,8 +15,8 @@ internal static class AutoUpdate /// Checks for updates when the start screen is shown. /// [HarmonyPostfix] - [HarmonyPatch(typeof(StartScreen), nameof(StartScreen.Start))] - private static void StartScreen_Start() + [HarmonyPatch(typeof(StartScreen_UI2), nameof(StartScreen_UI2.OnShow))] + private static void StartScreen_UI2_OnShow() { if (!Plugin.config.autoUpdate) return; if (Environment.GetEnvironmentVariable("WINEPREFIX") != null) @@ -154,7 +154,7 @@ exit 0 } // Show a popup to the user asking if they want to update - PopupManager.GetBasicPopup(new( + PopupManager.GetBasicPopupWithData(new( Localization.Get("polymod.autoupdate"), Localization.Get("polymod.autoupdate.description"), new(new PopupBase.PopupButtonData[] { diff --git a/src/Managers/Compatibility.cs b/src/Managers/Compatibility.cs index 4d42033..1d55bb7 100644 --- a/src/Managers/Compatibility.cs +++ b/src/Managers/Compatibility.cs @@ -34,7 +34,7 @@ public static void HashSignatures(StringBuilder checksumString) /// Checks the signature of a saved game to ensure it is compatible with the current mods. /// /// True if the signatures match or if the check is ignored, false otherwise. - private static bool CheckSignatures(Action action, int id, BaseEventData eventData, Il2CppSystem.Guid gameId) + private static bool CheckSignatures(Action action, Il2CppSystem.Guid gameId) { if (sawSignatureWarning) { @@ -67,13 +67,14 @@ private static bool CheckSignatures(Action action, int id, B } if (!doChecksumsMatch) { - PopupManager.GetBasicPopup(new( + PopupManager.GetBasicPopupWithData(new( Localization.Get("polymod.signature.mismatch"), Localization.Get("polymod.signature.incompatible"), new(new PopupBase.PopupButtonData[] { new("OK") }) )).Show(); + return false; } return true; @@ -83,8 +84,8 @@ private static bool CheckSignatures(Action action, int id, B /// Performs compatibility checks when the start screen is shown. /// [HarmonyPostfix] - [HarmonyPatch(typeof(StartScreen), nameof(StartScreen.Start))] - private static void StartScreen_Start() + [HarmonyPatch(typeof(StartScreen_UI2), nameof(StartScreen_UI2.OnShow))] + private static void StartScreen_UI2_OnShow() { string lastChecksum = checksum; try @@ -113,18 +114,20 @@ private static void StartScreen_Start() VersionManager.SemanticVersion.Cast().CutRevision().ToString() ); PlayerPrefs.Save(); - PopupManager.GetBasicPopup(new( - Localization.Get("polymod.version.mismatch"), - Localization.Get("polymod.version.mismatch.description"), - new(new PopupBase.PopupButtonData[] { - new("buttons.stay", customColorStates: ColorConstants.redButtonColorStates), - new( - "buttons.exitgame", - PopupBase.PopupButtonData.States.None, - (Il2CppSystem.Action)Application.Quit, - closesPopup: false - ) - })) + PopupManager.GetBasicPopupWithData( + new( + Localization.Get("polymod.version.mismatch"), + Localization.Get("polymod.version.mismatch.description"), + new PopupBase.PopupButtonData[] { + new("buttons.stay", customColorStates: ColorConstants.redButtonColorStates), + new( + "buttons.exitgame", + PopupBase.PopupButtonData.States.None, + (Il2CppSystem.Action)Application.Quit, + closesPopup: false + ) + } + ) ).Show(); } } @@ -134,19 +137,19 @@ private static void StartScreen_Start() /// [HarmonyPrefix] [HarmonyPatch(typeof(GameInfoPopup), nameof(GameInfoPopup.OnMainButtonClicked))] - private static bool GameInfoPopup_OnMainButtonClicked(GameInfoPopup __instance, int id, BaseEventData eventData) + private static bool GameInfoPopup_OnMainButtonClicked(GameInfoPopup __instance) { - return CheckSignatures(__instance.OnMainButtonClicked, id, eventData, __instance.gameId); + return CheckSignatures(__instance.OnMainButtonClicked, __instance.gameId); } /// /// Checks the signature of a single-player game before resuming it. /// [HarmonyPrefix] - [HarmonyPatch(typeof(StartScreen), nameof(StartScreen.OnResumeButtonClick))] - private static bool StartScreen_OnResumeButtonClick(StartScreen __instance, int id, BaseEventData eventData) + [HarmonyPatch(typeof(StartScreen_UI2), nameof(StartScreen_UI2.OnResumeButtonLongPress))] + private static bool StartScreen_OnResumeButtonClick(StartScreen_UI2 __instance) { - return CheckSignatures(__instance.OnResumeButtonClick, id, eventData, LocalSaveFileUtils.GetSaveFiles(PolytopiaBackendBase.Game.GameType.SinglePlayer)[0]); + return CheckSignatures(__instance.OnResumeButtonLongPress, LocalSaveFileUtils.GetSaveFiles(PolytopiaBackendBase.Game.GameType.SinglePlayer)[0]); } /// diff --git a/src/Managers/Hub.cs b/src/Managers/Hub.cs index 9d06de1..84fc071 100644 --- a/src/Managers/Hub.cs +++ b/src/Managers/Hub.cs @@ -24,6 +24,7 @@ internal static class Hub private const string HEADER_PREFIX = ""; private const string HEADER_POSTFIX = ""; private const int POPUP_WIDTH = 1400; + private static GameObject? polyModButton = null; /// /// Whether the configuration popup is currently active. @@ -64,68 +65,80 @@ private static void PopupButtonContainer_SetButtonData(PopupButtonContainer __in } } + [HarmonyPostfix] + [HarmonyPatch(typeof(StartScreen_UI2), nameof(StartScreen_UI2.OnHide))] + private static void StartScreen_UI2_OnHide(StartScreen_UI2 __instance) + { + if(polyModButton != null) + GameObject.Destroy(polyModButton); + } /// /// Patches the start screen to add the PolyMod hub button and version text. /// - [HarmonyPrefix] - [HarmonyPatch(typeof(StartScreen), nameof(StartScreen.Start))] - private static void StartScreen_Start(StartScreen __instance) + [HarmonyPostfix] + [HarmonyPatch(typeof(StartScreen_UI2), nameof(StartScreen_UI2.OnShow))] + private static void StartScreen_UI2_OnShow(StartScreen_UI2 __instance) { - var bottomBar = __instance.settingsButton.transform.parent; - var bottomBarHorizontalLayoutGroup = bottomBar.GetComponent(); - bottomBarHorizontalLayoutGroup.childAlignment = TextAnchor.LowerCenter; - bottomBarHorizontalLayoutGroup.childForceExpandWidth = false; - bottomBarHorizontalLayoutGroup.childForceExpandHeight = false; - bottomBarHorizontalLayoutGroup.padding.left = 120; - bottomBarHorizontalLayoutGroup.padding.right = bottomBarHorizontalLayoutGroup.padding.left; - - GameObject versionTextObject = GameObject.Instantiate(__instance.settingsButton.label.gameObject, bottomBar); - versionTextObject.name = "PolyModVersion"; - versionTextObject.SetActive(true); - - LayoutElement versionTextLayoutElement = versionTextObject.GetComponent() - ?? versionTextObject.AddComponent(); - versionTextLayoutElement.ignoreLayout = true; - - RectTransform versionTextRectTransform = versionTextObject.GetComponent(); - versionTextRectTransform.anchorMin = Vector2.zero; - versionTextRectTransform.anchorMax = Vector2.zero; - versionTextRectTransform.pivot = Vector2.zero; - versionTextRectTransform.anchoredPosition = new Vector2(5f, 5f); - - TextMeshProUGUI versionTextComponent = versionTextObject.GetComponent(); - versionTextComponent.fontSize = 18f; - versionTextComponent.alignment = TextAlignmentOptions.MidlineLeft; - versionTextComponent.enableWordWrapping = true; - - versionTextRectTransform.sizeDelta = new Vector2(110f, 50f); - - versionTextObject.GetComponent().Text = $"PolyMod {Plugin.VERSION}"; - - GameObject originalButton = __instance.newsButton.gameObject; - GameObject button = GameObject.Instantiate(originalButton, originalButton.transform.parent); + UIRoundButton_UI2 originalButton = __instance.newsButton; + UIRoundButton_UI2 button = GameObject.Instantiate(originalButton, originalButton.transform.parent); button.name = "PolyModHubButton"; - - RectTransform originalButtonRectTransform = originalButton.GetComponent(); - button.transform.position = originalButton.transform.position - new Vector3(originalButtonRectTransform.rect.width * 1.5f, 0, 0); - - UIRoundButton buttonComponent = button.GetComponent(); - buttonComponent.bg.sprite = Visual.BuildSprite(Plugin.GetResource("polymod_icon.png").ReadBytes()); - buttonComponent.bg.transform.localScale = buttonComponent.bg.transform.localScale * 1.2f; - buttonComponent.bg.color = Color.white; - - GameObject.Destroy(buttonComponent.icon.gameObject); - GameObject.Destroy(buttonComponent.outline.gameObject); - - Transform descriptionText = button.transform.Find("DescriptionText"); - descriptionText.gameObject.SetActive(true); - descriptionText.GetComponentInChildren().Key = "polymod.hub"; - - buttonComponent.OnClicked += (UIButtonBase.ButtonAction)PolyModHubButtonClicked; - + button.SetPosition(750, 460); + button.bg.sprite = Visual.BuildSprite(Plugin.GetResource("polymod_icon.png").ReadBytes()); + button.bg.transform.localScale = button.transform.localScale * 1.2f; + button.bg.color = Color.white; + button.iconContainer.gameObject.SetActive(false); + button.outline.gameObject.SetActive(false); + button.OnClicked += (UIButtonBase_UI2.ButtonAction)PolyModHubButtonClicked; + polyModButton = button.gameObject; + // Console.Write(0); + // GameObject versionTextObject = GameObject.Instantiate(__instance.settingsButton.textBg.gameObject); + // versionTextObject.name = "PolyModVersion"; + // versionTextObject.SetActive(true); + // Console.Write(2); + // LayoutElement versionTextLayoutElement = versionTextObject.GetComponent() + // ?? versionTextObject.AddComponent(); + // versionTextLayoutElement.ignoreLayout = true; + + // RectTransform versionTextRectTransform = versionTextObject.GetComponent(); + // versionTextRectTransform.anchorMin = Vector2.zero; + // versionTextRectTransform.anchorMax = Vector2.zero; + // versionTextRectTransform.pivot = Vector2.zero; + // versionTextRectTransform.anchoredPosition = new Vector2(5f, 5f); + // Console.Write(3); + // TextMeshProUGUI versionTextComponent = versionTextObject.GetComponent(); + // versionTextComponent.fontSize = 18f; + // versionTextComponent.alignment = TextAlignmentOptions.MidlineLeft; + // versionTextComponent.enableWordWrapping = true; + + // versionTextRectTransform.sizeDelta = new Vector2(110f, 50f); + + // versionTextObject.GetComponent().Text = $"PolyMod {Plugin.VERSION}"; + // Console.Write(4); + // GameObject originalButton = __instance.newsButton.gameObject; + // GameObject button = GameObject.Instantiate(originalButton, originalButton.transform.parent); + // button.name = "PolyModHubButton"; + + // RectTransform originalButtonRectTransform = originalButton.GetComponent(); + // button.transform.position = originalButton.transform.position - new Vector3(originalButtonRectTransform.rect.width * 1.5f, 0, 0); + + // UIRoundButton buttonComponent = button.GetComponent(); + // buttonComponent.bg.sprite = Visual.BuildSprite(Plugin.GetResource("polymod_icon.png").ReadBytes()); + // buttonComponent.bg.transform.localScale = buttonComponent.bg.transform.localScale * 1.2f; + // buttonComponent.bg.color = Color.white; + // Console.Write(5); + // GameObject.Destroy(buttonComponent.icon.gameObject); + // GameObject.Destroy(buttonComponent.outline.gameObject); + + // Transform descriptionText = button.transform.Find("DescriptionText"); + // descriptionText.gameObject.SetActive(true); + // descriptionText.GetComponentInChildren().Key = "polymod.hub"; + + // buttonComponent.OnClicked += (UIButtonBase.ButtonAction)PolyModHubButtonClicked; + // Console.Write(6); static void PolyModHubButtonClicked(int buttonId, BaseEventData eventData) { - BasicPopup popup = PopupManager.GetBasicPopup(); + WhatsNewPopup popup = PopupManager.GetWhatsNewPopup(); + popup.Header = Localization.Get("polymod.hub"); popup.Description = Localization.Get("polymod.hub.header", new Il2CppSystem.Object[] { HEADER_PREFIX, @@ -147,124 +160,34 @@ static void PolyModHubButtonClicked(int buttonId, BaseEventData eventData) HEADER_PREFIX, HEADER_POSTFIX }); + + void OpenDiscord() + { + NativeHelpers.OpenURL(Plugin.DISCORD_LINK, false); + } + List popupButtons = new() { new("buttons.back"), new( "polymod.hub.discord", - callback: (UIButtonBase.ButtonAction)((_, _) => - NativeHelpers.OpenURL(Plugin.DISCORD_LINK, false)) + callback: DelegateSupport.ConvertDelegate(OpenDiscord) ), new( "polymod.hub.config", - callback: (UIButtonBase.ButtonAction)((_, _) => - { - ShowConfigPopup(); - }) + callback: DelegateSupport.ConvertDelegate(ShowConfigPopup) ) }; if (Plugin.config.debug) { popupButtons.Add(new( "polymod.hub.dump", - callback: (UIButtonBase.ButtonAction)((_, _) => - { - Directory.CreateDirectory(Plugin.DUMPED_DATA_PATH); - Directory.CreateDirectory(Plugin.LOGIC_DUMP_PATH); - Directory.CreateDirectory(Plugin.LOCALIZATION_DUMP_PATH); - File.WriteAllTextAsync( - Path.Combine(Plugin.LOGIC_DUMP_PATH, "gameLogicData.json"), - PolytopiaDataManager.provider.LoadGameLogicData(VersionManager.GameLogicDataVersion) - ); - File.WriteAllTextAsync( - Path.Combine(Plugin.LOGIC_DUMP_PATH, "avatarData.json"), - PolytopiaDataManager.provider.LoadAvatarData(1337) - ); - var source = LocalizationManager.Sources[0]; - foreach (var language in source.GetLanguages()) - { - int languageIndex = source.GetLanguageIndex(language); - var dict = new Dictionary(); - - foreach (var term in source.mTerms) - { - var translation = term.GetTranslation(languageIndex); - - if (!string.IsNullOrEmpty(translation)) - dict[term.Term] = translation; - } - var options = new JsonSerializerOptions - { - WriteIndented = true, - Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping - }; - - string json = JsonSerializer.Serialize(dict, options); - - File.WriteAllText( - Path.Combine(Plugin.LOCALIZATION_DUMP_PATH, $"language_{source.mLanguages[languageIndex].Code}.json"), - json - ); - } - foreach (var category in source.GetCategories()) - File.WriteAllTextAsync( - Path.Combine(Plugin.LOCALIZATION_DUMP_PATH, $"localization_{category}.csv"), - source.Export_CSV(category) - ); - foreach (KeyValuePair entry in Registry.mods) - { - foreach (Mod.File file in entry.Value.files) - { - Match spritesMatch = Regex.Match(Path.GetFileName(file.name), @"^sprites(?:_(.*))?\.json$"); - if (spritesMatch.Success) - File.WriteAllBytes( - Path.Combine( - Plugin.DUMPED_DATA_PATH, - $"{Path.GetFileNameWithoutExtension(file.name)}_{entry.Key}.json" - ), - file.bytes - ); - } - } - foreach (TribeType type in Enum.GetValues(typeof(TribeType))) - { - List previewTiles = new(); - SelectTribePopup popup = PopupManager.GetSelectTribePopup(); - for (int x = -3; x <= 3; x++) - { - for (int y = -7; y <= 7; y++) - { - Vector2Int pos = new Vector2Int(x, y); - if (popup.UIWorldPreview.worldPreviewData.TryGetData(pos, type, out UITileData tileData)) - { - Visual.PreviewTile previewTile = new Visual.PreviewTile - { - x = tileData.Position.x, - y = tileData.Position.y, - terrainType = tileData.terrainType, - resourceType = tileData.resourceType, - unitType = tileData.unitType, - improvementType = tileData.improvementType - }; - previewTiles.Add(previewTile); - } - } - } - File.WriteAllTextAsync( - Path.Combine(Plugin.DUMPED_DATA_PATH, $"preview_{type}.json"), - JsonSerializer.Serialize(previewTiles, new JsonSerializerOptions { WriteIndented = true }) - ); - } - NotificationManager.Notify(Localization.Get("polymod.hub.dumped")); - }), + callback: DelegateSupport.ConvertDelegate(DumpData), closesPopup: false )); popupButtons.Add(new( "polymod.hub.spriteinfo.update", - callback: (UIButtonBase.ButtonAction)((_, _) => - { - UpdateSpriteInfos(); - }), + callback: DelegateSupport.ConvertDelegate(UpdateSpriteInfos), closesPopup: false )); } @@ -274,19 +197,22 @@ static void PolyModHubButtonClicked(int buttonId, BaseEventData eventData) if (Main.dependencyCycle) { - var popup = PopupManager.GetBasicPopup(new( - Localization.Get("polymod.cycle"), - Localization.Get("polymod.cycle.description"), - new(new PopupBase.PopupButtonData[] { - new( - "buttons.exitgame", - PopupBase.PopupButtonData.States.None, - (Il2CppSystem.Action)Application.Quit, - closesPopup: false, - customColorStates: ColorConstants.redButtonColorStates - ) - }) - )); + BasicPopup popup = PopupManager.GetBasicPopupWithData( + new( + Localization.Get("polymod.cycle"), + Localization.Get("polymod.cycle.description"), + new PopupBase.PopupButtonData[] { + new( + "buttons.exitgame", + PopupBase.PopupButtonData.States.None, + (Il2CppSystem.Action)Application.Quit, + closesPopup: false, + customColorStates: ColorConstants.redButtonColorStates + ) + } + ) + ); + popup.IsUnskippable = true; popup.Show(); } @@ -339,19 +265,112 @@ internal static void UpdateSpriteInfos() NotificationManager.Notify(message); } + /// + /// Dump all data. + /// + internal static void DumpData() + { + Directory.CreateDirectory(Plugin.DUMPED_DATA_PATH); + Directory.CreateDirectory(Plugin.LOGIC_DUMP_PATH); + Directory.CreateDirectory(Plugin.LOCALIZATION_DUMP_PATH); + File.WriteAllTextAsync( + Path.Combine(Plugin.LOGIC_DUMP_PATH, "gameLogicData.json"), + PolytopiaDataManager.provider.LoadGameLogicData(VersionManager.GameLogicDataVersion) + ); + File.WriteAllTextAsync( + Path.Combine(Plugin.LOGIC_DUMP_PATH, "avatarData.json"), + PolytopiaDataManager.provider.LoadAvatarData(1337) + ); + var source = LocalizationManager.Sources[0]; + foreach (var language in source.GetLanguages()) + { + int languageIndex = source.GetLanguageIndex(language); + var dict = new Dictionary(); + + foreach (var term in source.mTerms) + { + var translation = term.GetTranslation(languageIndex); + + if (!string.IsNullOrEmpty(translation)) + dict[term.Term] = translation; + } + var options = new JsonSerializerOptions + { + WriteIndented = true, + Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping + }; + + string json = JsonSerializer.Serialize(dict, options); + + File.WriteAllText( + Path.Combine(Plugin.LOCALIZATION_DUMP_PATH, $"language_{source.mLanguages[languageIndex].Code}.json"), + json + ); + } + foreach (var category in source.GetCategories()) + File.WriteAllTextAsync( + Path.Combine(Plugin.LOCALIZATION_DUMP_PATH, $"localization_{category}.csv"), + source.Export_CSV(category) + ); + foreach (KeyValuePair entry in Registry.mods) + { + foreach (Mod.File file in entry.Value.files) + { + Match spritesMatch = Regex.Match(Path.GetFileName(file.name), @"^sprites(?:_(.*))?\.json$"); + if (spritesMatch.Success) + File.WriteAllBytes( + Path.Combine( + Plugin.DUMPED_DATA_PATH, + $"{Path.GetFileNameWithoutExtension(file.name)}_{entry.Key}.json" + ), + file.bytes + ); + } + } + foreach (TribeType type in Enum.GetValues(typeof(TribeType))) + { + List previewTiles = new(); + SelectTribePopup popup = PopupManager.GetSelectTribePopup(); + for (int x = -3; x <= 3; x++) + { + for (int y = -7; y <= 7; y++) + { + Vector2Int pos = new Vector2Int(x, y); + if (popup.UIWorldPreview.worldPreviewData.TryGetData(pos, type, out UITileData tileData)) + { + Visual.PreviewTile previewTile = new Visual.PreviewTile + { + x = tileData.Position.x, + y = tileData.Position.y, + terrainType = tileData.terrainType, + resourceType = tileData.resourceType, + unitType = tileData.unitType, + improvementType = tileData.improvementType + }; + previewTiles.Add(previewTile); + } + } + } + File.WriteAllTextAsync( + Path.Combine(Plugin.DUMPED_DATA_PATH, $"preview_{type}.json"), + JsonSerializer.Serialize(previewTiles, new JsonSerializerOptions { WriteIndented = true }) + ); + } + NotificationManager.Notify(Localization.Get("polymod.hub.dumped")); + } + /// /// Shows the configuration popup. /// internal static void ShowConfigPopup() { - BasicPopup polymodPopup = PopupManager.GetBasicPopup(); + WhatsNewPopup polymodPopup = PopupManager.GetWhatsNewPopup(); polymodPopup.Header = Localization.Get("polymod.hub.config"); polymodPopup.Description = ""; polymodPopup.buttonData = CreateConfigPopupButtonData(); polymodPopup.ShowSetWidth(POPUP_WIDTH); - polymodPopup.Show(); } /// @@ -362,12 +381,12 @@ internal static PopupButtonData[] CreateConfigPopupButtonData() { List popupButtons = new() { - new(Localization.Get("buttons.back"), PopupButtonData.States.None, (UIButtonBase.ButtonAction)OnBackButtonClicked, -1, true, null) + new(Localization.Get("buttons.back"), PopupButtonData.States.None, DelegateSupport.ConvertDelegate(OnBackButtonClicked), -1, true, null) }; if (GameManager.Instance.isLevelLoaded) { - popupButtons.Add(new PopupButtonData(Localization.Get("polymod.hub.spriteinfo.update"), PopupButtonData.States.None, (UIButtonBase.ButtonAction)OnUpdateSpritesButtonClicked, -1, true, null)); + popupButtons.Add(new PopupButtonData(Localization.Get("polymod.hub.spriteinfo.update"), PopupButtonData.States.None, DelegateSupport.ConvertDelegate(OnUpdateSpritesButtonClicked), -1, true, null)); } else { @@ -386,13 +405,13 @@ internal static PopupButtonData[] CreateConfigPopupButtonData() new Il2CppSystem.Object[] { Localization.Get("polymod.autoupdate.alpha", new Il2CppSystem.Object[]{}).ToUpperInvariant() } ); - popupButtons.Add(new PopupButtonData(debugButtonName, PopupButtonData.States.None, (UIButtonBase.ButtonAction)OnDebugButtonClicked, -1, true, null)); - popupButtons.Add(new PopupButtonData(autoUpdateButtonName, PopupButtonData.States.None, (UIButtonBase.ButtonAction)OnAutoUpdateButtonClicked, -1, true, null)); - popupButtons.Add(new PopupButtonData(includeAlphasButtonName, Plugin.config.autoUpdate ? PopupButtonData.States.None : PopupButtonData.States.Disabled, (UIButtonBase.ButtonAction)OnIncludeAlphasButtonClicked, -1, true, null)); + popupButtons.Add(new PopupButtonData(debugButtonName, PopupButtonData.States.None, DelegateSupport.ConvertDelegate(OnDebugButtonClicked), -1, true, null)); + popupButtons.Add(new PopupButtonData(autoUpdateButtonName, PopupButtonData.States.None, DelegateSupport.ConvertDelegate(OnAutoUpdateButtonClicked), -1, true, null)); + popupButtons.Add(new PopupButtonData(includeAlphasButtonName, Plugin.config.autoUpdate ? PopupButtonData.States.None : PopupButtonData.States.Disabled, DelegateSupport.ConvertDelegate(OnIncludeAlphasButtonClicked), -1, true, null)); } return popupButtons.ToArray(); - void OnDebugButtonClicked(int buttonId, BaseEventData eventData) + void OnDebugButtonClicked() { Plugin.config = new(debug: !Plugin.config.debug, autoUpdate: Plugin.config.autoUpdate, updatePrerelease: Plugin.config.updatePrerelease); Plugin.WriteConfig(); @@ -405,7 +424,7 @@ void OnDebugButtonClicked(int buttonId, BaseEventData eventData) isConfigPopupActive = false; } - void OnAutoUpdateButtonClicked(int buttonId, BaseEventData eventData) + void OnAutoUpdateButtonClicked() { Plugin.config = new(debug: Plugin.config.debug, autoUpdate: !Plugin.config.autoUpdate, updatePrerelease: Plugin.config.updatePrerelease); Plugin.WriteConfig(); @@ -418,7 +437,7 @@ void OnAutoUpdateButtonClicked(int buttonId, BaseEventData eventData) isConfigPopupActive = false; } - void OnIncludeAlphasButtonClicked(int buttonId, BaseEventData eventData) + void OnIncludeAlphasButtonClicked() { Plugin.config = new(debug: Plugin.config.debug, autoUpdate: Plugin.config.autoUpdate, updatePrerelease: !Plugin.config.updatePrerelease); Plugin.WriteConfig(); @@ -431,13 +450,13 @@ void OnIncludeAlphasButtonClicked(int buttonId, BaseEventData eventData) isConfigPopupActive = false; } - void OnUpdateSpritesButtonClicked(int buttonId, BaseEventData eventData) + void OnUpdateSpritesButtonClicked() { UpdateSpriteInfos(); isConfigPopupActive = false; } - void OnBackButtonClicked(int buttonId, BaseEventData eventData) + void OnBackButtonClicked() { isConfigPopupActive = false; } diff --git a/src/Managers/Main.cs b/src/Managers/Main.cs index 6a728e9..6bead52 100644 --- a/src/Managers/Main.cs +++ b/src/Managers/Main.cs @@ -88,7 +88,6 @@ private static void GameLogicData_AddGameLogicPlaceholders(GameLogicData __insta /// [HarmonyPrefix] [HarmonyPatch(typeof(PurchaseManager), nameof(PurchaseManager.IsSkinUnlocked))] - [HarmonyPatch(typeof(PurchaseManager), nameof(PurchaseManager.IsSkinUnlockedInternal))] private static bool PurchaseManager_IsSkinUnlockedInternal(ref bool __result, SkinType skinType) { __result = (int)skinType >= Plugin.AUTOIDX_STARTS_FROM && skinType != SkinType.Test; diff --git a/src/Managers/Visual.cs b/src/Managers/Visual.cs index 7f0d5e2..19f3dc4 100644 --- a/src/Managers/Visual.cs +++ b/src/Managers/Visual.cs @@ -8,6 +8,8 @@ using PolyMod.Json; using System.Text.Json.Serialization; using PolytopiaBackendBase.Common; +using Il2CppInterop.Runtime; +using TMPro; namespace PolyMod.Managers; @@ -30,7 +32,7 @@ public class PreviewTile /// The terrain type of the tile. [JsonInclude] [JsonConverter(typeof(EnumCacheJson))] - public Polytopia.Data.TerrainData.Type terrainType = Polytopia.Data.TerrainData.Type.Ocean; + public Polytopia.Data.TerrainData.Type terrainType = Polytopia.Data.TerrainData.Type.None; /// The resource type on the tile. [JsonInclude] [JsonConverter(typeof(EnumCacheJson))] @@ -74,6 +76,8 @@ public UnitPrefabInfo(string type, string tribe, string skin) /// A dictionary of skin types of tribes, which can flood tiles, keyed by custom flood tile effect. /// internal static Dictionary customFloodingSkins = new(); + private static bool isTakingSnapshot = false; + private static float? baseOrthographicCameraSize = null; /// The type of a custom prefab. public enum PrefabType @@ -128,8 +132,8 @@ private static void TechItem_SetupComplete() /// Resets the firstTimeOpeningPreview flag when the start screen is shown. [HarmonyPrefix] - [HarmonyPatch(typeof(StartScreen), nameof(StartScreen.Start))] - private static void StartScreen_Start() + [HarmonyPatch(typeof(StartScreen_UI2), nameof(StartScreen_UI2.OnShow))] + private static void StartScreen_UI2_OnShow() { firstTimeOpeningPreview = true; } @@ -176,7 +180,7 @@ void GetAtlas(SpriteAtlas spriteAtlas) /// Patches the sprite atlas manager to look up custom sprites. [HarmonyPostfix] [HarmonyPatch(typeof(SpriteAtlasManager), nameof(SpriteAtlasManager.DoSpriteLookup))] - private static void SpriteAtlasManager_DoSpriteLookup(ref SpriteAtlasManager.SpriteLookupResult __result, SpriteAtlasManager __instance, string baseName, TribeType tribe, SkinType skin, bool checkForOutline, int level) + private static void SpriteAtlasManager_DoSpriteLookup(ref SpriteAtlasManager.SpriteLookupResult __result, SpriteAtlasManager __instance, string baseName, TribeType tribe, SkinType skin, int level) { baseName = Util.FormatSpriteName(baseName); @@ -463,7 +467,7 @@ private static void UIWorldPreviewData_TryGetData(ref bool __result, UIWorldPrev [HarmonyPatch(typeof(UIWorldPreview), nameof(UIWorldPreview.SetPreview), new Type[] { })] private static void UIWorldPreview_SetPreview(UIWorldPreview __instance) { - if (Plugin.config.debug && UIManager.Instance.CurrentScreen == UIConstants.Screens.TribeSelector) + if (Plugin.config.debug && UIManager.Instance.CurrentScreen == UIConstants.Screens.TribePicker) { if (firstTimeOpeningPreview) { @@ -480,6 +484,117 @@ private static void UIWorldPreview_SetPreview(UIWorldPreview __instance) } } + + [HarmonyPostfix] + [HarmonyPatch(typeof(TribePreviewRegistry), nameof(TribePreviewRegistry.GetTribePreviewData))] + private static void TribePreviewRegistry_GetTribePreviewData(ref SaveStateData __result, TribeType tribeType, SkinType skinType) + { + string tribeName = EnumCache.GetName(tribeType).ToLower(); + if (!Registry.tribePreviews.ContainsKey(tribeName)) + return; + + PreviewTile[]? preview = Registry.tribePreviews[tribeName]; + if (preview == null) + return; + + ClientSerializationWrapper result = new ClientSerializationWrapper(null); + int version; + bool num = DiskSerializationHelpers.FromLZ4CompressedByteArray(__result.byteArray, out result, out version); + if (num) + { + GameState currentGameState = result.GetCurrentGameState(); + foreach (var previewTile in preview) + { + if(previewTile.x == null || previewTile.y == null) + continue; + + WorldCoordinates coordinates = new((int)previewTile.x, (int)previewTile.y); + TileData? tileData = currentGameState.Map.GetTile(coordinates); + if(tileData == null) + continue; + + if(previewTile.terrainType != Polytopia.Data.TerrainData.Type.None) + tileData.terrain = previewTile.terrainType; + + if(previewTile.resourceType != Polytopia.Data.ResourceData.Type.None) + tileData.resource = new ResourceState { type = previewTile.resourceType }; + + if(previewTile.unitType != Polytopia.Data.UnitData.Type.None && + currentGameState.TryGetPlayer(currentGameState.CurrentPlayer, out PlayerState playerState) && + currentGameState.GameLogicData.TryGetData(previewTile.unitType, out UnitData unitData)) + { + ActionUtils.TrainUnit(currentGameState, playerState, tileData, unitData); + } + + if(previewTile.improvementType != Polytopia.Data.ImprovementData.Type.None && + currentGameState.GameLogicData.TryGetData(previewTile.improvementType, out var improvementData)) + { + tileData.improvement = new ImprovementState + { + type = previewTile.improvementType, + borderSize = (ushort)improvementData.borderSize, + level = 0, + xp = 0, + production = 1, + founded = (ushort)currentGameState.CurrentTurn, + baseScore = (ushort)improvementData.GetScoreReward(), + founder = currentGameState.CurrentPlayer + }; + } + } + __result.byteArray = DiskSerializationHelpers.ToLZ4CompressedByteArray(result, version); + } + } + + [HarmonyPrefix] + [HarmonyPatch(typeof(SpriteCamera), nameof(SpriteCamera.TakeSnapshotOfMapState))] + private static bool SpriteCamera_TakeSnapshotOfMapState(ref Texture2D __result, SpriteCamera.SnapshotMapData mapSnapshot, + float w, float h, TribeType tribe, SkinType skin, TribeType climate, int color, bool clearMapAfterwards) + { + if(!Plugin.config.debug) + return true; + + var instance = SpriteCamera.instance; + if(baseOrthographicCameraSize == null) + baseOrthographicCameraSize = instance.spriteCamera.orthographicSize; + + instance.spriteCamera.orthographicSize = (float)baseOrthographicCameraSize * 2; + isTakingSnapshot = true; + + return true; + } + + [HarmonyPostfix] + [HarmonyPatch(typeof(SpriteCamera), nameof(SpriteCamera.TakeSnapshotOfMapState))] + private static void SpriteCamera_TakeSnapshotOfMapState_Postfix(ref Texture2D __result, SpriteCamera.SnapshotMapData mapSnapshot, + float w, float h, TribeType tribe, SkinType skin, TribeType climate, int color, bool clearMapAfterwards) + { + if(isTakingSnapshot) + isTakingSnapshot = false; + } + + [HarmonyPostfix] + [HarmonyPatch(typeof(Tile), nameof(Tile.RenderDebug))] + public static void Tile_RenderDebug(Tile __instance) + { + if(!isTakingSnapshot) + return; + + GameObject textObj = new GameObject("CoordinateText"); + textObj.transform.SetParent(__instance.transform); + textObj.transform.localPosition = new Vector3(0, 0.0f, 0); + + TextMeshPro textMesh = textObj.AddComponent(); + textMesh.text = __instance.Data.coordinates.ToString(); + textMesh.fontSize = 3; + textMesh.alignment = TextAlignmentOptions.Center; + textMesh.color = Color.white; + + MeshRenderer renderer = textObj.GetComponent(); + renderer.sortingLayerID = MeshCache.TERRAIN_LAYER_ID; + renderer.sortingOrder = __instance.Depth + 10; + } + #endregion #region UI @@ -646,8 +761,21 @@ private static void PlayerInfoIcon_SetData(PlayerInfoIcon __instance, TribeType /// Updates the width of a basic popup if a custom width is set. [HarmonyPostfix] - [HarmonyPatch(typeof(BasicPopup), nameof(BasicPopup.Update))] - private static void BasicPopup_Update(BasicPopup __instance) + [HarmonyPatch(typeof(PopupBase), nameof(PopupBase.RefreshHeight))] + private static void BasicPopup_RefreshHeight(ref Il2CppSystem.Collections.IEnumerator __result, PopupBase __instance, Il2CppSystem.Action OnComplete) + { + UpdateWidth(__instance); + } + + [HarmonyPrefix] + [HarmonyPatch(typeof(PopupBase), nameof(PopupBase.OnShowComplete))] + private static bool BasicPopup_ShowInternal(PopupBase __instance) + { + UpdateWidth(__instance); + return true; + } + + private static void UpdateWidth(PopupBase __instance) { int id = __instance.GetInstanceID(); if (basicPopupWidths.ContainsKey(id)) @@ -691,25 +819,28 @@ private static void PopupBase_Hide(PopupBase __instance) } [HarmonyPrefix] - [HarmonyPatch(typeof(StartScreen), nameof(StartScreen.OnWeeklyChallengedButtonClick))] - private static bool StartScreen_OnWeeklyChallengedButtonClick(StartScreen __instance) + [HarmonyPatch(typeof(StartScreen_UI2), nameof(StartScreen_UI2.OnWeeklyChallengeClicked))] + private static bool StartScreen_OnWeeklyChallengeClicked(StartScreen_UI2 __instance) { if(seenWarningWCPopup) return true; + BasicPopup popup = PopupManager.GetBasicPopup(); popup.Header = Localization.Get("polymod.hub"); popup.Description = Localization.Get("polymod.wc.warning", new Il2CppSystem.Object[] { Localization.Get("weeklychallenge", new Il2CppSystem.Object[] { }) }); + + void WCProceed() + { + seenWarningWCPopup = true; + __instance.OnWeeklyChallengeClicked(); + } List popupButtons = new() { new("buttons.back"), new( "polymod.wc.proceed", PopupBase.PopupButtonData.States.None, - callback: (UIButtonBase.ButtonAction)((_, _) => - { - seenWarningWCPopup = true; - __instance.OnWeeklyChallengedButtonClick(); - }), + callback: DelegateSupport.ConvertDelegate(WCProceed), customColorStates: ColorConstants.redButtonColorStates ) }; @@ -719,12 +850,30 @@ private static bool StartScreen_OnWeeklyChallengedButtonClick(StartScreen __inst } /// Shows a basic popup with a custom width. - public static void ShowSetWidth(this BasicPopup self, int width) + public static void ShowSetWidth(this BasicPopupLegacy self, int width) { basicPopupWidths.Add(self.GetInstanceID(), width); self.Show(); } + // [HarmonyPrefix] + // [HarmonyPatch(typeof(BasicPopup), nameof(BasicPopup.SetButtonData))] + // public static bool SetButtonData(BasicPopup __instance, PopupBase.PopupButtonData[] buttonDatas, bool updateOmniCursor) + // { + // if (buttonDatas == null) + // { + // __instance.SetDefaultOkbutton(); + // return false; + // } + // foreach (var buttonData in buttonDatas) + // { + // var MainButton = __instance.createButton(buttonData.text, buttonData.callback, UIButtonBase_UI2.ButtonStyle.Suggested); + // MainButton.OnClickedSignal.Add(DelegateSupport.ConvertDelegate(__instance.Hide)); + // } + // __instance.RunLayout(); + // return false; + // } + #endregion /// Updates a visual part with a custom sprite.