Skip to content

Commit 1149747

Browse files
committed
feat: Added support to LDtkTableOfContents ScriptableObject to get fields, and also can access entity definition data from a toc entry
1 parent e2fb42a commit 1149747

File tree

6 files changed

+217
-26
lines changed

6 files changed

+217
-26
lines changed
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
using UnityEditor;
2+
3+
namespace LDtkUnity.Editor
4+
{
5+
// This class merely existing makes the inspector draw with no scroll rects
6+
[CustomEditor(typeof(LDtkTableOfContents))]
7+
internal sealed class LDtkTableOfContentsEditor : UnityEditor.Editor
8+
{
9+
10+
}
11+
}

Assets/LDtkUnity/Editor/CustomEditor/LDtkTableOfContentsEditor.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.
Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
using System;
2+
using System.Collections.Generic;
3+
4+
namespace LDtkUnity.Editor
5+
{
6+
/// <summary>
7+
/// toc fields are only keyed by the entity's identifier and then the field's identifier. no uid.
8+
/// So we should build up a dictionary by identifier for easy lookup
9+
/// </summary>
10+
internal sealed class LDtkTocFieldFactory
11+
{
12+
private LdtkJson _json;
13+
private readonly LDtkJsonImporter _importer;
14+
private readonly LDtkProjectImporter _project;
15+
16+
private Dictionary<string, EntityFieldDefsByIdentifier> _entityIdentifierToFieldDefs;
17+
private Dictionary<string, LDtkDefinitionObjectEntity> _entityIdentifierToEntityDefinition;
18+
19+
public class TocFieldFactoryOutput
20+
{
21+
public LDtkDefinitionObjectEntity Definition;
22+
public List<LDtkField[]> Fields;
23+
}
24+
25+
26+
private class EntityFieldDefsByIdentifier : Dictionary<string, FieldDefinition>
27+
{
28+
public EntityFieldDefsByIdentifier(int capacity) : base(capacity) { }
29+
}
30+
31+
public LDtkTocFieldFactory(LdtkJson json, LDtkJsonImporter importer, LDtkProjectImporter project)
32+
{
33+
_json = json;
34+
_importer = importer;
35+
_project = project;
36+
}
37+
38+
public void IndexEntitiesAndFieldsByIdentifiers()
39+
{
40+
//no preallocate because we aren't necessarily covering all entities
41+
_entityIdentifierToFieldDefs = new Dictionary<string, EntityFieldDefsByIdentifier>();
42+
_entityIdentifierToEntityDefinition = new Dictionary<string, LDtkDefinitionObjectEntity>();
43+
44+
foreach (EntityDefinition entityDef in _json.Defs.Entities)
45+
{
46+
//skip caching any that don't export to toc
47+
if (!entityDef.ExportToToc) continue;
48+
49+
_entityIdentifierToEntityDefinition.Add(entityDef.Identifier, _importer.DefinitionObjects.GetObject<LDtkDefinitionObjectEntity>(entityDef.Uid));
50+
51+
EntityFieldDefsByIdentifier fields = new EntityFieldDefsByIdentifier(entityDef.FieldDefs.Length);
52+
foreach (FieldDefinition fieldDef in entityDef.FieldDefs)
53+
{
54+
//skip caching fields that don't export to toc
55+
if (!fieldDef.ExportToToc) continue;
56+
57+
fields.Add(fieldDef.Identifier, fieldDef);
58+
}
59+
_entityIdentifierToFieldDefs.Add(entityDef.Identifier, fields);
60+
}
61+
}
62+
63+
/// <summary>
64+
/// One Toc entry can have multiple instances. so a list for each eneityt, and the element is an array of fields that the entity would possess.
65+
/// </summary>
66+
/// <param name="entry"></param>
67+
/// <returns></returns>
68+
public TocFieldFactoryOutput GenerateFieldsFromTocEntry(LdtkTableOfContentEntry entry)
69+
{
70+
string entityIdentifier = entry.Identifier;
71+
72+
List<LDtkField[]> fieldsList = new List<LDtkField[]>();
73+
74+
LdtkTocInstanceData[] instances = entry.UnityInstances();
75+
foreach (LdtkTocInstanceData instance in instances)
76+
{
77+
LDtkField[] fields = GetFields(entityIdentifier, instance.Fields);
78+
fieldsList.Add(fields);
79+
}
80+
81+
TocFieldFactoryOutput output = new TocFieldFactoryOutput()
82+
{
83+
Definition = _entityIdentifierToEntityDefinition[entityIdentifier],
84+
Fields = fieldsList
85+
};
86+
87+
return output;
88+
}
89+
90+
private LDtkField[] GetFields(string entityIdentifier, Dictionary<string,object> srcFields)
91+
{
92+
LDtkFieldFactory fieldFactory = new LDtkFieldFactory(_project, _importer);
93+
94+
LDtkField[] fields = new LDtkField[srcFields.Count];
95+
96+
int i = 0;
97+
foreach (var fieldIdentifier in srcFields.Keys)
98+
{
99+
FieldDefinition def = GetFieldDefByFieldIdentifier(entityIdentifier, fieldIdentifier);
100+
fields[i] = fieldFactory.GetFieldFromInstance(def, srcFields[fieldIdentifier]);
101+
i++;
102+
}
103+
104+
return fields;
105+
}
106+
107+
/// <summary>
108+
/// The important part about this:
109+
/// A Toc field is only identified by its name. use the entity's name and the field name to figure out the type of the field to get it's object and then parse it.
110+
/// </summary>
111+
private FieldDefinition GetFieldDefByFieldIdentifier(string entityIdentifier, string fieldIdentifier)
112+
{
113+
if (_entityIdentifierToFieldDefs.TryGetValue(entityIdentifier, out EntityFieldDefsByIdentifier fields))
114+
{
115+
if (fields.TryGetValue(fieldIdentifier, out FieldDefinition fieldDef))
116+
{
117+
return fieldDef;
118+
}
119+
120+
LDtkDebug.LogError($"The field identifier \"{fieldIdentifier}\" does not exist in the entity \"{entityIdentifier}\"");
121+
}
122+
else
123+
{
124+
LDtkDebug.LogWarning($"The entity identifier \"{entityIdentifier}\" does not exist in the table of contents");
125+
}
126+
127+
return null;
128+
}
129+
}
130+
}

