Skip to content

Commit 27c1e11

Browse files
authored
TypeHandler public api and Prefabs fix (#137)
* Attempted fix of prefab * Added a way to add custom type handler * removed unnecessary logw arning, changed to log info
1 parent a1c77f5 commit 27c1e11

2 files changed

Lines changed: 116 additions & 85 deletions

File tree

PolyMod.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
</RestoreAdditionalProjectSources>
1212
<Configurations>IL2CPP</Configurations>
1313
<RootNamespace>PolyMod</RootNamespace>
14-
<Version>1.2.10-pre</Version>
14+
<Version>1.2.10-pre.1</Version>
1515
<PolytopiaVersion>2.16.3.15581</PolytopiaVersion>
1616
<Authors>PolyModdingTeam</Authors>
1717
<Description>The Battle of Polytopia's mod loader.</Description>

src/Loader.cs

Lines changed: 115 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -54,85 +54,89 @@ internal record TypeMapping(Type type, bool shouldCreateCache = true);
5454
/// <summary>
5555
/// Handlers for processing specific data types during mod loading.
5656
/// </summary>
57-
internal static readonly Dictionary<Type, Action<JObject, bool>> typeHandlers = new()
57+
internal static readonly Dictionary<Type, List<Action<JObject, bool>>> typeHandlers = new()
5858
{
59-
[typeof(TribeType)] = new((token, duringEnumCacheCreation) =>
60-
{
61-
if (duringEnumCacheCreation)
59+
[typeof(TribeType)] = new List<Action<JObject, bool>>() {
60+
new((token, duringEnumCacheCreation) =>
6261
{
63-
Registry.customTribes.Add((TribeType)Registry.autoidx);
64-
token["style"] = Registry.climateAutoidx;
65-
token["climate"] = Registry.climateAutoidx;
66-
Registry.climateAutoidx++;
67-
}
68-
else
69-
{
70-
if (token["skins"] != null)
62+
if (duringEnumCacheCreation)
63+
{
64+
Registry.customTribes.Add((TribeType)Registry.autoidx);
65+
token["style"] = Registry.climateAutoidx;
66+
token["climate"] = Registry.climateAutoidx;
67+
Registry.climateAutoidx++;
68+
}
69+
else
7170
{
72-
JArray skins = token["skins"].Cast<JArray>();
73-
List<JToken> skinValues = skins._values.ToArray().ToList();
74-
foreach (var skin in skinValues)
71+
if (token["skins"] != null)
7572
{
76-
string skinValue = skin.ToString();
77-
if (!Enum.TryParse<SkinType>(skinValue, ignoreCase: true, out _))
73+
JArray skins = token["skins"].Cast<JArray>();
74+
List<JToken> skinValues = skins._values.ToArray().ToList();
75+
foreach (var skin in skinValues)
7876
{
79-
EnumCache<SkinType>.AddMapping(skinValue.ToLowerInvariant(), (SkinType)Registry.autoidx);
80-
EnumCache<SkinType>.AddMapping(skinValue.ToLowerInvariant(), (SkinType)Registry.autoidx);
81-
Registry.skinInfo.Add(new Visual.SkinInfo(Registry.autoidx, skinValue, null));
82-
Plugin.logger.LogInfo("Created mapping for skinType with id " + skinValue + " and index " + Registry.autoidx);
83-
Registry.autoidx++;
77+
string skinValue = skin.ToString();
78+
if (!Enum.TryParse<SkinType>(skinValue, ignoreCase: true, out _))
79+
{
80+
EnumCache<SkinType>.AddMapping(skinValue.ToLowerInvariant(), (SkinType)Registry.autoidx);
81+
EnumCache<SkinType>.AddMapping(skinValue.ToLowerInvariant(), (SkinType)Registry.autoidx);
82+
Registry.skinInfo.Add(new Visual.SkinInfo(Registry.autoidx, skinValue, null));
83+
Plugin.logger.LogInfo("Created mapping for skinType with id " + skinValue + " and index " + Registry.autoidx);
84+
Registry.autoidx++;
85+
}
8486
}
85-
}
86-
Il2CppSystem.Collections.Generic.List<JToken> modifiedSkins = skins._values;
87-
foreach (var skin in Registry.skinInfo)
88-
{
89-
if (modifiedSkins.Contains(skin.id))
87+
Il2CppSystem.Collections.Generic.List<JToken> modifiedSkins = skins._values;
88+
foreach (var skin in Registry.skinInfo)
9089
{
91-
modifiedSkins.Remove(skin.id);
92-
modifiedSkins.Add(skin.idx.ToString());
90+
if (modifiedSkins.Contains(skin.id))
91+
{
92+
modifiedSkins.Remove(skin.id);
93+
modifiedSkins.Add(skin.idx.ToString());
94+
}
9395
}
96+
JArray newSkins = new JArray();
97+
foreach (var item in modifiedSkins)
98+
{
99+
newSkins.Add(item);
100+
}
101+
token["skins"] = newSkins;
94102
}
95-
JArray newSkins = new JArray();
96-
foreach (var item in modifiedSkins)
103+
if (token["preview"] != null)
97104
{
98-
newSkins.Add(item);
105+
Visual.PreviewTile[] preview = JsonSerializer.Deserialize<Visual.PreviewTile[]>(token["preview"].ToString())!;
106+
Registry.tribePreviews[Util.GetJTokenName(token)] = preview;
99107
}
100-
token["skins"] = newSkins;
101-
}
102-
if (token["preview"] != null)
103-
{
104-
Visual.PreviewTile[] preview = JsonSerializer.Deserialize<Visual.PreviewTile[]>(token["preview"].ToString())!;
105-
Registry.tribePreviews[Util.GetJTokenName(token)] = preview;
106108
}
107-
}
108-
}),
109-
110-
[typeof(UnitData.Type)] = new((token, duringEnumCacheCreation) =>
111-
{
112-
if (!duringEnumCacheCreation)
109+
})
110+
},
111+
[typeof(UnitData.Type)] = new List<Action<JObject, bool>>() {
112+
new((token, duringEnumCacheCreation) =>
113113
{
114-
if (token["prefab"] != null)
115-
{
116-
Registry.prefabNames.Add((int)(UnitData.Type)(int)token["idx"], token["prefab"]!.ToString());
117-
}
118-
if (token["embarksTo"] != null)
114+
if (!duringEnumCacheCreation)
119115
{
120-
string unitId = Util.GetJTokenName(token);
121-
string embarkUnitId = token["embarksTo"].ToString();
122-
Main.embarkNames[unitId] = embarkUnitId;
123-
}
124-
if (token["weapon"] != null)
125-
{
126-
string weaponString = token["weapon"].ToString();
127-
if (EnumCache<UnitData.WeaponEnum>.TryGetType(weaponString, out UnitData.WeaponEnum type))
116+
if (token["prefab"] != null)
128117
{
129-
token["weapon"] = (int)type;
118+
Registry.prefabNames.Add((int)(UnitData.Type)(int)token["idx"], token["prefab"]!.ToString());
119+
}
120+
if (token["embarksTo"] != null)
121+
{
122+
string unitId = Util.GetJTokenName(token);
123+
string embarkUnitId = token["embarksTo"].ToString();
124+
Main.embarkNames[unitId] = embarkUnitId;
125+
}
126+
if (token["weapon"] != null)
127+
{
128+
string weaponString = token["weapon"].ToString();
129+
if (EnumCache<UnitData.WeaponEnum>.TryGetType(weaponString, out UnitData.WeaponEnum type))
130+
{
131+
token["weapon"] = (int)type;
132+
}
130133
}
131134
}
132-
}
133-
}),
135+
})
136+
},
134137

