diff --git a/src/Brush.cs b/src/Brush.cs index 3aafca9..65d624a 100644 --- a/src/Brush.cs +++ b/src/Brush.cs @@ -1,6 +1,7 @@ using HarmonyLib; using Polytopia.Data; using PolytopiaBackendBase.Common; +using PolytopiaMapManager.UI; using PolytopiaMapManager.UI.Picker; using UnityEngine; @@ -8,12 +9,6 @@ namespace PolytopiaMapManager; public static class Brush { - internal static int chosenClimate = 0; - internal static SkinType chosenSkinType = SkinType.Default; - internal static Polytopia.Data.TerrainData.Type chosenTerrain = Polytopia.Data.TerrainData.Type.None; - internal static Polytopia.Data.ResourceData.Type chosenResource = Polytopia.Data.ResourceData.Type.None; - internal static TileData.EffectType chosenTileEffect = TileData.EffectType.None; - internal static ImprovementData.Type chosenBuilding = ImprovementData.Type.None; private static float nextAllowedTimeForPopup = 0f; [HarmonyPostfix] @@ -24,106 +19,155 @@ private static void Tile_OnHoverStart(Tile __instance) return; GameState gameState = GameManager.GameState; - byte localPlayer = GameManager.LocalPlayer.Id; - if(chosenTerrain != Polytopia.Data.TerrainData.Type.None) - __instance.data.terrain = chosenTerrain; + HandleTerrain(__instance.data, (Polytopia.Data.TerrainData.Type)Editor.terrainPicker.chosenValue); + HandleResource(gameState, __instance.data, (ResourceData.Type)Editor.resourcePicker.chosenValue); + HandleTileEffect(__instance.data, (TileData.EffectType)Editor.tileEffectPicker.chosenValue); + HandleImprovement(gameState, __instance.data, (ImprovementData.Type)Editor.improvementPicker.chosenValue); + HandleBiome(__instance.data, Editor.biomePicker.chosenValue, Editor.biomePicker.chosenSkinType); - if(chosenResource != ResourceData.Type.None) + __instance.Render(); + } + + internal static void HandleTerrain(TileData tileData, Polytopia.Data.TerrainData.Type terrain) + { + if(terrain != Polytopia.Data.TerrainData.Type.None) + tileData.terrain = terrain; + } + + internal static void HandleResource(GameState gameState, TileData tileData, ResourceData.Type resource) + { + if(resource == ResourceData.Type.None) + return; + + if(resource == (ResourceData.Type)PickerBase.DESTROY_OPTION_ID) { - if(chosenResource == (ResourceData.Type)PickerBase.DESTROY_OPTION_ID) - { - __instance.data.resource = null; - ActionUtils.CheckSurroundingArea(gameState, localPlayer, __instance.data); - } - else if(gameState.GameLogicData.TryGetData(chosenResource, out ResourceData data)) - { - if(data.resourceTerrainRequirements.Contains(__instance.data.terrain)) - { - __instance.data.resource = new ResourceState + tileData.resource = null; + return; + } + + if(!gameState.GameLogicData.TryGetData(resource, out ResourceData data) && Time.time >= nextAllowedTimeForPopup) + { + NotificationManager.Notify(Localization.Get("mapmaker.failed.retrieve", new Il2CppSystem.Object[] { tileData.resource})); + nextAllowedTimeForPopup = Time.time + 1f; + return; + } + + if(!data.resourceTerrainRequirements.Contains(tileData.terrain) && Time.time >= nextAllowedTimeForPopup) + { + NotificationManager.Notify( + Localization.Get( + "mapmaker.failed.creation", + new Il2CppSystem.Object[] { - type = chosenResource - }; - ActionUtils.CheckSurroundingArea(gameState, localPlayer, __instance.data); - } - else if(Time.time >= nextAllowedTimeForPopup) - { - NotificationManager.Notify(Localization.Get("mapmaker.failed.creation", new Il2CppSystem.Object[] { Localization.Get(data.displayName, new Il2CppSystem.Object[] {} ),Localization.Get(__instance.data.terrain.GetDisplayName(), new Il2CppSystem.Object[] {} )})); - nextAllowedTimeForPopup = Time.time + 1f; - } + Localization.Get(data.displayName, new Il2CppSystem.Object[] {} ), + Localization.Get(tileData.terrain.GetDisplayName(), new Il2CppSystem.Object[] {} ) + } + ) + ); + nextAllowedTimeForPopup = Time.time + 1f; + return; + } + + tileData.resource = new ResourceState + { + type = resource + }; + } + + internal static void HandleTileEffect(TileData tileData, TileData.EffectType effectType) + { + if(effectType == TileData.EffectType.None) + return; + + tileData.effects.Clear(); + + if(effectType == TileData.EffectType.Flooded) + { + if(tileData.isFloodable()) + { + tileData.AddEffect(effectType); + if(Editor.biomePicker.chosenSkinType == SkinType.Swamp) + tileData.AddEffect(TileData.EffectType.Swamped); } else if(Time.time >= nextAllowedTimeForPopup) { - NotificationManager.Notify(Localization.Get("mapmaker.failed.retrieve", new Il2CppSystem.Object[] { __instance.data.resource})); + NotificationManager.Notify( + Localization.Get( + "mapmaker.failed.creation", + new Il2CppSystem.Object[] + { + Localization.Get($"tile.effect.{EnumCache.GetName(effectType)}"), + Localization.Get(tileData.terrain.GetDisplayName(), new Il2CppSystem.Object[] {} ) + } + ) + ); nextAllowedTimeForPopup = Time.time + 1f; } } - if(chosenTileEffect != TileData.EffectType.None) + else if(effectType == TileData.EffectType.Algae) { - __instance.data.effects.Clear(); - if(!__instance.data.HasEffect(chosenTileEffect)) + if(tileData.IsWater) { - if(chosenTileEffect == TileData.EffectType.Flooded) - { - if(__instance.data.isFloodable()) - { - __instance.data.AddEffect(chosenTileEffect); - if(chosenSkinType == SkinType.Swamp) - __instance.data.AddEffect(TileData.EffectType.Swamped); - } - else if(Time.time >= nextAllowedTimeForPopup) - { - NotificationManager.Notify(Localization.Get("mapmaker.failed.creation", new Il2CppSystem.Object[] { Localization.Get($"tile.effect.{EnumCache.GetName(chosenTileEffect)}"), Localization.Get(__instance.data.terrain.GetDisplayName(), new Il2CppSystem.Object[] {} )})); - nextAllowedTimeForPopup = Time.time + 1f; - } - } - else if(chosenTileEffect == TileData.EffectType.Algae) - { - if(__instance.data.IsWater) - { - __instance.data.AddEffect(chosenTileEffect); - if(chosenSkinType == SkinType.Cute) - __instance.data.AddEffect(TileData.EffectType.Foam); - } - else if(Time.time >= nextAllowedTimeForPopup) - { - NotificationManager.Notify(Localization.Get("mapmaker.failed.creation", new Il2CppSystem.Object[] { Localization.Get($"tile.effect.{EnumCache.GetName(chosenTileEffect)}"), Localization.Get(__instance.data.terrain.GetDisplayName(), new Il2CppSystem.Object[] {} )})); - nextAllowedTimeForPopup = Time.time + 1f; - } - } + tileData.AddEffect(effectType); + if(Editor.biomePicker.chosenSkinType == SkinType.Cute) + tileData.AddEffect(TileData.EffectType.Foam); } - } - if(chosenBuilding != ImprovementData.Type.None && !__instance.data.HasImprovement(ImprovementData.Type.LightHouse)) - { - if(chosenBuilding == (ImprovementData.Type)PickerBase.DESTROY_OPTION_ID) - { - __instance.data.improvement = null; - Data.Capital? capital = Loader.GetCapital(__instance.data.coordinates, Main.currCapitals); - - if(capital != null) - Main.currCapitals.Remove(capital); - } - else if (gameState.GameLogicData.TryGetData(chosenBuilding, out ImprovementData improvementData)) + else if(Time.time >= nextAllowedTimeForPopup) { - ImprovementState improvementState = new ImprovementState - { - type = chosenBuilding, - borderSize = (ushort)improvementData.borderSize, - level = 0, - xp = 0, - production = 1, - founded = 0, - baseScore = 0, - founder = localPlayer - }; - __instance.data.improvement = improvementState; + NotificationManager.Notify( + Localization.Get( + "mapmaker.failed.creation", + new Il2CppSystem.Object[] + { + Localization.Get($"tile.effect.{EnumCache.GetName(effectType)}"), + Localization.Get(tileData.terrain.GetDisplayName(), new Il2CppSystem.Object[] {} ) + } + ) + ); + nextAllowedTimeForPopup = Time.time + 1f; } } - if(chosenClimate != 0) + } + + internal static void HandleImprovement(GameState gameState, TileData tileData, ImprovementData.Type improvement) + { + if(improvement == ImprovementData.Type.None || tileData.HasImprovement(ImprovementData.Type.LightHouse)) + return; + + if(improvement == (ImprovementData.Type)PickerBase.DESTROY_OPTION_ID) { - __instance.data.climate = chosenClimate; - __instance.data.Skin = chosenSkinType; + tileData.improvement = null; + Data.Capital? capital = Loader.GetCapital(tileData.coordinates, Main.currCapitals); + + if(capital != null) + Main.currCapitals.Remove(capital); + return; } - __instance.Render(); + + if (!gameState.GameLogicData.TryGetData(improvement, out ImprovementData improvementData)) + return; + + ImprovementState improvementState = new ImprovementState + { + type = improvement, + borderSize = (ushort)improvementData.borderSize, + level = 0, + xp = 0, + production = 1, + founded = 0, + baseScore = 0, + founder = gameState.CurrentPlayer + }; + tileData.improvement = improvementState; + } + + internal static void HandleBiome(TileData tileData, int climate, SkinType skinType) + { + if(Editor.biomePicker.chosenValue == 0) + return; + + tileData.climate = climate; + tileData.Skin = skinType; } } \ No newline at end of file diff --git a/src/IO.cs b/src/IO.cs index e776309..784ea47 100644 --- a/src/IO.cs +++ b/src/IO.cs @@ -147,8 +147,13 @@ public static bool SaveMap(string name, ushort size, List tiles, List< return mapInfo; } - internal static string[] GetAllMaps() + internal static List GetAllMaps() { - return Directory.GetFiles(MAPS_PATH, "*.json"); + List names = new(); + foreach (var rawName in Directory.GetFiles(MAPS_PATH, "*.json")) + { + names.Add(Path.GetFileNameWithoutExtension(rawName)); + } + return names; } } \ No newline at end of file diff --git a/src/UI/Menu/GameSetup.cs b/src/UI/Menu/GameSetup.cs index 4bf5dca..ded82b7 100644 --- a/src/UI/Menu/GameSetup.cs +++ b/src/UI/Menu/GameSetup.cs @@ -143,15 +143,8 @@ private static void GameSetupScreen_CreateGameModeList(GameSetupScreen __instanc { types.Add(value.ToString()); } - string[] maps = IO.GetAllMaps(); - visualMaps = new(); - int num = 1; - if (maps.Length > 0) - { - visualMaps = maps.Select(map => Path.GetFileNameWithoutExtension(map)).ToList(); - num++; - } - __instance.CreateHorizontalList("gamesettings.generationtype", types.ToArray(), new Action(OnMapGenTypeChanged), 0, null, maps.Length + 1, (Il2CppSystem.Action)OnTriedSelectDisabledMapGenType); + visualMaps = IO.GetAllMaps(); + __instance.CreateHorizontalList("gamesettings.generationtype", types.ToArray(), new Action(OnMapGenTypeChanged), 0, null, visualMaps.Count + 1, (Il2CppSystem.Action)OnTriedSelectDisabledMapGenType); } } diff --git a/src/UI/Picker/BiomePicker.cs b/src/UI/Picker/BiomePicker.cs index 469ac84..ad8b2e2 100644 --- a/src/UI/Picker/BiomePicker.cs +++ b/src/UI/Picker/BiomePicker.cs @@ -5,6 +5,7 @@ namespace PolytopiaMapManager.UI.Picker; internal class BiomePicker : PickerBase { + internal SkinType chosenSkinType = SkinType.Default; internal override string HeaderKey => "mapmaker.choose.climate"; internal static List excludedTribes = new() { @@ -24,20 +25,20 @@ internal override void Update(GameLogicData gameLogicData) if(button == null) return; - if(Brush.chosenClimate != 0) + if(chosenValue != 0) { - TribeType tribeType = gameLogicData.GetTribeTypeFromStyle(Brush.chosenClimate); + TribeType tribeType = gameLogicData.GetTribeTypeFromStyle(chosenValue); string spriteName; - if (Brush.chosenSkinType == SkinType.Default) + if (chosenSkinType == SkinType.Default) { spriteName = EnumCache.GetName(tribeType); } else { - spriteName = EnumCache.GetName(Brush.chosenSkinType); + spriteName = EnumCache.GetName(chosenSkinType); } button.iconSpriteHandle.Request(SpriteData.GetHeadSpriteAddress(spriteName)); - button.BG.color = ColorUtil.SetAlphaOnColor(ColorUtil.ColorFromInt(gameLogicData.GetTribeColor(tribeType, Brush.chosenSkinType)), 1f); + button.BG.color = ColorUtil.SetAlphaOnColor(ColorUtil.ColorFromInt(gameLogicData.GetTribeColor(tribeType, chosenSkinType)), 1f); } else { @@ -57,20 +58,20 @@ void OnClick(int id) { id *= -1; SkinType skinType = (SkinType)id; - Brush.chosenClimate = Loader.GetTribeClimateFromSkin(skinType, gameState.GameLogicData); - Brush.chosenSkinType = skinType; + chosenValue = Loader.GetTribeClimateFromSkin(skinType, gameState.GameLogicData); + chosenSkinType = skinType; } else { if((TribeType)id != TribeType.None) { - Brush.chosenClimate = Loader.GetTribeClimateFromType((TribeType)id, gameState.GameLogicData); + chosenValue = Loader.GetTribeClimateFromType((TribeType)id, gameState.GameLogicData); } else { - Brush.chosenClimate = 0; + chosenValue = 0; } - Brush.chosenSkinType = SkinType.Default; + chosenSkinType = SkinType.Default; } this.Update(gameState.GameLogicData); Editor.resourcePicker.Update(gameState.GameLogicData); diff --git a/src/UI/Picker/ImprovementPicker.cs b/src/UI/Picker/ImprovementPicker.cs index a8782de..13b843e 100644 --- a/src/UI/Picker/ImprovementPicker.cs +++ b/src/UI/Picker/ImprovementPicker.cs @@ -15,7 +15,7 @@ internal class ImprovementPicker : PickerBase internal override Sprite GetIcon(GameLogicData gameLogicData) { - return base.GetSprite((int)Brush.chosenBuilding, SpriteData.ImprovementToString(Brush.chosenBuilding), gameLogicData); + return base.GetSprite(chosenValue, SpriteData.ImprovementToString((ImprovementData.Type)chosenValue), gameLogicData); } internal override void CreatePopupButtons(ref float num, SelectViewmodePopup selectViewmodePopup, GameState gameState) @@ -35,7 +35,7 @@ internal override void CreatePopupButtons(ref float num, SelectViewmodePopup sel void OnClick(int id) { - Brush.chosenBuilding = (ImprovementData.Type)id; + chosenValue = id; Update(gameState.GameLogicData); } diff --git a/src/UI/Picker/MapPicker.cs b/src/UI/Picker/MapPicker.cs index f64199d..fda5cad 100644 --- a/src/UI/Picker/MapPicker.cs +++ b/src/UI/Picker/MapPicker.cs @@ -6,6 +6,7 @@ internal class MapPicker : PickerBase { internal override string HeaderKey => "mapmaker.choose.map"; internal override Vector3? Indent => new Vector3(0, -110, 0); + private Dictionary cachedMaps = new(); internal override Sprite GetIcon() { @@ -14,28 +15,39 @@ internal override Sprite GetIcon() internal override void CreatePopupButtons(ref float num, SelectViewmodePopup selectViewmodePopup, GameState gameState) { - string[] maps = IO.GetAllMaps(); - List visualMaps = new(); - if (maps.Length > 0) + List maps = IO.GetAllMaps(); + if(maps.Count > cachedMaps.Count) { - visualMaps = maps.Select(map => Path.GetFileNameWithoutExtension(map)).ToList(); - num++; + foreach (string mapName in maps) + { + if(!cachedMaps.ContainsKey(mapName)) + CacheMap(mapName); + } } - for (int index = 0; index < visualMaps.Count(); index++) + else if(maps.Count < cachedMaps.Count) { - string name = visualMaps[index]; - + foreach (var map in cachedMaps) + { + if(!maps.Contains(map.Key)) + cachedMaps.Remove(map.Key); + } + } + for (int index = 0; index < cachedMaps.Count; index++) + { + string name = cachedMaps.Keys.ToArray()[index]; base.CreateChoiceButton(selectViewmodePopup, name, index, ref num, OnClick, ColorUtil.SetAlphaOnColor(Color.black, 0.6f), SetMapIcon); void OnClick(int id) { - string mapName = visualMaps[id]; - Loader.chosenMap = IO.LoadMap(mapName); - if(Loader.chosenMap == null) + string name = cachedMaps.Keys.ToArray()[id]; + MapInfo? mapInfo = IO.LoadMap(name); + + if(mapInfo == null) return; - Main.MapName = mapName; + Loader.chosenMap = mapInfo; + Main.MapName = name; Loader.LoadMapInState(ref gameState, Loader.chosenMap); Main.currCapitals = Loader.chosenMap.capitals; GameManager.Client.UpdateGameState(gameState, PolytopiaBackendBase.Game.StateUpdateReason.Unknown); @@ -44,24 +56,36 @@ void OnClick(int id) void SetMapIcon(UIRoundButton button, int type) { - MapInfo? mapInfo = IO.LoadMap(name); - if(mapInfo == null) - return; + string name = cachedMaps.Keys.ToArray()[type]; + + base.SetIcon(button, cachedMaps[name]); + } + } + } + + private void CacheMap(string mapName) + { + MapInfo? mapInfo = IO.LoadMap(mapName); + if(mapInfo == null) + return; - Sprite icon = GetIcon(); - if(mapInfo.icon.Count > 0) - { - Texture2D texture = new Texture2D(2, 2, TextureFormat.RGB24, false); - texture.LoadImage(mapInfo.icon.ToArray()); - icon = Sprite.Create( - texture, - new(0, 0, texture.width, texture.height), - new(0.5f, 0.5f), - 2112f - ); - } - base.SetIcon(button, icon); + Sprite icon = GetIcon(); + if(mapInfo.icon.Count > 0) + { + Texture2D texture = new Texture2D(2, 2, TextureFormat.RGB24, false); + texture.LoadImage(mapInfo.icon.ToArray()); + icon = Sprite.Create( + texture, + new(0, 0, texture.width, texture.height), + new(0.5f, 0.5f), + 2112f + ); + if(!Editor.spriteAtlasManager.cachedSprites["Heads"].ContainsKey(mapName)) + { + Editor.spriteAtlasManager.cachedSprites.TryAdd("Heads", new()); + Editor.spriteAtlasManager.cachedSprites["Heads"].Add(mapName, icon); } } + cachedMaps[mapName] = icon; } } \ No newline at end of file diff --git a/src/UI/Picker/PickerBase.cs b/src/UI/Picker/PickerBase.cs index bfb3912..3b38b40 100644 --- a/src/UI/Picker/PickerBase.cs +++ b/src/UI/Picker/PickerBase.cs @@ -16,6 +16,7 @@ internal class PickerBase internal virtual string HeaderKey => ""; internal virtual Vector3? Indent => null; internal virtual Vector2 ChoiceButtonSize => new Vector2(56f, 56f); + internal int chosenValue = 0; internal virtual void Create(UIRoundButton referenceButton, Transform parent) { @@ -54,11 +55,11 @@ public Sprite GetSprite(int type, string spriteName, GameLogicData gameLogicData if(type != 0) { TribeType tribeType = TribeType.Xinxi; - if(Brush.chosenClimate != 0) + if(Editor.biomePicker.chosenValue != 0) { - tribeType = gameLogicData.GetTribeTypeFromStyle(Brush.chosenClimate); + tribeType = gameLogicData.GetTribeTypeFromStyle(Editor.biomePicker.chosenValue); } - SpriteAtlasManager.SpriteLookupResult lookupResult = Editor.spriteAtlasManager.DoSpriteLookup(spriteName, tribeType, Brush.chosenSkinType, false); + SpriteAtlasManager.SpriteLookupResult lookupResult = Editor.spriteAtlasManager.DoSpriteLookup(spriteName, tribeType, Editor.biomePicker.chosenSkinType, false); sprite = lookupResult.sprite; } if(sprite == null) diff --git a/src/UI/Picker/ResourcePicker.cs b/src/UI/Picker/ResourcePicker.cs index 29b5c8e..99360c3 100644 --- a/src/UI/Picker/ResourcePicker.cs +++ b/src/UI/Picker/ResourcePicker.cs @@ -13,7 +13,7 @@ internal class ResourcePicker : PickerBase internal override Sprite GetIcon(GameLogicData gameLogicData) { - return base.GetSprite((int)Brush.chosenResource, SpriteData.ResourceToString(Brush.chosenResource), gameLogicData); + return base.GetSprite(chosenValue, SpriteData.ResourceToString((ResourceData.Type)chosenValue), gameLogicData); } internal override void CreatePopupButtons(ref float num, SelectViewmodePopup selectViewmodePopup, GameState gameState) @@ -33,7 +33,7 @@ internal override void CreatePopupButtons(ref float num, SelectViewmodePopup sel void OnClick(int id) { - Brush.chosenResource = (ResourceData.Type)id; + chosenValue = id; Update(gameState.GameLogicData!); } diff --git a/src/UI/Picker/TerrainPicker.cs b/src/UI/Picker/TerrainPicker.cs index 040ed9c..b5f4e8b 100644 --- a/src/UI/Picker/TerrainPicker.cs +++ b/src/UI/Picker/TerrainPicker.cs @@ -14,7 +14,7 @@ internal class TerrainPicker : PickerBase internal override Sprite GetIcon(GameLogicData gameLogicData) { - return base.GetSprite((int)Brush.chosenTerrain, SpriteData.TerrainToString(Brush.chosenTerrain), gameLogicData); + return base.GetSprite(chosenValue, SpriteData.TerrainToString((Polytopia.Data.TerrainData.Type)chosenValue), gameLogicData); } internal override void CreatePopupButtons(ref float num, SelectViewmodePopup selectViewmodePopup, GameState gameState) @@ -30,7 +30,7 @@ internal override void CreatePopupButtons(ref float num, SelectViewmodePopup sel void OnClick(int id) { - Brush.chosenTerrain = (Polytopia.Data.TerrainData.Type)id; + chosenValue = id; Update(gameState.GameLogicData); } diff --git a/src/UI/Picker/TileEffectPicker.cs b/src/UI/Picker/TileEffectPicker.cs index 5ea3eb2..c9f9b33 100644 --- a/src/UI/Picker/TileEffectPicker.cs +++ b/src/UI/Picker/TileEffectPicker.cs @@ -15,7 +15,7 @@ internal class TileEffectPicker : PickerBase internal override Sprite GetIcon(GameLogicData gameLogicData) { - return base.GetSprite((int)Brush.chosenTileEffect, TileEffectToString(Brush.chosenTileEffect), gameLogicData); + return base.GetSprite(chosenValue, TileEffectToString(chosenValue), gameLogicData); } internal override void CreatePopupButtons(ref float num, SelectViewmodePopup selectViewmodePopup, GameState gameState) @@ -36,19 +36,20 @@ internal override void CreatePopupButtons(ref float num, SelectViewmodePopup sel void OnClick(int id) { - Brush.chosenTileEffect = (TileData.EffectType)id; + chosenValue = id; Update(gameState.GameLogicData); } void SetTileEffectIcon(UIRoundButton button, int type) { - base.SetIcon(button, base.GetSprite(type, TileEffectToString((TileData.EffectType)type), gameState.GameLogicData), 0.6f); + base.SetIcon(button, base.GetSprite(type, TileEffectToString(type), gameState.GameLogicData), 0.6f); } } } - internal static string TileEffectToString(TileData.EffectType tileEffect) + internal static string TileEffectToString(int effectIdx) { + TileData.EffectType tileEffect = (TileData.EffectType)effectIdx; if(tileEffect == TileData.EffectType.Flooded) { return SpriteData.TILE_WETLAND;