diff --git a/src/Json/EnumCacheJson.cs b/src/Json/EnumCacheJson.cs
index 0aae58d..3a177d4 100644
--- a/src/Json/EnumCacheJson.cs
+++ b/src/Json/EnumCacheJson.cs
@@ -7,7 +7,7 @@ namespace PolyMod.Json;
/// Converts an to and from a JSON string using the .
///
/// The type of the enum.
-internal class EnumCacheJson : JsonConverter where T : struct, Enum
+public class EnumCacheJson : JsonConverter where T : struct, Enum
{
///
/// Reads and converts the JSON to an enum value.
diff --git a/src/Json/JsonMerger.cs b/src/Json/JsonMerger.cs
new file mode 100644
index 0000000..3db0e7c
--- /dev/null
+++ b/src/Json/JsonMerger.cs
@@ -0,0 +1,124 @@
+using Il2CppSystem.IO;
+using Newtonsoft.Json.Linq;
+
+namespace PolyMod.Json;
+
+///
+/// Provides functionality to merge JSON objects, with special handling for arrays.
+///
+public static class JsonMerger
+{
+ ///
+ /// Merges a patch JObject into an original JObject.
+ ///
+ /// The original JObject.
+ /// The patch JObject to merge.
+ /// The merged JObject.
+ public static JObject Merge(JObject original, JObject patch)
+ {
+ foreach (var property in patch.Properties().ToArray().ToList())
+ {
+ if (property == null || property.Name == null)
+ continue;
+
+ string propName = property.Name;
+ JToken? originalValue = original[propName];
+ JToken patchValue = property.Value;
+
+ if (originalValue == null)
+ {
+ original[propName] = patchValue;
+ continue;
+ }
+
+ JObject? originalObj = originalValue.TryCast();
+ JObject? patchObj = patchValue.TryCast();
+ if (originalObj != null && patchObj != null)
+ {
+ Merge(originalObj, patchObj);
+ continue;
+ }
+
+ JArray? originalArr = originalValue.TryCast();
+ JArray? patchArr = patchValue.TryCast();
+ if (originalArr != null && patchArr != null)
+ {
+ bool isSkins = propName.Equals("skins", StringComparison.OrdinalIgnoreCase);
+ JArray merged = MergeArrays(originalArr, patchArr, isSkins);
+ original[propName] = merged;
+ continue;
+ }
+ original[propName] = patchValue;
+ }
+
+ return original;
+ }
+
+ ///
+ /// Merges two JArrays, with special handling for adding and removing elements.
+ ///
+ /// The original JArray.
+ /// The patch JArray to merge.
+ /// A flag to indicate if the array is a 'skins' array, which has special merging logic.
+ /// The merged JArray.
+ private static JArray MergeArrays(JArray original, JArray patch, bool isSkins)
+ {
+ var result = new JArray(original);
+ var patchList = patch._values.ToArray().ToList();
+
+ bool hasDirectValues = patchList.Any(v =>
+ v.Type == JTokenType.String &&
+ !v.ToString().StartsWith("+") &&
+ !v.ToString().StartsWith("-"));
+
+ if (!isSkins && hasDirectValues)
+ {
+ result = new JArray();
+ }
+
+ foreach (var token in patchList)
+ {
+ if (token.Type != JTokenType.String)
+ {
+ result.Add(token);
+ continue;
+ }
+
+ string str = token.ToString();
+
+ if (str.StartsWith("+"))
+ {
+ string value = str.Substring(1);
+ if (!result._values.ToArray().Any(t => t.Type == JTokenType.String && t.ToString() == value))
+ {
+ result.Add(value);
+ }
+ }
+ else if (str.StartsWith("-"))
+ {
+ string value = str.Substring(1);
+ var toRemove = result._values.ToArray()
+ .Where(t => t.Type == JTokenType.String && t.ToString() == value)
+ .ToList();
+ foreach (var rem in toRemove)
+ result.Remove(rem);
+ }
+ else
+ {
+ if (isSkins)
+ {
+ if (!result._values.ToArray().Any(t => t.Type == JTokenType.String && t.ToString() == str))
+ {
+ result.Add(str);
+ }
+ }
+ else
+ {
+ result.Add(str);
+ }
+ }
+ }
+
+ return result;
+ }
+}
diff --git a/src/Json/Vector2Json.cs b/src/Json/Vector2Json.cs
index 4764952..1957c4d 100644
--- a/src/Json/Vector2Json.cs
+++ b/src/Json/Vector2Json.cs
@@ -7,7 +7,7 @@ namespace PolyMod.Json;
///
/// Converts a to and from a JSON array of two numbers.
///
-internal class Vector2Json : JsonConverter
+public class Vector2Json : JsonConverter
{
///
/// Reads and converts the JSON to a .
diff --git a/src/Json/VersionJson.cs b/src/Json/VersionJson.cs
index 54bb0a1..21c6c81 100644
--- a/src/Json/VersionJson.cs
+++ b/src/Json/VersionJson.cs
@@ -6,7 +6,7 @@ namespace PolyMod.Json;
///
/// Converts a to and from a JSON string.
///
-internal class VersionJson : JsonConverter
+public class VersionJson : JsonConverter
{
///
/// Reads and converts the JSON to a .
diff --git a/src/Loader.cs b/src/Loader.cs
index de33248..dc3cd61 100644
--- a/src/Loader.cs
+++ b/src/Loader.cs
@@ -23,23 +23,26 @@ namespace PolyMod;
///
public static class Loader
{
+ internal record TypeMapping(Type type, bool shouldCreateCache = true);
+
///
/// Mappings from JSON data types to their corresponding C# types.
///
- internal static Dictionary typeMappings = new()
+ internal static Dictionary typeMappings = new()
{
- { "tribeData", typeof(TribeData.Type) },
- { "techData", typeof(TechData.Type) },
- { "unitData", typeof(UnitData.Type) },
- { "improvementData", typeof(ImprovementData.Type) },
- { "terrainData", typeof(Polytopia.Data.TerrainData.Type) },
- { "resourceData", typeof(ResourceData.Type) },
- { "taskData", typeof(TaskData.Type) },
- { "tribeAbility", typeof(TribeAbility.Type) },
- { "unitAbility", typeof(UnitAbility.Type) },
- { "improvementAbility", typeof(ImprovementAbility.Type) },
- { "playerAbility", typeof(PlayerAbility.Type) },
- { "weaponData", typeof(UnitData.WeaponEnum) }
+ { "tribeData", new TypeMapping(typeof(TribeData.Type)) },
+ { "techData", new TypeMapping(typeof(TechData.Type)) },
+ { "unitData", new TypeMapping(typeof(UnitData.Type)) },
+ { "improvementData", new TypeMapping(typeof(ImprovementData.Type)) },
+ { "terrainData", new TypeMapping(typeof(Polytopia.Data.TerrainData.Type)) },
+ { "resourceData", new TypeMapping(typeof(ResourceData.Type)) },
+ { "taskData", new TypeMapping(typeof(TaskData.Type)) },
+ { "tribeAbility", new TypeMapping(typeof(TribeAbility.Type)) },
+ { "unitAbility", new TypeMapping(typeof(UnitAbility.Type)) },
+ { "improvementAbility", new TypeMapping(typeof(ImprovementAbility.Type)) },
+ { "playerAbility", new TypeMapping(typeof(PlayerAbility.Type)) },
+ { "weaponData", new TypeMapping(typeof(UnitData.WeaponEnum)) },
+ { "skinData", new TypeMapping(typeof(SkinData), false) }
};
///
@@ -50,7 +53,7 @@ public static class Loader
///
/// Handlers for processing specific data types during mod loading.
///
- private static readonly Dictionary> typeHandlers = new()
+ internal static readonly Dictionary> typeHandlers = new()
{
[typeof(TribeData.Type)] = new((token, duringEnumCacheCreation) =>
{
@@ -63,6 +66,38 @@ public static class Loader
}
else
{
+ if (token["skins"] != null)
+ {
+ JArray skins = token["skins"].Cast();
+ List skinValues = skins._values.ToArray().ToList();
+ foreach (var skin in skinValues)
+ {
+ string skinValue = skin.ToString();
+ if (!Enum.TryParse(CultureInfo.CurrentCulture.TextInfo.ToTitleCase(skinValue), out _))
+ {
+ EnumCache.AddMapping(skinValue.ToLowerInvariant(), (SkinType)Registry.autoidx);
+ EnumCache.AddMapping(skinValue.ToLowerInvariant(), (SkinType)Registry.autoidx);
+ Registry.skinInfo.Add(new Visual.SkinInfo(Registry.autoidx, skinValue, null));
+ Plugin.logger.LogInfo("Created mapping for skinType with id " + skinValue + " and index " + Registry.autoidx);
+ Registry.autoidx++;
+ }
+ }
+ Il2CppSystem.Collections.Generic.List modifiedSkins = skins._values;
+ foreach (var skin in Registry.skinInfo)
+ {
+ if (modifiedSkins.Contains(skin.id))
+ {
+ modifiedSkins.Remove(skin.id);
+ modifiedSkins.Add(skin.idx.ToString());
+ }
+ }
+ JArray newSkins = new JArray();
+ foreach (var item in modifiedSkins)
+ {
+ newSkins.Add(item);
+ }
+ token["skins"] = newSkins;
+ }
if (token["preview"] != null)
{
Visual.PreviewTile[] preview = JsonSerializer.Deserialize(token["preview"].ToString())!;
@@ -142,7 +177,13 @@ public static class Loader
}
PrefabManager.resources.TryAdd((ResourceData.Type)Registry.autoidx, PrefabManager.resources[resourcePrefabType]);
}
- })
+ }),
+
+ [typeof(SkinData)] = new((token, duringEnumCacheCreation) =>
+ {
+ var prop = token.Parent.Cast();
+ prop.Replace(new JProperty(prop.Name.ToLower(), prop.Value));
+ }),
};
///
@@ -176,7 +217,13 @@ public static void AddGameModeButton(string id, UIButtonBase.ButtonAction action
public static void AddPatchDataType(string typeId, Type type)
{
if (!typeMappings.ContainsKey(typeId))
- typeMappings.Add(typeId, type);
+ typeMappings.Add(typeId, new TypeMapping(type));
+ }
+
+ public static void AddPatchDataType(string typeId, Type type, bool shouldCreateCache)
+ {
+ if (!typeMappings.ContainsKey(typeId))
+ typeMappings.Add(typeId, new TypeMapping(type, shouldCreateCache));
}
///
@@ -428,7 +475,7 @@ public static void LoadLocalizationFile(Mod mod, Mod.File file)
}
catch (Exception e)
{
- Plugin.logger.LogError($"Error on loading locatization from {mod.id} mod: {e.Message}");
+ Plugin.logger.LogError($"Error on loading locatization from {mod.id} mod: {e.StackTrace}");
}
}
@@ -509,7 +556,7 @@ public static void UpdateSprite(string name)
}
catch (Exception e)
{
- Plugin.logger.LogError($"Error on loading sprite data from {mod.id} mod: {e.Message}");
+ Plugin.logger.LogError($"Error on loading sprite data from {mod.id} mod: {e.StackTrace}");
return null;
}
}
@@ -568,7 +615,7 @@ public static void LoadPrefabInfoFile(Mod mod, Mod.File file)
}
catch (Exception e)
{
- Plugin.logger.LogError($"Error on loading prefab info from {mod.id} mod: {e.Message}");
+ Plugin.logger.LogError($"Error on loading prefab info from {mod.id} mod: {e.StackTrace}");
}
}
@@ -675,60 +722,13 @@ public static void LoadGameLogicDataPatch(Mod mod, JObject gld, JObject patch)
{
try
{
- HandleSkins(gld, patch);
- // First pass: add new enum values and create mappings
- foreach (JToken jtoken in patch.SelectTokens("$.*.*").ToArray())
- {
- JObject? token = jtoken.TryCast();
- if (token != null)
- {
- string dataType = Util.GetJTokenName(token, 2);
- if (typeMappings.TryGetValue(dataType, out Type? targetType))
- {
- if (token["idx"] != null && (int)token["idx"] == -1)
- {
- string id = Util.GetJTokenName(token);
- token["idx"] = Registry.autoidx;
- MethodInfo? methodInfo = typeof(EnumCache<>).MakeGenericType(targetType).GetMethod("AddMapping");
- if (methodInfo != null)
- {
- methodInfo.Invoke(null, new object[] { id, Registry.autoidx });
- methodInfo.Invoke(null, new object[] { id, Registry.autoidx });
-
- if (typeHandlers.TryGetValue(targetType, out var handler))
- {
- handler(token, true);
- }
- Plugin.logger.LogInfo("Created mapping for " + targetType.ToString() + " with id " + id + " and index " + Registry.autoidx);
- Registry.autoidx++;
- }
- }
- }
- }
- }
- // Second pass: apply special handling
- foreach (JToken jtoken in patch.SelectTokens("$.*.*").ToArray())
- {
- JObject? token = jtoken.TryCast();
- if (token != null)
- {
- string dataType = Util.GetJTokenName(token, 2);
- if (typeMappings.TryGetValue(dataType, out Type? targetType))
- {
- if (typeHandlers.TryGetValue(targetType, out var handler))
- {
- handler(token, false);
- }
- }
- }
- }
- // Final pass: merge the patch into the game logic data
- gld.Merge(patch, new() { MergeArrayHandling = MergeArrayHandling.Replace, MergeNullValueHandling = MergeNullValueHandling.Merge });
+ // Merge the patch into the game logic data
+ gld = JsonMerger.Merge(gld, patch);
Plugin.logger.LogInfo($"Registered patch from {mod.id} mod");
}
catch (Exception e)
{
- Plugin.logger.LogError($"Error on loading patch from {mod.id} mod: {e.Message}");
+ Plugin.logger.LogError($"Error on loading patch from {mod.id} mod: {e.StackTrace}");
mod.status = Mod.Status.Error;
}
}
@@ -747,76 +747,160 @@ public static void LoadAssetBundle(Mod mod, Mod.File file)
}
///
- /// Handles skin data from a patch.
+ /// Processes the merged game logic data after all mods have been loaded and patched.
///
- /// The original game logic data.
- /// The patch to apply.
- public static void HandleSkins(JObject gld, JObject patch)
+ /// The game logic data object to populate.
+ /// The root JObject of the merged game logic data.
+ internal static void ProcessGameLogicData(GameLogicData gameLogicData, JObject rootObject)
{
- foreach (JToken jtoken in patch.SelectTokens("$.tribeData.*").ToArray())
+ try
{
- JObject token = jtoken.Cast();
+ CreateMappings(rootObject);
+ ProcessPrefabs();
+ ProcessEmbarkOverrides();
+ ProcessAttractOverrides();
+ }
+ catch (Exception e)
+ {
+ Plugin.logger.LogError($"Error on processing modified game logic data : {e.StackTrace}");
+ }
+ }
- if (token["skins"] != null)
+ ///
+ /// Creates EnumCache mappings for custom enum values and invokes type handlers.
+ ///
+ ///
+ internal static void CreateMappings(JObject rootObject)
+ {
+ foreach (JToken jtoken in rootObject.SelectTokens("$.*.*").ToArray())
+ {
+ JObject? token = jtoken.TryCast();
+ if (token != null)
{
- JArray skins = token["skins"].Cast();
- List skinsToRemove = new();
- List skinValues = skins._values.ToArray().ToList();
- foreach (var skin in skinValues)
+ string dataType = Util.GetJTokenName(token, 2);
+ if (Loader.typeMappings.TryGetValue(dataType, out Loader.TypeMapping? typeMapping))
{
- string skinValue = skin.ToString();
- if (skinValue.StartsWith('-') && Enum.TryParse(skinValue.Substring(1), out _))
+ if (token["idx"] != null && (int)token["idx"] == -1 && typeMapping.shouldCreateCache)
{
- skinsToRemove.Add(skinValue.Substring(1));
- }
- else if (!Enum.TryParse(skinValue, out _))
- {
- EnumCache.AddMapping(skinValue.ToLowerInvariant(), (SkinType)Registry.autoidx);
- EnumCache.AddMapping(skinValue.ToLowerInvariant(), (SkinType)Registry.autoidx);
- Registry.skinInfo.Add(new Visual.SkinInfo(Registry.autoidx, skinValue, null));
- Plugin.logger.LogInfo("Created mapping for skinType with id " + skinValue + " and index " + Registry.autoidx);
- Registry.autoidx++;
- }
- }
- foreach (var skin in Registry.skinInfo)
- {
- if (skins._values.Contains(skin.id))
- {
- skins._values.Remove(skin.id);
- skins._values.Add(skin.idx);
+ Type targetType = typeMapping.type;
+ string id = Util.GetJTokenName(token);
+ token["idx"] = Registry.autoidx;
+ MethodInfo? methodInfo = typeof(EnumCache<>).MakeGenericType(targetType).GetMethod("AddMapping");
+ if (methodInfo != null)
+ {
+ methodInfo.Invoke(null, new object[] { id, Registry.autoidx });
+ methodInfo.Invoke(null, new object[] { id, Registry.autoidx });
+
+ if (Loader.typeHandlers.TryGetValue(targetType, out var handler))
+ {
+ handler(token, true);
+ }
+ Plugin.logger.LogInfo("Created mapping for " + targetType.ToString() + " with id " + id + " and index " + Registry.autoidx);
+ Registry.autoidx++;
+ }
}
}
- JToken originalSkins = gld.SelectToken(skins.Path, false);
- if (originalSkins != null)
+ }
+ }
+ foreach (JToken jtoken in rootObject.SelectTokens("$.*.*").ToArray())
+ {
+ JObject? token = jtoken.TryCast();
+ if (token != null)
+ {
+ string dataType = Util.GetJTokenName(token, 2);
+ if (Loader.typeMappings.TryGetValue(dataType, out Loader.TypeMapping? typeMapping))
{
- skins.Merge(originalSkins);
- foreach (var skin in skinsToRemove)
+ if (Loader.typeHandlers.TryGetValue(typeMapping.type, out var handler))
{
- skins._values.Remove(skin);
- skins._values.Remove("-" + skin);
+ handler(token, false);
}
}
}
}
- foreach (JToken jtoken in patch.SelectTokens("$.skinData.*").ToArray())
+ }
+
+ ///
+ /// Processes the prefab registry and populates the PrefabManager with custom prefabs.
+ ///
+ internal static void ProcessPrefabs()
+ {
+ foreach (System.Collections.Generic.KeyValuePair item in Registry.prefabNames)
{
- JObject token = jtoken.Cast();
- string id = Util.GetJTokenName(token);
- int index = Registry.skinInfo.FindIndex(t => t.id == id);
- if (Registry.skinInfo.ElementAtOrDefault(index) != null)
+ UnitData.Type unitPrefabType = UnitData.Type.Scout;
+ string prefabId = item.Value;
+ if (Enum.TryParse(prefabId, out UnitData.Type parsedType))
{
- SkinData skinData = new();
- if (token["color"] != null)
+ unitPrefabType = parsedType;
+ PrefabManager.units.TryAdd(item.Key, PrefabManager.units[(int)unitPrefabType]);
+ }
+ else
+ {
+ KeyValuePair prefabInfo = Registry.unitPrefabs.FirstOrDefault(kv => kv.Key.name == prefabId);
+ if (!EqualityComparer.Default.Equals(prefabInfo.Key, default))
{
- skinData.color = (int)token["color"];
+ PrefabManager.units.TryAdd(item.Key, prefabInfo.Value);
}
- if (token["language"] != null)
+ else
{
- skinData.language = token["language"].ToString();
+ PrefabManager.units.TryAdd(item.Key, PrefabManager.units[(int)unitPrefabType]);
}
- Registry.skinInfo[index] = new Visual.SkinInfo(Registry.skinInfo[index].idx, Registry.skinInfo[index].id, skinData);
}
}
- patch.Remove("skinData");
+ }
+
+ ///
+ /// Processes embark overrides by mapping original embark unit types to configured overrides.
+ ///
+ internal static void ProcessEmbarkOverrides()
+ {
+ foreach (KeyValuePair entry in Main.embarkNames)
+ {
+ try
+ {
+ UnitData.Type unit = EnumCache.GetType(entry.Key);
+ UnitData.Type newUnit = EnumCache.GetType(entry.Value);
+ Main.embarkOverrides[unit] = newUnit;
+ Plugin.logger.LogInfo($"Embark unit type for {entry.Key} is now {entry.Value}");
+ }
+ catch
+ {
+ Plugin.logger.LogError($"Embark unit type for {entry.Key} is not valid: {entry.Value}");
+ }
+ }
+ }
+
+ ///
+ /// Processes attract overrides by mapping improvements to resources and terrain types based on configured overrides.
+ ///
+ internal static void ProcessAttractOverrides()
+ {
+ foreach (KeyValuePair entry in Main.attractsResourceNames)
+ {
+ try
+ {
+ ImprovementData.Type improvement = EnumCache.GetType(entry.Key);
+ ResourceData.Type resource = EnumCache.GetType(entry.Value);
+ Main.attractsResourceOverrides[improvement] = resource;
+ Plugin.logger.LogInfo($"Improvement {entry.Key} now attracts {entry.Value}");
+ }
+ catch
+ {
+ Plugin.logger.LogError($"Improvement {entry.Key} resource type is not valid: {entry.Value}");
+ }
+ }
+ foreach (KeyValuePair entry in Main.attractsTerrainNames)
+ {
+ try
+ {
+ ImprovementData.Type improvement = EnumCache.GetType(entry.Key);
+ Polytopia.Data.TerrainData.Type terrain = EnumCache.GetType(entry.Value);
+ Main.attractsTerrainOverrides[improvement] = terrain;
+ Plugin.logger.LogInfo($"Improvement {entry.Key} now attracts on {entry.Value}");
+ }
+ catch
+ {
+ Plugin.logger.LogError($"Improvement {entry.Key} terrain type is not valid: {entry.Value}");
+ }
+ }
}
}
diff --git a/src/Managers/Loc.cs b/src/Managers/Loc.cs
index 37d7767..cf6c5d3 100644
--- a/src/Managers/Loc.cs
+++ b/src/Managers/Loc.cs
@@ -63,9 +63,9 @@ private static bool Localization_Get(ref string key, Il2CppReferenceArray).MakeGenericType(targetType).GetMethod("TryGetName");
+ MethodInfo? methodInfo = typeof(EnumCache<>).MakeGenericType(typeMapping.type).GetMethod("TryGetName");
if (methodInfo != null)
{
object?[] parameters = { idx, null };
diff --git a/src/Managers/Main.cs b/src/Managers/Main.cs
index acc8c5e..b9e19f4 100644
--- a/src/Managers/Main.cs
+++ b/src/Managers/Main.cs
@@ -1,8 +1,10 @@
using BepInEx.Unity.IL2CPP.Logging;
using HarmonyLib;
+using Il2CppSystem.Linq;
using Newtonsoft.Json.Linq;
using Polytopia.Data;
using PolytopiaBackendBase.Game;
+using System.Reflection;
using System.Diagnostics;
using System.Text;
using System.Text.Json;
@@ -76,80 +78,11 @@ public static class Main
///
[HarmonyPrefix]
[HarmonyPatch(typeof(GameLogicData), nameof(GameLogicData.AddGameLogicPlaceholders))]
- private static void GameLogicData_Parse(GameLogicData __instance, JObject rootObject)
+ private static void GameLogicData_AddGameLogicPlaceholders(GameLogicData __instance, ref JObject rootObject)
{
if (!fullyInitialized)
{
- Load(rootObject);
- foreach (System.Collections.Generic.KeyValuePair item in Registry.prefabNames)
- {
- UnitData.Type unitPrefabType = UnitData.Type.Scout;
- string prefabId = item.Value;
- if (Enum.TryParse(prefabId, out UnitData.Type parsedType))
- {
- unitPrefabType = parsedType;
- PrefabManager.units.TryAdd(item.Key, PrefabManager.units[(int)unitPrefabType]);
- }
- else
- {
- KeyValuePair prefabInfo = Registry.unitPrefabs.FirstOrDefault(kv => kv.Key.name == prefabId);
- if (!EqualityComparer.Default.Equals(prefabInfo.Key, default))
- {
- PrefabManager.units.TryAdd(item.Key, prefabInfo.Value);
- }
- else
- {
- PrefabManager.units.TryAdd(item.Key, PrefabManager.units[(int)unitPrefabType]);
- }
- }
- }
- foreach (Visual.SkinInfo skin in Registry.skinInfo)
- {
- if (skin.skinData != null)
- __instance.skinData[(SkinType)skin.idx] = skin.skinData;
- }
- foreach (KeyValuePair entry in embarkNames)
- {
- try
- {
- UnitData.Type unit = EnumCache.GetType(entry.Key);
- UnitData.Type newUnit = EnumCache.GetType(entry.Value);
- embarkOverrides[unit] = newUnit;
- Plugin.logger.LogInfo($"Embark unit type for {entry.Key} is now {entry.Value}");
- }
- catch
- {
- Plugin.logger.LogError($"Embark unit type for {entry.Key} is not valid: {entry.Value}");
- }
- }
- foreach (KeyValuePair entry in attractsResourceNames)
- {
- try
- {
- ImprovementData.Type improvement = EnumCache.GetType(entry.Key);
- ResourceData.Type resource = EnumCache.GetType(entry.Value);
- attractsResourceOverrides[improvement] = resource;
- Plugin.logger.LogInfo($"Improvement {entry.Key} now attracts {entry.Value}");
- }
- catch
- {
- Plugin.logger.LogError($"Improvement {entry.Key} resource type is not valid: {entry.Value}");
- }
- }
- foreach (KeyValuePair entry in attractsTerrainNames)
- {
- try
- {
- ImprovementData.Type improvement = EnumCache.GetType(entry.Key);
- Polytopia.Data.TerrainData.Type terrain = EnumCache.GetType(entry.Value);
- attractsTerrainOverrides[improvement] = terrain;
- Plugin.logger.LogInfo($"Improvement {entry.Key} now attracts on {entry.Value}");
- }
- catch
- {
- Plugin.logger.LogError($"Improvement {entry.Key} terrain type is not valid: {entry.Value}");
- }
- }
+ Load(__instance, rootObject);
fullyInitialized = true;
}
}
@@ -452,7 +385,8 @@ internal static void Init()
/// Loads all mod content.
///
/// The game logic data to patch.
- internal static void Load(JObject gameLogicdata)
+ /// The JSON object representing the game logic data.
+ internal static void Load(GameLogicData gameLogicData, JObject json)
{
stopwatch.Start();
Loc.BuildAndLoadLocalization(
@@ -476,7 +410,7 @@ internal static void Load(JObject gameLogicdata)
{
Loader.LoadGameLogicDataPatch(
mod,
- gameLogicdata,
+ json,
JObject.Parse(new StreamReader(new MemoryStream(file.bytes)).ReadToEnd())
);
continue;
@@ -509,6 +443,7 @@ internal static void Load(JObject gameLogicdata)
{
TechItem.techTierFirebaseId.Add($"tech_research_{i}");
}
+ Loader.ProcessGameLogicData(gameLogicData, json);
stopwatch.Stop();
Plugin.logger.LogInfo($"Loaded all mods in {stopwatch.ElapsedMilliseconds}ms");
}
diff --git a/src/Managers/Visual.cs b/src/Managers/Visual.cs
index f2ae379..acd12ba 100644
--- a/src/Managers/Visual.cs
+++ b/src/Managers/Visual.cs
@@ -643,12 +643,16 @@ private static void UpdateVisualPart(SkinVisualsReference.VisualPart visualPart,
{
if (visualPart.outlineRenderer.spriteRenderer != null)
visualPart.outlineRenderer.spriteRenderer.sprite = outlineSprite;
- else if (visualpart.outlineRenderer.polytopiaSpriteRenderer != null)
+ else if (visualPart.outlineRenderer.polytopiaSpriteRenderer != null)
visualPart.outlineRenderer.polytopiaSpriteRenderer.sprite = outlineSprite;
}
}
/// Builds a sprite from raw byte data.
+ /// The raw byte data of the image.
+ /// The pivot point of the sprite.
+ /// The number of pixels per unit for the sprite.
+ /// The created sprite.
public static Sprite BuildSprite(byte[] data, Vector2? pivot = null, float pixelsPerUnit = 2112f)
{
Texture2D texture = new(1, 1, TextureFormat.RGBA32, true);
@@ -665,6 +669,10 @@ public static Sprite BuildSprite(byte[] data, Vector2? pivot = null, float pixel
}
/// Builds a sprite from a texture.
+ /// The texture to create the sprite from.
+ /// The pivot point of the sprite.
+ /// The number of pixels per unit for the sprite.
+ /// The created sprite.
public static Sprite BuildSpriteWithTexture(Texture2D texture, Vector2? pivot = null, float? pixelsPerUnit = 2112f)
{
return Sprite.Create(