Skip to content

Commit e2fb42a

Browse files
committed
feat: Refactored the fields system to have a secondary way to get field data from LDtkFields with GetField(). This is a requisite to support fields in LDtkTableOfContents
1 parent 73040e5 commit e2fb42a

28 files changed

+535
-544
lines changed
Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using UnityEngine;
5+
6+
namespace LDtkUnity.Editor
7+
{
8+
/// <summary>
9+
/// Shared class for processing a field, used by both LDtkFieldsFactory and LDtkTocFieldFactory
10+
/// </summary>
11+
internal sealed class LDtkFieldFactory
12+
{
13+
private readonly LDtkProjectImporter _project;
14+
private readonly LDtkJsonImporter _importer;
15+
16+
public LDtkFieldFactory(LDtkProjectImporter project, LDtkJsonImporter importer)
17+
{
18+
_project = project;
19+
_importer = importer;
20+
}
21+
22+
/// <summary>
23+
/// Make an LDtkField from a field instance.
24+
/// </summary>
25+
/// <param name="def"></param>
26+
/// <param name="value">the field value, whether array or not. Depends on the field def</param>
27+
/// <returns></returns>
28+
public LDtkField GetFieldFromInstance(FieldDefinition def, object value)
29+
{
30+
LDtkProfiler.BeginSample($"GetObjectElements {def.Identifier}");
31+
LDtkFieldElement[] elements = GetObjectElements(def, value);
32+
LDtkProfiler.EndSample();
33+
34+
LDtkDefinitionObjectField defObj = null;
35+
36+
Debug.Assert(_importer.DefinitionObjects != null);
37+
if (_importer.DefinitionObjects != null)
38+
{
39+
defObj = _importer.DefinitionObjects.GetObject<LDtkDefinitionObjectField>(def.Uid);
40+
}
41+
42+
LDtkField field = new LDtkField(defObj, elements);
43+
return field;
44+
}
45+
46+
private LDtkFieldElement[] GetObjectElements(FieldDefinition def, object value)
47+
{
48+
LDtkProfiler.BeginSample($"GetElements");
49+
object[] elements = GetElements(def, value);
50+
LDtkProfiler.EndSample();
51+
52+
LDtkProfiler.BeginSample($"new LDtkFieldElements");
53+
LDtkFieldElement[] fieldElements = new LDtkFieldElement[elements.Length];
54+
for (int i = 0; i < fieldElements.Length; i++)
55+
{
56+
fieldElements[i] = new LDtkFieldElement(elements[i], def);
57+
}
58+
LDtkProfiler.EndSample();
59+
60+
return fieldElements;
61+
}
62+
63+
private object[] GetElements(FieldDefinition def, object value)
64+
{
65+
if (def.IsArray)
66+
{
67+
LDtkProfiler.BeginSample("GetArray");
68+
Array array = GetArray(def, value);
69+
LDtkProfiler.EndSample();
70+
71+
object[] objArray = new object[array.Length];
72+
for (int i = 0; i < array.Length; i++)
73+
{
74+
objArray[i] = array.GetValue(i);
75+
}
76+
return objArray;
77+
}
78+
79+
LDtkProfiler.BeginSample("GetSingle");
80+
object single = GetParsedValue(def, value);
81+
82+
LDtkProfiler.EndSample();
83+
84+
return new[] { single };
85+
}
86+
87+
private Array GetArray(FieldDefinition def, object value)
88+
{
89+
List<object> objs;
90+
91+
if (value is List<object> list)
92+
{
93+
objs = list;
94+
}
95+
else
96+
{
97+
LDtkDebug.LogError($"Not list (was {value.GetType().GetGenericArguments().First().Name}), not populating field instance \"{def.Identifier}\"");
98+
return Array.Empty<object>();
99+
}
100+
101+
//parse em
102+
LDtkProfiler.BeginSample("CopyArray");
103+
object[] srcObjs = new object[objs.Count];
104+
for (int i = 0; i < objs.Count; i++)
105+
{
106+
srcObjs[i] = GetParsedValue(def, objs[i]);
107+
}
108+
LDtkProfiler.EndSample();
109+
110+
LDtkProfiler.BeginSample("CopyArray");
111+
Array array = new object[srcObjs.Length];
112+
try
113+
{
114+
Array.Copy(srcObjs, array, srcObjs.Length);
115+
}
116+
catch(Exception e)
117+
{
118+
string srcObjsStrings = string.Join(", ", srcObjs);
119+
LDtkDebug.LogError($"Issue copying array for field instance \"{def.Identifier}\"; LDtk type: {def.Type}, ParsedObjects: {srcObjsStrings}. {e}");
120+
}
121+
LDtkProfiler.EndSample();
122+
123+
return array;
124+
}
125+
126+
private object GetParsedValue(FieldDefinition field, object value)
127+
{
128+
ParseFieldValueAction action = LDtkFieldParser.GetParserMethodForType(field);
129+
130+
LDtkFieldParseContext ctx = new LDtkFieldParseContext()
131+
{
132+
Project = _project,
133+
Importer = _importer,
134+
Input = value
135+
};
136+
137+
return action?.Invoke(ctx);
138+
}
139+
}
140+
}