135-
[typeof(ImprovementData.Type)] = new((token, duringEnumCacheCreation) =>
138+
[typeof(ImprovementData.Type)] = new List<Action<JObject, bool>>() {
139+
new((token, duringEnumCacheCreation) =>
136140
{
137141
if (duringEnumCacheCreation)
138142
{
@@ -161,29 +165,34 @@ internal record TypeMapping(Type type, bool shouldCreateCache = true);
161165
Main.attractsTerrainNames[improvementId] = attractsId;
162166
}
163167
}
164-
}),
168+
})
169+
},
165170

166-
[typeof(ResourceData.Type)] = new((token, duringEnumCacheCreation) =>
167-
{
168-
if (duringEnumCacheCreation)
171+
[typeof(ResourceData.Type)] = new List<Action<JObject, bool>>() {
172+
new((token, duringEnumCacheCreation) =>
169173
{
170-
ResourceData.Type resourcePrefabType = ResourceData.Type.Game;
171-
if (token["prefab"] != null)
174+
if (duringEnumCacheCreation)
172175
{
173-
string prefabId = CultureInfo.CurrentCulture.TextInfo.ToTitleCase(token["prefab"]!.ToString());
174-
if (Enum.TryParse(prefabId, out ResourceData.Type parsedType))
175-
resourcePrefabType = parsedType;
176+
ResourceData.Type resourcePrefabType = ResourceData.Type.Game;
177+
if (token["prefab"] != null)
178+
{
179+
string prefabId = CultureInfo.CurrentCulture.TextInfo.ToTitleCase(token["prefab"]!.ToString());
180+
if (Enum.TryParse(prefabId, out ResourceData.Type parsedType))
181+
resourcePrefabType = parsedType;
182+
}
183+
if(token["idx"] != null)
184+
PrefabManager.resources.TryAdd((ResourceData.Type)(int)token["idx"], PrefabManager.resources[resourcePrefabType]);
176185
}
177-
if(token["idx"] != null)
178-
PrefabManager.resources.TryAdd((ResourceData.Type)(int)token["idx"], PrefabManager.resources[resourcePrefabType]);
179-
}
180-
}),
186+
})
187+
},
181188

