Skip to content

Commit 3355481

Browse files
committed
fix: resolve issues with XNB content type names
1 parent 66a5f91 commit 3355481

16 files changed

Lines changed: 129 additions & 90 deletions

Core.SourceGen/CodeStringBuilder.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,16 +36,16 @@ public void AppendLine(string s)
3636
AppendLine();
3737
}
3838

39-
public void BeginCodeBlock()
39+
public void BeginCodeBlock(string openCharacter = "{")
4040
{
41-
AppendLine("{");
41+
AppendLine(openCharacter);
4242
_currentIndent++;
4343
}
4444

45-
public void EndCodeBlock()
45+
public void EndCodeBlock(string closeCharacter = "}")
4646
{
4747
if(_currentIndent > 0) _currentIndent--;
48-
AppendLine("}");
48+
AppendLine(closeCharacter);
4949
}
5050

5151
public override string ToString() => _stringBuilder.ToString();

Core.SourceGen/ContentSerializerGenerator.cs

Lines changed: 46 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ private struct XnbTypeInfo
1818
public string TypeName;
1919
public string TypeFullName;
2020
public string QualifierString;
21+
public List<string> GenericParameters;
2122
public List<XnbPropertyInfo> Properties;
2223
}
2324

@@ -50,11 +51,6 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
5051
return null;
5152
}
5253

53-
if (typeSymbol.IsGenericType)
54-
{
55-
return null;
56-
}
57-
5854
var xnbReaderTypeAttribute = typeSymbol.GetAttributes()
5955
.FirstOrDefault(a => a.AttributeClass?.ToDisplayString() == XnbReaderTypeAttributeName);
6056

@@ -63,19 +59,19 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
6359
return null;
6460
}
6561

66-
bool useBaseClass = xnbReaderTypeAttribute.NamedArguments
67-
.FirstOrDefault(x => x.Key == "UseBaseClass").Value.Value is true;
62+
bool isPrivate = xnbReaderTypeAttribute.NamedArguments
63+
.FirstOrDefault(x => x.Key == "IsPrivate").Value.Value is true;
6864

69-
var logicalTypeSymbol = typeSymbol;
70-
if (useBaseClass && typeSymbol.BaseType is not null)
65+
if (isPrivate)
7166
{
72-
logicalTypeSymbol = typeSymbol.BaseType;
67+
return null;
7368
}
7469

7570
var qualifierString = xnbReaderTypeAttribute.ConstructorArguments[0].Value as string ?? string.Empty;
71+
var genericParameters = typeSymbol.TypeParameters.Select(tp => tp.Name).ToList();
7672
var properties = new List<XnbPropertyInfo>();
7773

78-
foreach (var member in logicalTypeSymbol.GetMembers().OfType<IPropertySymbol>())
74+
foreach (var member in typeSymbol.GetMembers().OfType<IPropertySymbol>())
7975
{
8076
ct.ThrowIfCancellationRequested();
8177

@@ -123,9 +119,10 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
123119
return new XnbTypeInfo
124120
{
125121
TypeName = typeSymbol.Name,
126-
TypeFullName = logicalTypeSymbol.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat),
122+
TypeFullName = typeSymbol.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat),
127123
QualifierString = qualifierString,
128124
Properties = properties,
125+
GenericParameters = genericParameters
129126
};
130127
}
131128