Assets/LDtkUnity/Editor/ParsedField/LDtkTocFieldFactory.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/ScriptedImporter/LDtkProjectImporter.cs

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,10 @@ private void CreateJsonAsset()
234234
_jsonFile = ReadAssetText();
235235
ImportContext.AddObjectToAsset("jsonFile", _jsonFile, LDtkIconUtility.LoadListIcon());
236236
}
237+
/// <summary>
238+
/// Should process after all the definition scriptable objects are created so that they are accessible in this context
239+
/// </summary>
240+
/// <param name="json"></param>
237241
private void TryCreateTableOfContents(LdtkJson json)
238242
{
239243
if (json.Toc.IsNullOrEmpty())
@@ -243,7 +247,25 @@ private void TryCreateTableOfContents(LdtkJson json)
243247

244248
Toc = ScriptableObject.CreateInstance<LDtkTableOfContents>();
245249
Toc.name += AssetName + "_Toc";
246-
Toc.Initialize(json);
250+
251+
LDtkTocFieldFactory factory = new LDtkTocFieldFactory(json, this, this);
252+
253+
LDtkProfiler.BeginSample("Toc_IndexEntitiesAndFieldsByIdentifiers");
254+
factory.IndexEntitiesAndFieldsByIdentifiers();
255+
LDtkProfiler.EndSample();
256+
257+
Toc.InitializeList(json);
258+
259+
LDtkFieldParser.CacheRecentBuilder(null);
260+
LDtkProfiler.BeginSample("Toc_GenerateAndAddEntries");
261+
foreach (LdtkTableOfContentEntry tocEntry in json.Toc)
262+
{
263+
var output = factory.GenerateFieldsFromTocEntry(tocEntry);
264+
Toc.AddEntry(tocEntry, output.Definition, output.Fields);
265+
}
266+
LDtkProfiler.EndSample();
267+
268+
247269
ImportContext.AddObjectToAsset("toc", Toc, LDtkIconUtility.LoadListIcon());
248270
}
249271

Assets/LDtkUnity/Runtime/UnityAssets/Assets/LDtkTableOfContents.cs