182-
[typeof(SkinData)] = new((token, duringEnumCacheCreation) =>
183-
{
184-
var prop = token.Parent.Cast<JProperty>();
185-
prop.Replace(new JProperty(prop.Name.ToLower(), prop.Value));
186-
}),
189+
[typeof(SkinData)] = new List<Action<JObject, bool>>() {
190+
new((token, duringEnumCacheCreation) =>
191+
{
192+
var prop = token.Parent.Cast<JProperty>();
193+
prop.Replace(new JProperty(prop.Name.ToLower(), prop.Value));
194+
})
195+
},
187196
};
188197

189198
/// <summary>
@@ -217,7 +226,7 @@ public static void AddGameMode(string id, UIButtonBase.ButtonAction action, bool
217226
/// Adds a new data type for patching.
218227
/// </summary>
219228
/// <param name="typeId">The identifier for the data type in JSON.</param>
220-
/// <param name="type">The C# type corresponding to the identifier.</param>
229+
/// <param name="type">"The C# type corresponding to the identifier.</param>
221230
public static void AddPatchDataType(string typeId, Type type)
222231
{
223232
if (!typeMappings.ContainsKey(typeId))
@@ -230,6 +239,22 @@ public static void AddPatchDataType(string typeId, Type type, bool shouldCreateC
230239
typeMappings.Add(typeId, new TypeMapping(type, shouldCreateCache));
231240
}
232241

242+
public static void AddTypeHandler(Type type, Action<JObject, bool> handler)
243+
{
244+
string typeString = type.ToString();
245+
if(!typeMappings.ContainsValue(new TypeMapping(type, true)) && !typeMappings.ContainsValue(new TypeMapping(type, false)))
246+
{
247+
Plugin.logger.LogWarning($"Tried adding TypeHandler for type: {typeString} with missing TypeMapping. Please, add TypeMapping first.");
248+
return;
249+
}
250+
if(!typeHandlers.ContainsKey(type))
251+
typeHandlers[type] = new();
252+
253+
typeHandlers[type].Add(handler);
254+
255+
Plugin.logger.LogInfo($"Added TypeHandler for type: {typeString}.");
256+
}
257+
233258
/// <summary>
234259
/// Loads all mods from the mods directory.
235260
/// </summary>
@@ -889,9 +914,12 @@ internal static void CreateMappings(JObject rootObject)
889914
methodInfo.Invoke(null, new object[] { id, (int)token["idx"] });
890915
methodInfo.Invoke(null, new object[] { id, (int)token["idx"] });
891916

892-
if (typeHandlers.TryGetValue(targetType, out var handler))
917+
if (typeHandlers.TryGetValue(targetType, out var handlers))
893918
{
894-
handler(token, true);
919+
foreach(var handler in handlers)
920+
{
921+
handler(token, true);
922+
}
895923
}
896924
Plugin.logger.LogInfo("Created mapping for " + targetType.ToString() + " with id " + id + " and index " + (int)token["idx"]);
897925
}
@@ -903,9 +931,12 @@ internal static void CreateMappings(JObject rootObject)
903931
string dataType = Util.GetJTokenName(token, 2);
904932
if (typeMappings.TryGetValue(dataType, out TypeMapping? typeMapping))
905933
{
906-
if (typeHandlers.TryGetValue(typeMapping.type, out var handler))
934+
if (typeHandlers.TryGetValue(typeMapping.type, out var handlers))
907935
{
908-
handler(token, false);
936+
foreach(var handler in handlers)
937+
{
938+
handler(token, false);
939+
}
909940
}
910941
}
911942
}

0 commit comments

Comments
 (0)