@@ -148,18 +145,53 @@ private static void EmitSerializer(CodeStringBuilder cb, XnbTypeInfo xnbTypeInfo
148145
cb.AppendLine();
149146
cb.AppendLine("namespace FEZRepacker.Core.XNB.ContentSerialization;");
150147
cb.AppendLine();
151-
cb.Append($"internal sealed class {xnbTypeInfo.TypeName}ContentSerializer");
148+
cb.Append($"internal sealed class {ConstructSerializerName(xnbTypeInfo)}");
152149
cb.AppendLine($" : XnbContentSerializer<{xnbTypeInfo.TypeFullName}>");
153150
cb.BeginCodeBlock();
154151
{
155-
cb.AppendLine($"public override XnbAssemblyQualifier Name => \"{xnbTypeInfo.QualifierString}\";");
152+
EmitConstructor(cb, xnbTypeInfo);
156153
cb.AppendLine();
157154
EmitDeserialize(cb, xnbTypeInfo);
158155
cb.AppendLine();
159156
EmitSerialize(cb, xnbTypeInfo);
160157
}
161158
cb.EndCodeBlock();
162159
}
160+
161+
private static string ConstructSerializerName(XnbTypeInfo xnbTypeInfo)
162+
{
163+
var name = $"{xnbTypeInfo.TypeName}ContentSerializer";
164+
if (xnbTypeInfo.GenericParameters.Count > 0)
165+
{
166+
var genericParametersList = string.Join(", " , xnbTypeInfo.GenericParameters);
167+
name += $"<{genericParametersList}>";
168+
}
169+
return name;
170+
}
171+
172+
private static void EmitConstructor(CodeStringBuilder cb, XnbTypeInfo xnbTypeInfo)
173+
{
174+
if (xnbTypeInfo.GenericParameters.Count == 0)
175+
{
176+
cb.AppendLine($"public override XnbAssemblyQualifier Name => \"{xnbTypeInfo.QualifierString}\";");
177+
return;
178+
}
179+
180+
cb.AppendLine( "private readonly XnbAssemblyQualifier _name;");
181+
cb.AppendLine();
182+
cb.AppendLine("public override XnbAssemblyQualifier Name => _name;");
183+
cb.Append("public override Type[] UnderlyingContentTypes => [");
184+
cb.Append(string.Join(", ", xnbTypeInfo.GenericParameters.Select(type => $"typeof({type})")));
185+
cb.AppendLine("];");
186+
cb.AppendLine();
187+
cb.AppendLine($"public {xnbTypeInfo.TypeName}ContentSerializer() : base ()");
188+
cb.BeginCodeBlock();
189+
{
190+
cb.AppendLine($"var name = XnbAssemblyQualifier.TryGetFromXnbReaderType(typeof({xnbTypeInfo.TypeFullName}));");
191+
cb.AppendLine("if (name.HasValue) _name = name.Value;");
192+
}
193+
cb.EndCodeBlock();
194+
}
163195

164196
private static void EmitDeserialize(CodeStringBuilder cb, XnbTypeInfo model)
165197
{
Lines changed: 1 addition & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
using FEZRepacker.Core.Definitions.Game.ArtObject;
2-
using FEZRepacker.Core.Definitions.Game.XNA;
1+
using FEZRepacker.Core.Definitions.Game.XNA;
32

43
namespace FEZRepacker.Core.Definitions.Game.Graphics
54
{
@@ -23,21 +22,4 @@ public IndexedPrimitives()
2322
Indices = new ushort[0];
2423
}
2524
}
26-
27-
28-
/* Helper subclasses for serialization sourcegen - easier to control qualifier name this way. */
29-
30-
[XnbReaderType("FezEngine.Readers.ShaderInstancedIndexedPrimitivesReader`2" +
31-
"[[FezEngine.Structure.Geometry.VertexPositionNormalTextureInstance, FezEngine]," +
32-
"[Microsoft.Xna.Framework.Matrix, Microsoft.Xna.Framework, Version=4.0.0.0, " +
33-
"Culture=neutral, PublicKeyToken=842cf8be1de50553]], FezEngine",
34-
UseBaseClass = true)]
35-
internal class ArtObjectIndexedPrimitives : IndexedPrimitives<VertexInstance, Matrix>;
36-
37-
[XnbReaderType("FezEngine.Readers.ShaderInstancedIndexedPrimitivesReader`2" +
38-
"[[FezEngine.Structure.Geometry.VertexPositionNormalTextureInstance, FezEngine]," +
39-
"[Microsoft.Xna.Framework.Vector4, Microsoft.Xna.Framework, Version=4.0.0.0, " +
40-
"Culture=neutral, PublicKeyToken=842cf8be1de50553]], FezEngine",
41-
UseBaseClass = true)]
42-
internal class TrileSetIndexedPrimitives : IndexedPrimitives<VertexInstance, Vector4>;
4325
}