Lines changed: 47 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -15,23 +15,25 @@ public sealed class LDtkTableOfContents : ScriptableObject
1515
{
1616
[SerializeField] internal List<LDtkTableOfContentsEntry> _entries;
1717

18-
internal void Initialize(LdtkJson json)
18+
internal void InitializeList(LdtkJson json)
1919
{
2020
_entries = new List<LDtkTableOfContentsEntry>(json.Toc.Length);
21-
foreach (LdtkTableOfContentEntry p in json.Toc)
22-
{
23-
_entries.Add(new LDtkTableOfContentsEntry(p));
24-
}
21+
}
22+
23+
internal void AddEntry(LdtkTableOfContentEntry entry, LDtkDefinitionObjectEntity def, List<LDtkField[]> fields)
24+
{
25+
LDtkTableOfContentsEntry newEntry = new LDtkTableOfContentsEntry(entry, def, fields);
26+
_entries.Add(newEntry);
2527
}
2628

2729
[PublicAPI, Obsolete("Use " + nameof(GetEntry) + " instead")]
2830
public LDtkReferenceToAnEntityInstance[] GetEntities(string identifier)
2931
{
30-
return GetEntry(identifier)._entries.Select(p => p.EntityRef).ToArray();
32+
return GetEntry(identifier).Entries.Select(p => p.EntityRef).ToArray();
3133
}
3234

3335
/// <summary>
34-
/// Gets all of the entity references in this table of contents of an entity type.
36+
/// Gets all the entity references in this table of contents of an entity type.
3537
/// </summary>
3638
/// <param name="identifier">
3739
/// The identifier of the entity type to look for.
@@ -40,7 +42,7 @@ public LDtkTableOfContentsEntry GetEntry(string identifier)
4042
{
4143
foreach (LDtkTableOfContentsEntry entry in _entries)
4244
{
43-
if (entry._identifier == identifier)
45+
if (entry.Definition.Identifier == identifier)
4446
{
4547
return entry;
4648
}
@@ -53,37 +55,57 @@ public LDtkTableOfContentsEntry GetEntry(string identifier)
5355
[Serializable]
5456
public sealed class LDtkTableOfContentsEntry
5557
{
56-
public string _identifier;
57-
public List<LDtkTableOfContentsEntryData> _entries;
58-
59-
public LDtkTableOfContentsEntry(LdtkTableOfContentEntry entry)
58+
[SerializeField] private LDtkDefinitionObjectEntity _def;
59+
[SerializeField] private List<LDtkTableOfContentsEntryData> _entries;
60+
61+
public LDtkDefinitionObjectEntity Definition => _def;
62+
63+
/// <summary>
64+
/// The list of entity instances in this table of contents entry.
65+
/// </summary>
66+
public List<LDtkTableOfContentsEntryData> Entries => _entries;
67+
68+
internal LDtkTableOfContentsEntry(LdtkTableOfContentEntry entry, LDtkDefinitionObjectEntity def, List<LDtkField[]> fields)
6069
{
61-
_identifier = entry.Identifier;
70+
_def = def;
6271

6372
LdtkTocInstanceData[] datas = entry.UnityInstances();
6473

6574
_entries = new List<LDtkTableOfContentsEntryData>(datas.Length);
66-
foreach (LdtkTocInstanceData p in datas)
75+
for (int i = 0; i < datas.Length; i++)
6776
{
68-
_entries.Add(new LDtkTableOfContentsEntryData(p));
77+
_entries.Add(new LDtkTableOfContentsEntryData(datas[i], fields[i]));
6978
}
7079
}
7180
}
7281

7382
[Serializable]
7483
public sealed class LDtkTableOfContentsEntryData
7584
{
76-
public LDtkReferenceToAnEntityInstance EntityRef;
77-
//public LDtkFields Field; //todo
78-
public Vector2Int WorldPos;
79-
public Vector2Int SizePx;
80-
81-
public LDtkTableOfContentsEntryData(LdtkTocInstanceData data)
85+
[SerializeField] private LDtkReferenceToAnEntityInstance _entityRef;
86+
[SerializeField] private Vector2Int _worldPos;
87+
[SerializeField] private Vector2Int _sizePx;
88+
[SerializeField] private LDtkField[] _fields;
89+
90+
public LDtkReferenceToAnEntityInstance EntityRef => _entityRef;
91+
public Vector2Int WorldPosition => _worldPos;
92+
public Vector2Int Size => _sizePx;
93+
public LDtkField[] Fields => _fields;
94+
95+
/// <summary>
96+
/// Finds a field by its identifier.
97+
/// </summary>
98+
public LDtkField GetField(string identifier)
99+
{
100+
return _fields.FirstOrDefault(p => p.Identifier == identifier);
101+
}
102+
103+
internal LDtkTableOfContentsEntryData(LdtkTocInstanceData data, LDtkField[] fields)
82104
{
83-
EntityRef = new LDtkReferenceToAnEntityInstance(data.Iids);
84-
//Field = data.Fields; todo
85-
WorldPos = data.UnityWorld;
86-
SizePx = data.UnitySizePx;
105+
_entityRef = new LDtkReferenceToAnEntityInstance(data.Iids);
106+
_fields = fields;
107+
_worldPos = data.UnityWorld;
108+
_sizePx = data.UnitySizePx;
87109
}
88110
}
89111
}

0 commit comments

Comments
 (0)