com.artromskiy.deltaecs.unity 0.0.38 → 0.0.39
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +4 -0
- package/CHANGELOG.md.meta +7 -0
- package/Editor/BoundEntityRootEditor.cs +23 -6
- package/Editor/ComponentPropertyBagFields.cs +280 -0
- package/Editor/ComponentPropertyBagFields.cs.meta +2 -0
- package/Editor/Resources/Inspector/SceneAuthoringEditor.uss +15 -16
- package/Editor/Resources/Inspector/SceneAuthoringEditor.uxml +1 -1
- package/Editor/SceneEntityInspectorView.cs +251 -120
- package/Editor.meta +8 -0
- package/README.md +1 -1
- package/Runtime/ComponentData.cs +16 -25
- package/Runtime/PropertyBagValueAccess.cs +258 -0
- package/Runtime/PropertyBagValueAccess.cs.meta +2 -0
- package/Runtime/SceneWorld.cs +62 -5
- package/Runtime.meta +8 -0
- package/package.json +8 -2
- package/package.json.meta +2 -0
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
using System;
|
|
2
|
+
using System.Collections.Generic;
|
|
3
|
+
using Delta.ECS;
|
|
4
|
+
using Unity.Properties;
|
|
5
|
+
|
|
6
|
+
namespace Delta.ECS.Unity
|
|
7
|
+
{
|
|
8
|
+
internal static class PropertyBagValueAccess
|
|
9
|
+
{
|
|
10
|
+
internal static bool TryGetValue(object container, Type containerType, string[] path, out object value)
|
|
11
|
+
{
|
|
12
|
+
value = null;
|
|
13
|
+
if (container == null || path == null || path.Length == 0)
|
|
14
|
+
{
|
|
15
|
+
return false;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
IPropertyBag propertyBag = PropertyBag.GetPropertyBag(containerType);
|
|
19
|
+
if (propertyBag == null)
|
|
20
|
+
{
|
|
21
|
+
return false;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
var visitor = new ReadPathVisitor(path, 0);
|
|
25
|
+
propertyBag.Accept(visitor, ref container);
|
|
26
|
+
value = visitor.Value;
|
|
27
|
+
return visitor.Found;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
internal static bool TrySetValue(ref object container, Type containerType, string[] path, object value)
|
|
31
|
+
{
|
|
32
|
+
if (container == null || path == null || path.Length == 0)
|
|
33
|
+
{
|
|
34
|
+
return false;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
IPropertyBag propertyBag = PropertyBag.GetPropertyBag(containerType);
|
|
38
|
+
if (propertyBag == null)
|
|
39
|
+
{
|
|
40
|
+
return false;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
var visitor = new WritePathVisitor(path, 0, value);
|
|
44
|
+
propertyBag.Accept(visitor, ref container);
|
|
45
|
+
return visitor.Succeeded;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
internal static string FormatPath(IReadOnlyList<string> path)
|
|
49
|
+
{
|
|
50
|
+
return string.Join("/", path);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
internal static string[] ParsePath(string path)
|
|
54
|
+
{
|
|
55
|
+
return string.IsNullOrEmpty(path) ? Array.Empty<string>() : path.Split('/');
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
internal static void CollectEntityReferences(object container, Type containerType,
|
|
59
|
+
Func<Entity, string> stableIdResolver, IList<EntityReference> references)
|
|
60
|
+
{
|
|
61
|
+
if (container == null)
|
|
62
|
+
{
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
IPropertyBag propertyBag = PropertyBag.GetPropertyBag(containerType);
|
|
67
|
+
if (propertyBag == null)
|
|
68
|
+
{
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
var visitor = new EntityReferenceVisitor(stableIdResolver, references);
|
|
73
|
+
propertyBag.Accept(visitor, ref container);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
private sealed class ReadPathVisitor : IPropertyBagVisitor
|
|
77
|
+
{
|
|
78
|
+
private readonly string[] _path;
|
|
79
|
+
private readonly int _pathIndex;
|
|
80
|
+
|
|
81
|
+
internal object Value;
|
|
82
|
+
internal bool Found;
|
|
83
|
+
|
|
84
|
+
internal ReadPathVisitor(string[] path, int pathIndex)
|
|
85
|
+
{
|
|
86
|
+
_path = path;
|
|
87
|
+
_pathIndex = pathIndex;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
public void Visit<TContainer>(IPropertyBag<TContainer> properties, ref TContainer container)
|
|
91
|
+
{
|
|
92
|
+
foreach (var property in properties.GetProperties(ref container))
|
|
93
|
+
{
|
|
94
|
+
if (!string.Equals(property.Name, _path[_pathIndex], StringComparison.Ordinal))
|
|
95
|
+
{
|
|
96
|
+
continue;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
object value = property.GetValue(ref container);
|
|
100
|
+
if (_pathIndex == _path.Length - 1)
|
|
101
|
+
{
|
|
102
|
+
Value = value;
|
|
103
|
+
Found = true;
|
|
104
|
+
}
|
|
105
|
+
else if (value != null)
|
|
106
|
+
{
|
|
107
|
+
IPropertyBag nestedBag = PropertyBag.GetPropertyBag(value.GetType());
|
|
108
|
+
if (nestedBag != null)
|
|
109
|
+
{
|
|
110
|
+
var nestedVisitor = new ReadPathVisitor(_path, _pathIndex + 1);
|
|
111
|
+
nestedBag.Accept(nestedVisitor, ref value);
|
|
112
|
+
Value = nestedVisitor.Value;
|
|
113
|
+
Found = nestedVisitor.Found;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
private sealed class WritePathVisitor : IPropertyBagVisitor
|
|
123
|
+
{
|
|
124
|
+
private readonly string[] _path;
|
|
125
|
+
private readonly int _pathIndex;
|
|
126
|
+
private readonly object _value;
|
|
127
|
+
|
|
128
|
+
internal bool Succeeded;
|
|
129
|
+
|
|
130
|
+
internal WritePathVisitor(string[] path, int pathIndex, object value)
|
|
131
|
+
{
|
|
132
|
+
_path = path;
|
|
133
|
+
_pathIndex = pathIndex;
|
|
134
|
+
_value = value;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
public void Visit<TContainer>(IPropertyBag<TContainer> properties, ref TContainer container)
|
|
138
|
+
{
|
|
139
|
+
TContainer updated = container;
|
|
140
|
+
foreach (var property in properties.GetProperties(ref updated))
|
|
141
|
+
{
|
|
142
|
+
if (!string.Equals(property.Name, _path[_pathIndex], StringComparison.Ordinal))
|
|
143
|
+
{
|
|
144
|
+
continue;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
if (property.IsReadOnly)
|
|
148
|
+
{
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
if (_pathIndex == _path.Length - 1)
|
|
153
|
+
{
|
|
154
|
+
property.SetValue(ref updated, _value);
|
|
155
|
+
Succeeded = true;
|
|
156
|
+
}
|
|
157
|
+
else
|
|
158
|
+
{
|
|
159
|
+
object nestedValue = property.GetValue(ref updated);
|
|
160
|
+
if (nestedValue == null)
|
|
161
|
+
{
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
IPropertyBag nestedBag = PropertyBag.GetPropertyBag(nestedValue.GetType());
|
|
166
|
+
if (nestedBag == null)
|
|
167
|
+
{
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
var nestedVisitor = new WritePathVisitor(_path, _pathIndex + 1, _value);
|
|
172
|
+
nestedBag.Accept(nestedVisitor, ref nestedValue);
|
|
173
|
+
if (nestedVisitor.Succeeded)
|
|
174
|
+
{
|
|
175
|
+
property.SetValue(ref updated, nestedValue);
|
|
176
|
+
Succeeded = true;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
container = updated;
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
private sealed class EntityReferenceVisitor : IPropertyBagVisitor, IPropertyVisitor
|
|
187
|
+
{
|
|
188
|
+
private readonly Func<Entity, string> _stableIdResolver;
|
|
189
|
+
private readonly IList<EntityReference> _references;
|
|
190
|
+
private readonly List<string> _path = new();
|
|
191
|
+
private readonly HashSet<object> _activeReferences = new HashSet<object>(new ReferenceSet());
|
|
192
|
+
|
|
193
|
+
internal EntityReferenceVisitor(Func<Entity, string> stableIdResolver, IList<EntityReference> references)
|
|
194
|
+
{
|
|
195
|
+
_stableIdResolver = stableIdResolver;
|
|
196
|
+
_references = references;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
public void Visit<TContainer>(IPropertyBag<TContainer> properties, ref TContainer container)
|
|
200
|
+
{
|
|
201
|
+
foreach (var property in properties.GetProperties(ref container))
|
|
202
|
+
{
|
|
203
|
+
((IPropertyAccept<TContainer>)property).Accept(this, ref container);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
public void Visit<TContainer, TValue>(Property<TContainer, TValue> property, ref TContainer container)
|
|
208
|
+
{
|
|
209
|
+
TValue value = property.GetValue(ref container);
|
|
210
|
+
_path.Add(property.Name);
|
|
211
|
+
try
|
|
212
|
+
{
|
|
213
|
+
if (typeof(TValue) == typeof(Entity))
|
|
214
|
+
{
|
|
215
|
+
string targetId = _stableIdResolver((Entity)(object)value);
|
|
216
|
+
if (!string.IsNullOrEmpty(targetId))
|
|
217
|
+
{
|
|
218
|
+
_references.Add(new EntityReference(FormatPath(_path), targetId));
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
else if (_path.Count < 24 && value != null)
|
|
222
|
+
{
|
|
223
|
+
object activeReference = value;
|
|
224
|
+
bool trackReference = !typeof(TValue).IsValueType;
|
|
225
|
+
if (!trackReference || _activeReferences.Add(activeReference))
|
|
226
|
+
{
|
|
227
|
+
try
|
|
228
|
+
{
|
|
229
|
+
object nestedValue = value;
|
|
230
|
+
if (PropertyBag.TryGetPropertyBagForValue(ref nestedValue, out IPropertyBag nestedBag))
|
|
231
|
+
{
|
|
232
|
+
nestedBag.Accept(this, ref nestedValue);
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
finally
|
|
236
|
+
{
|
|
237
|
+
if (trackReference)
|
|
238
|
+
{
|
|
239
|
+
_activeReferences.Remove(activeReference);
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
finally
|
|
246
|
+
{
|
|
247
|
+
_path.RemoveAt(_path.Count - 1);
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
private sealed class ReferenceSet : IEqualityComparer<object>
|
|
253
|
+
{
|
|
254
|
+
public new bool Equals(object left, object right) => ReferenceEquals(left, right);
|
|
255
|
+
public int GetHashCode(object value) => System.Runtime.CompilerServices.RuntimeHelpers.GetHashCode(value);
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
}
|
package/Runtime/SceneWorld.cs
CHANGED
|
@@ -212,6 +212,11 @@ namespace Delta.ECS.Unity
|
|
|
212
212
|
continue;
|
|
213
213
|
}
|
|
214
214
|
|
|
215
|
+
if (descriptor.IsTag)
|
|
216
|
+
{
|
|
217
|
+
continue;
|
|
218
|
+
}
|
|
219
|
+
|
|
215
220
|
object value = data.CreateValue(descriptor.ValueType, ResolveEntity);
|
|
216
221
|
if (_integration.TryRead(entity, descriptor.Id, out ComponentSnapshot snapshot, out _)
|
|
217
222
|
&& !_integration.TryWrite(entity, descriptor.Id, value, snapshot.Stamp, out _, out EcsWriteError error))
|
|
@@ -341,7 +346,7 @@ namespace Delta.ECS.Unity
|
|
|
341
346
|
{
|
|
342
347
|
if (TryGetEntity(authoring, out Entity entity))
|
|
343
348
|
{
|
|
344
|
-
return
|
|
349
|
+
return TryRead(entity, descriptor, out snapshot, out error);
|
|
345
350
|
}
|
|
346
351
|
|
|
347
352
|
snapshot = default;
|
|
@@ -349,13 +354,50 @@ namespace Delta.ECS.Unity
|
|
|
349
354
|
return false;
|
|
350
355
|
}
|
|
351
356
|
|
|
357
|
+
internal bool TryRead(Entity entity, ComponentDescriptor descriptor,
|
|
358
|
+
out ComponentSnapshot snapshot, out EcsReadError error)
|
|
359
|
+
=> _integration.TryRead(entity, descriptor.Id, out snapshot, out error);
|
|
360
|
+
|
|
361
|
+
internal bool TryGetComponents(Entity entity, Span<ComponentId> destination, out int totalCount)
|
|
362
|
+
{
|
|
363
|
+
totalCount = 0;
|
|
364
|
+
if (!_integration.IsAlive(entity))
|
|
365
|
+
{
|
|
366
|
+
return false;
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
ReadOnlyMemory<ComponentDescriptor> components = _integration.Catalog.Components;
|
|
370
|
+
for (int index = 0; index < components.Length; index++)
|
|
371
|
+
{
|
|
372
|
+
ComponentId component = components.Span[index].Id;
|
|
373
|
+
if (!_world.Has(entity, component))
|
|
374
|
+
{
|
|
375
|
+
continue;
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
if (totalCount < destination.Length)
|
|
379
|
+
{
|
|
380
|
+
destination[totalCount] = component;
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
totalCount++;
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
return true;
|
|
387
|
+
}
|
|
388
|
+
|
|
352
389
|
internal bool TryWrite(EntityAuthoring authoring, ComponentData data,
|
|
353
390
|
ComponentDescriptor descriptor, object value, out EcsWriteError error)
|
|
354
391
|
{
|
|
355
|
-
if (!TryGetEntity(authoring, out Entity entity)
|
|
356
|
-
|| !_integration.TryRead(entity, descriptor.Id, out ComponentSnapshot snapshot, out _))
|
|
392
|
+
if (!TryGetEntity(authoring, out Entity entity) || !_integration.IsAlive(entity))
|
|
357
393
|
{
|
|
358
|
-
error =
|
|
394
|
+
error = new EcsWriteError(EcsWriteErrorCode.EntityNotAlive);
|
|
395
|
+
return false;
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
if (!_integration.TryRead(entity, descriptor.Id, out ComponentSnapshot snapshot, out _))
|
|
399
|
+
{
|
|
400
|
+
error = new EcsWriteError(EcsWriteErrorCode.ComponentMissing);
|
|
359
401
|
return false;
|
|
360
402
|
}
|
|
361
403
|
|
|
@@ -364,7 +406,15 @@ namespace Delta.ECS.Unity
|
|
|
364
406
|
return false;
|
|
365
407
|
}
|
|
366
408
|
|
|
367
|
-
|
|
409
|
+
if (descriptor.IsTag)
|
|
410
|
+
{
|
|
411
|
+
data.StoreDefaultTag();
|
|
412
|
+
}
|
|
413
|
+
else
|
|
414
|
+
{
|
|
415
|
+
data.StoreValue(value, GetStableIdOrEmpty);
|
|
416
|
+
}
|
|
417
|
+
|
|
368
418
|
return true;
|
|
369
419
|
}
|
|
370
420
|
|
|
@@ -395,6 +445,13 @@ namespace Delta.ECS.Unity
|
|
|
395
445
|
return false;
|
|
396
446
|
}
|
|
397
447
|
|
|
448
|
+
if (descriptor.IsTag)
|
|
449
|
+
{
|
|
450
|
+
data.StoreDefaultTag();
|
|
451
|
+
error = default;
|
|
452
|
+
return true;
|
|
453
|
+
}
|
|
454
|
+
|
|
398
455
|
object value = data.CreateValue(descriptor.ValueType, ResolveEntity);
|
|
399
456
|
if (!_integration.TryRead(entity, descriptor.Id, out ComponentSnapshot snapshot, out EcsReadError readError))
|
|
400
457
|
{
|
package/Runtime.meta
ADDED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "com.artromskiy.deltaecs.unity",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.39",
|
|
4
4
|
"displayName": "DeltaECS Unity",
|
|
5
5
|
"description": "Unity scene authoring and editor integration for DeltaECS.",
|
|
6
6
|
"unity": "6000.7",
|
|
@@ -23,9 +23,15 @@
|
|
|
23
23
|
},
|
|
24
24
|
"files": [
|
|
25
25
|
"Runtime/",
|
|
26
|
+
"Runtime.meta",
|
|
26
27
|
"Editor/",
|
|
28
|
+
"Editor.meta",
|
|
27
29
|
"README.md",
|
|
30
|
+
"README.md.meta",
|
|
28
31
|
"CHANGELOG.md",
|
|
29
|
-
"
|
|
32
|
+
"CHANGELOG.md.meta",
|
|
33
|
+
"LICENSE.md",
|
|
34
|
+
"LICENSE.md.meta",
|
|
35
|
+
"package.json.meta"
|
|
30
36
|
]
|
|
31
37
|
}
|