Core/Definitions/Game/XnbReaderTypeAttribute.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,7 @@ namespace FEZRepacker.Core.Definitions.Game
1111
internal sealed class XnbReaderTypeAttribute : Attribute
1212
{
1313
public XnbAssemblyQualifier Qualifier { get; set; }
14-
15-
public bool UseBaseClass { get; set; }
14+
public bool IsPrivate { get; set; }
1615

1716
public XnbReaderTypeAttribute(string _qualifier)
1817
{

Core/Helpers/OrderedDictionary.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
namespace FEZRepacker.Core.Helpers
66
{
77
[XnbType("System.Collections.Generic.Dictionary, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
8-
[XnbReaderType("Microsoft.Xna.Framework.Content.DictionaryReader")]
8+
[XnbReaderType("Microsoft.Xna.Framework.Content.DictionaryReader", IsPrivate = true)]
99
internal class OrderedDictionary<TKey, TValue> : IDictionary<TKey, TValue>
1010
{
1111
private readonly Dictionary<TKey, TValue> _dictionary;

Core/XNB/ContentSerialization/System/ArrayContentSerializer.cs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@ internal class ArrayContentSerializer<T> : XnbContentSerializer<T[]> where T : n
55
{
66
private XnbAssemblyQualifier _name;
77
private readonly bool _skipElementType;
8+
9+
public override XnbAssemblyQualifier Name => _name;
10+
public override Type[] UnderlyingContentTypes => [typeof(T)];
11+
812
public ArrayContentSerializer(bool skipElementType = true) : base()
913
{
1014
// creating type assembly qualifier name
@@ -19,8 +23,6 @@ public ArrayContentSerializer(bool skipElementType = true) : base()
1923
_skipElementType = skipElementType;
2024
}
2125

22-
public override XnbAssemblyQualifier Name => _name;
23-
2426
public override object Deserialize(XnbContentReader reader)
2527
{
2628
int dataCount = reader.ReadInt32();
@@ -35,6 +37,7 @@ public override object Deserialize(XnbContentReader reader)
3537

3638
public override void Serialize(object data, XnbContentWriter writer)
3739
{
40+
writer.TryClaimContentType(typeof(T));
3841
T[] array = (T[])data;
3942

4043
writer.Write(array.Length);

Core/XNB/ContentSerialization/System/DictionaryContentSerializer.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ internal class DictionaryContentSerializer<K, V> : XnbContentSerializer<OrderedD
1010

1111
public override Type ContentType => typeof(IDictionary<K, V>);
1212
public override XnbAssemblyQualifier Name => _name;
13+
public override Type[] UnderlyingContentTypes => [typeof(K), typeof(V)];
1314

1415
public DictionaryContentSerializer(
1516
bool skipKeyIdentifier = false,
@@ -43,6 +44,9 @@ public override object Deserialize(XnbContentReader reader)
4344

4445
public override void Serialize(object data, XnbContentWriter writer)
4546
{
47+
writer.TryClaimContentType(typeof(K));
48+
writer.TryClaimContentType(typeof(V));
49+
4650
var dict = (IDictionary<K, V>)data;
4751

4852
writer.Write(dict.Count);

Core/XNB/ContentSerialization/System/EnumContentSerializer.cs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,10 @@
33
internal class EnumContentSerializer<T> : XnbContentSerializer<T> where T : Enum
44
{
55
private XnbAssemblyQualifier _name;
6-
6+
7+
public override XnbAssemblyQualifier Name => _name;
8+
public override Type[] UnderlyingContentTypes => [typeof(int)];
9+
710
public EnumContentSerializer() : base()
811
{
912
// creating type assembly qualifier name
@@ -13,8 +16,7 @@ public EnumContentSerializer() : base()
1316

1417
_name.Templates[0] = XnbAssemblyQualifier.GetForType(typeof(T));
1518
}
16-
17-
public override XnbAssemblyQualifier Name => _name;
19+
1820

1921
public override object Deserialize(XnbContentReader reader)
2022
{

Core/XNB/ContentSerialization/System/ListContentSerializer.cs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@ internal class ListContentSerializer<T> : XnbContentSerializer<List<T>> where T
44
{
55
private XnbAssemblyQualifier _name;
66
private bool _skipElementType;
7+
8+
public override XnbAssemblyQualifier Name => _name;
9+
public override Type[] UnderlyingContentTypes => [typeof(T)];
10+
711
public ListContentSerializer(bool skipElementType = false) : base()
812
{
913
// creating type assembly qualifier name
@@ -19,8 +23,6 @@ public ListContentSerializer(bool skipElementType = false) : base()
1923
_skipElementType = skipElementType;
2024
}
2125

22-
public override XnbAssemblyQualifier Name => _name;
23-
2426
public override object Deserialize(XnbContentReader reader)
2527
{
2628
List<T> data = new List<T>();
@@ -35,6 +37,7 @@ public override object Deserialize(XnbContentReader reader)
3537

3638
public override void Serialize(object data, XnbContentWriter writer)
3739
{
40+
writer.TryClaimContentType(typeof(T));
3841
List<T> list = (List<T>)data;
3942

4043
writer.Write(list.Count);

Core/XNB/ContentSerialization/XnbContentSerializer.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ internal abstract class XnbContentSerializer
77
{
88
public abstract XnbAssemblyQualifier Name { get; }
99
public abstract Type ContentType { get; }
10+
public virtual Type[] UnderlyingContentTypes => [];
1011
public bool IsPrivate { get; protected set; }
1112

1213
public XnbContentSerializer()

0 commit comments

Comments
 (0)