Assets/LDtkUnity/Editor/ParsedField/LDtkFieldFactory.cs.meta

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Assets/LDtkUnity/Editor/ParsedField/LDtkFieldParseContext.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,12 @@
33
internal sealed class LDtkFieldParseContext
44
{
55
public object Input;
6+
7+
/// <summary>
8+
/// Needed by the parsed tile to get a sprite from it
9+
/// </summary>
610
public LDtkProjectImporter Project;
11+
712
public LDtkJsonImporter Importer;
813
}
914
}

Assets/LDtkUnity/Editor/ParsedField/LDtkFieldParser.cs

Lines changed: 58 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,14 @@
1-
using System;
2-
using System.Collections.Generic;
3-
using System.Linq;
4-
using UnityEditor;
5-
using UnityEngine;
1+
using System.Collections.Generic;
62

73
namespace LDtkUnity.Editor
84
{
95
internal static class LDtkFieldParser
106
{
117
private static LDtkBuilderEntity _builder;
12-
private static List<ILDtkValueParser> _parsers;
8+
private static Dictionary<string, ILDtkValueParser> _parsers;
139

14-
[RuntimeInitializeOnLoadMethod]
10+
//todo reinstate attribute if we add runtime building
11+
//[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)]
1512
private static void ResetValue()
1613
{
1714
_builder = null;
@@ -24,34 +21,73 @@ public static void CacheRecentBuilder(LDtkBuilderEntity builder)
2421
_builder = builder;
2522
}
2623

27-
public static ParseFieldValueAction GetParserMethodForType(FieldInstance instance)
24+
public static ParseFieldValueAction GetParserMethodForType(FieldDefinition def)
2825
{
2926
GetParserInstances();
3027

31-
ILDtkValueParser parser = _parsers.FirstOrDefault(p => p.TypeName(instance));
32-
33-
if (parser != null)
28+
if (!_parsers.TryGetValue(def.Type, out ILDtkValueParser parser))
3429
{
35-
//never apply post processing to field values if it was a level. the builder would be null in this case
36-
if (_builder != null && parser is ILDtkPostParser postParser)
30+
//maybe it was an enum that isn't based in hardcoded string
31+
if (def.IsEnum)
3732
{
38-
postParser.SupplyPostProcessorData(_builder, instance);
33+
parser = _parsers["LocalEnum"];
34+
}
35+
else
36+
{
37+
LDtkDebug.LogError($"FieldParser doesnt contain a key for \"{def.Type}\".");
38+
return null;
3939
}
40-
41-
//Debug.Log($"Parse FieldInstance {instance.Identifier}");
42-
return parser.ImportString;
40+
}
41+
42+
//never apply post-processing to field values if it was a level. the builder would be null in this case
43+
if (_builder != null && parser is ILDtkPostParser postParser)
44+
{
45+
postParser.SupplyPostProcessorData(_builder, def);
4346
}
4447

45-
LDtkDebug.LogError($"C# type \"{instance.Type}\" is not a parseable LDtk field type.");
46-
return null;
48+
//Debug.Log($"Parse FieldInstance {instance.Identifier}");
49+
return parser.ImportString;
4750
}
48-
51+
4952
private static void GetParserInstances()
5053
{
5154
if (_parsers == null)
5255
{
53-
TypeCache.TypeCollection parserTypes = TypeCache.GetTypesDerivedFrom<ILDtkValueParser>();
54-
_parsers = parserTypes.Select(Activator.CreateInstance).Cast<ILDtkValueParser>().ToList();
56+
_parsers = new Dictionary<string, ILDtkValueParser>
57+
{
58+
{ "Int", new LDtkParsedInt() },
59+
{ "Array<Int>", new LDtkParsedInt() },
60+
61+
{ "Float", new LDtkParsedFloat() },
62+
{ "Array<Float>", new LDtkParsedFloat() },
63+
64+
{ "Bool", new LDtkParsedBool() },
65+
{ "Array<Bool>", new LDtkParsedBool() },
66+
67+
{ "String", new LDtkParsedString() },
68+
{ "Array<String>", new LDtkParsedString() },
69+
70+
{ "Multilines", new LDtkParsedMultiline() },
71+
{ "Array<Multilines>", new LDtkParsedMultiline() },
72+
73+
{ "FilePath", new LDtkParsedFilePath() },
74+
{ "Array<FilePath>", new LDtkParsedFilePath() },
75+
76+
{ "Color", new LDtkParsedColor() },
77+
{ "Array<Color>", new LDtkParsedColor() },
78+
79+
//only need the one because enums are an exception to the rule
80+
{ "LocalEnum", new LDtkParsedEnum() },
81+
82+
{ "Tile", new LDtkParsedTile() },
83+
{ "Array<Tile>", new LDtkParsedTile() },
84+
85+
{ "EntityRef", new LDtkParsedEntityRef() },
86+
{ "Array<EntityRef>", new LDtkParsedEntityRef() },
87+
88+
{ "Point", new LDtkParsedPoint() },
89+
{ "Array<Point>", new LDtkParsedPoint() }
90+
};
5591
}
5692
}
5793
}

0 commit comments

Comments
 (0)