Skip to content

Commit 6d3ce60

Browse files
committed
Add TypeMapper, can't test yet so just hoping it works
1 parent 384d9de commit 6d3ce60

3 files changed

Lines changed: 105 additions & 112 deletions

File tree

API.csproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,11 @@
2222
<ItemGroup>
2323
<Reference Include="Assembly-CSharp">
2424
<HintPath>lib\Assembly-CSharp.dll</HintPath>
25+
<Private>False</Private>
2526
</Reference>
2627
<Reference Include="Sirenix.Serialization">
2728
<HintPath>lib\Sirenix.Serialization.dll</HintPath>
29+
<Private>False</Private>
2830
</Reference>
2931
</ItemGroup>
3032
</Project>

Plugin.cs

Lines changed: 4 additions & 112 deletions
Original file line numberDiff line numberDiff line change
@@ -56,9 +56,12 @@ public class CustomCard
5656
public bool? flipPortraitForStrafe;
5757
public bool? onePerDeck;
5858
public List<CardAppearanceBehaviour.Appearance> appearanceBehaviour;
59+
[IgnoreMapping]
5960
public Texture2D tex;
61+
[IgnoreMapping]
6062
public Texture2D altTex;
6163
public Texture titleGraphic;
64+
[IgnoreMapping]
6265
public Texture2D pixelTex;
6366
public GameObject animatedPortrait;
6467
public List<Texture> decals;
@@ -107,106 +110,7 @@ public CustomCard(string name, List<CardMetaCategory> metaCategories = null, Car
107110

108111
public CardInfo AdjustCard(CardInfo card)
109112
{
110-
if (this.metaCategories is not null)
111-
{
112-
card.metaCategories = this.metaCategories;
113-
}
114-
if (this.cardComplexity is not null)
115-
{
116-
card.cardComplexity = (CardComplexity)this.cardComplexity;
117-
}
118-
if (this.temple is not null)
119-
{
120-
card.temple = (CardTemple)this.temple;
121-
}
122-
if (!String.IsNullOrEmpty(displayedName))
123-
{
124-
card.displayedName = displayedName;
125-
}
126-
if (this.baseAttack is not null)
127-
{
128-
card.baseAttack = baseAttack.Value;
129-
}
130-
if (this.baseHealth is not null)
131-
{
132-
card.baseHealth = baseHealth.Value;
133-
}
134-
if (!String.IsNullOrEmpty(description))
135-
{
136-
card.description = this.description;
137-
}
138-
if (this.cost is not null)
139-
{
140-
card.cost = cost.Value;
141-
}
142-
if (this.bonesCost is not null)
143-
{
144-
card.bonesCost = bonesCost.Value;
145-
}
146-
if (this.energyCost is not null)
147-
{
148-
card.energyCost = energyCost.Value;
149-
}
150-
if (this.gemsCost is not null)
151-
{
152-
card.gemsCost = gemsCost;
153-
}
154-
if (this.specialStatIcon is not null)
155-
{
156-
card.specialStatIcon = specialStatIcon.Value;
157-
}
158-
if (this.tribes is not null)
159-
{
160-
card.tribes = this.tribes;
161-
}
162-
if (this.traits is not null)
163-
{
164-
card.traits = this.traits;
165-
}
166-
if (this.specialAbilities is not null)
167-
{
168-
card.specialAbilities = specialAbilities;
169-
}
170-
if (this.abilities is not null)
171-
{
172-
card.abilities = abilities;
173-
}
174-
if (evolveParams is not null)
175-
{
176-
card.evolveParams = evolveParams;
177-
}
178-
if (evolveParams is not null)
179-
{
180-
card.evolveParams = evolveParams;
181-
}
182-
if (!String.IsNullOrEmpty(defaultEvolutionName))
183-
{
184-
card.defaultEvolutionName = defaultEvolutionName;
185-
}
186-
if (tailParams is not null)
187-
{
188-
card.tailParams = tailParams;
189-
}
190-
if (iceCubeParams is not null)
191-
{
192-
card.iceCubeParams = iceCubeParams;
193-
}
194-
if (this.appearanceBehaviour is not null)
195-
{
196-
card.appearanceBehaviour = this.appearanceBehaviour;
197-
}
198-
if (this.flipPortraitForStrafe is not null)
199-
{
200-
card.flipPortraitForStrafe = (bool)this.flipPortraitForStrafe;
201-
}
202-
if (this.onePerDeck is not null)
203-
{
204-
card.onePerDeck = (bool)this.onePerDeck;
205-
}
206-
if (this.hideAttackAndHealth is not null)
207-
{
208-
card.hideAttackAndHealth = (bool)this.hideAttackAndHealth;
209-
}
113+
TypeMapper<CustomCard, CardInfo>.Convert(this, card);
210114
if (this.tex is not null)
211115
{
212116
tex.name = "portrait_" + name;
@@ -221,25 +125,13 @@ public CardInfo AdjustCard(CardInfo card)
221125
card.alternatePortrait = Sprite.Create(altTex, new Rect(0.0f, 0.0f, 114.0f, 94.0f), new Vector2(0.5f, 0.5f));
222126
card.alternatePortrait.name = "portrait_" + name;
223127
}
224-
if (this.titleGraphic is not null)
225-
{
226-
card.titleGraphic = this.titleGraphic;
227-
}
228128
if (this.pixelTex is not null)
229129
{
230130
pixelTex.name = "portrait_" + name;
231131
pixelTex.filterMode = FilterMode.Point;
232132
card.pixelPortrait = Sprite.Create(pixelTex, new Rect(0.0f, 0.0f, 114.0f, 94.0f), new Vector2(0.5f, 0.5f));
233133
card.pixelPortrait.name = "portrait_" + name;
234134
}
235-
if (animatedPortrait is not null)
236-
{
237-
card.animatedPortrait = animatedPortrait;
238-
}
239-
if (decals is not null)
240-
{
241-
card.decals = decals;
242-
}
243135
Plugin.Log.LogInfo($"Adjusted default card {name}!");
244136
return card;
245137
}

TypeMapper.cs

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using HarmonyLib;
5+
using Mono.Cecil.Cil;
6+
using MonoMod.Utils;
7+
8+
namespace CardLoaderPlugin
9+
{
10+
[AttributeUsage(AttributeTargets.Field)]
11+
public class IgnoreMappingAttribute : Attribute {}
12+
public static unsafe class TypeMapper<S, D> where S : class where D : class, new()
13+
{
14+
private struct GetFieldDelegate
15+
{
16+
public delegate*<S, object> Del;
17+
}
18+
19+
private struct SetFieldDelegate
20+
{
21+
public delegate*<D, object, void> Del;
22+
}
23+
24+
private static Dictionary<string, GetFieldDelegate> _accessors = null;
25+
private static Dictionary<string, GetFieldDelegate> FieldAccessors
26+
{
27+
get
28+
{
29+
if (_accessors is null)
30+
{
31+
_accessors = new();
32+
33+
foreach (var field in AccessTools.GetDeclaredFields(typeof(S)).Where(x => !x.GetCustomAttributes(typeof(IgnoreMappingAttribute), false).Any()))
34+
{
35+
var accessor = new DynamicMethodDefinition("get_" + field.Name, typeof(object), new Type[] { typeof(S) });
36+
var il = accessor.GetILProcessor();
37+
il.Emit(OpCodes.Ldarg_0);
38+
il.Emit(OpCodes.Ldfld, accessor.Module.ImportReference(field));
39+
if (field.FieldType.IsValueType)
40+
il.Emit(OpCodes.Box);
41+
il.Emit(OpCodes.Ret);
42+
_accessors.Add(field.Name, new GetFieldDelegate { Del = (delegate*<S, object>)accessor.Generate().MethodHandle.GetFunctionPointer() });
43+
}
44+
}
45+
return _accessors;
46+
}
47+
}
48+
49+
private static Dictionary<string, SetFieldDelegate> _setters = null;
50+
private static Dictionary<string, SetFieldDelegate> FieldSetters
51+
{
52+
get
53+
{
54+
if (_setters == null)
55+
{
56+
_setters = new();
57+
58+
foreach (var field in AccessTools.GetDeclaredFields(typeof(D)))
59+
{
60+
var fieldType = field.FieldType;
61+
var setter = new DynamicMethodDefinition("set_" + field.Name, typeof(void), new Type[] { typeof(D), typeof(object) });
62+
var il = setter.GetILProcessor();
63+
il.Emit(OpCodes.Ldarg_0);
64+
il.Emit(OpCodes.Ldarg_1);
65+
if (field.FieldType.GetGenericTypeDefinition() == typeof(Nullable<>))
66+
{
67+
il.Emit(OpCodes.Call, AccessTools.DeclaredPropertyGetter(fieldType, "Value"));
68+
fieldType = fieldType.GetGenericArguments()[0];
69+
}
70+
else if (fieldType.IsValueType)
71+
il.Emit(OpCodes.Unbox, setter.Module.ImportReference(field.FieldType));
72+
else
73+
il.Emit(OpCodes.Castclass, setter.Module.ImportReference(field.FieldType));
74+
il.Emit(OpCodes.Stfld, setter.Module.ImportReference(field));
75+
il.Emit(OpCodes.Ret);
76+
_setters.Add(field.Name, new SetFieldDelegate { Del = (delegate*<D, object, void>)setter.Generate().MethodHandle.GetFunctionPointer() });
77+
}
78+
}
79+
return _setters;
80+
}
81+
}
82+
83+
public static D Convert(S source, D destination = null)
84+
{
85+
destination ??= new();
86+
87+
foreach (var field in FieldAccessors)
88+
{
89+
object val = field.Value.Del(source);
90+
if (val is not null)
91+
{
92+
FieldSetters[field.Key].Del(destination, val);
93+
}
94+
}
95+
96+
return destination;
97+
}
98+
}
99+
}

0 commit comments

Comments
 (0)