com.artromskiy.deltaecs.unity 0.0.37 → 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.
@@ -1,7 +1,6 @@
1
1
  using System;
2
2
  using System.Collections.Generic;
3
3
  using System.Linq;
4
- using System.Reflection;
5
4
  using Delta;
6
5
  using Delta.ECS;
7
6
  using Delta.ECS.Integration;
@@ -194,10 +193,12 @@ namespace Delta.ECS.Unity.Editor
194
193
  _header.Add(BuildEntityHeader(authoring));
195
194
  _componentEntries.AddRange(ProjectAuthoringComponents(authoring));
196
195
  RenderComponentRows();
196
+ _footer.Add(BuildAddComponentMenu(authoring));
197
197
  var deleteButton = new Button(() => HierarchyMenu.DeleteEntity(Authoring, authoring.StableId))
198
198
  {
199
199
  text = "Delete Entity"
200
200
  };
201
+ deleteButton.AddToClassList("ecs-action-button");
201
202
  deleteButton.AddToClassList("ecs-delete-entity");
202
203
  _footer.Add(deleteButton);
203
204
  }
@@ -302,6 +303,7 @@ namespace Delta.ECS.Unity.Editor
302
303
  text = "Unbind",
303
304
  tooltip = "Remove the GameObject binding from this entity"
304
305
  };
306
+ unbind.AddToClassList("ecs-action-button");
305
307
  unbind.SetEnabled(currentView != null);
306
308
  field.RegisterValueChangedCallback(evt =>
307
309
  {
@@ -335,6 +337,12 @@ namespace Delta.ECS.Unity.Editor
335
337
  {
336
338
  return BuildComponentCard(descriptor, body =>
337
339
  {
340
+ if (descriptor.IsTag)
341
+ {
342
+ body.Add(CreateClassLabel("Tag · membership only", "ecs-empty-component"));
343
+ return;
344
+ }
345
+
338
346
  if (!_previewWorld.TryRead(authoring, descriptor, out ComponentSnapshot snapshot, out EcsReadError readError))
339
347
  {
340
348
  body.Add(new HelpBox($"Could not read component: {readError.Code}.", HelpBoxMessageType.Error));
@@ -343,7 +351,7 @@ namespace Delta.ECS.Unity.Editor
343
351
 
344
352
  DrawEditableValue(body, authoring, data, descriptor, snapshot.Value);
345
353
  },
346
- () => ResetComponent(authoring, data, descriptor),
354
+ descriptor.IsTag ? null : () => ResetComponent(authoring, data, descriptor),
347
355
  () => RemoveComponent(authoring, data, descriptor));
348
356
  }
349
357
 
@@ -366,6 +374,7 @@ namespace Delta.ECS.Unity.Editor
366
374
  private VisualElement BuildAddComponentMenu(EntityAuthoring authoring)
367
375
  {
368
376
  var button = new Button { text = "Add Component" };
377
+ button.AddToClassList("ecs-action-button");
369
378
  button.AddToClassList("ecs-add-component");
370
379
  HashSet<ulong> existingSchemas = authoring.Components
371
380
  .Select(GetSchemaId)
@@ -483,25 +492,26 @@ namespace Delta.ECS.Unity.Editor
483
492
  private void DrawEditableValue(VisualElement body, EntityAuthoring authoring, ComponentData data,
484
493
  ComponentDescriptor descriptor, object value)
485
494
  {
486
- FieldInfo[] fields = GetComponentFields(descriptor.ValueType);
487
- if (fields.Length == 0)
488
- {
489
- body.Add(CreateClassLabel("Component has no public fields.", "ecs-empty-component"));
490
- return;
491
- }
492
-
493
- for (int i = 0; i < fields.Length; i++)
494
- {
495
- FieldInfo field = fields[i];
496
- object current = field.GetValue(value);
497
- VisualElement control = CreateFieldControl(field, current, next =>
495
+ bool canWrite = (descriptor.Capabilities & ComponentCapabilities.Write) != 0
496
+ && descriptor.ValueType.IsValueType;
497
+ int previousChildCount = body.childCount;
498
+ ComponentPropertyBinding[] bindings = ComponentPropertyBagFields.Build(body, descriptor, value,
499
+ canWrite,
500
+ (path, next) =>
498
501
  {
499
- if (Equals(current, next)) return;
502
+ object updated = value;
503
+ if (!PropertyBagValueAccess.TrySetValue(ref updated, descriptor.ValueType, path, next))
504
+ {
505
+ Debug.LogWarning($"Could not edit a property on {descriptor.Name}: the property path is unavailable.", Authoring);
506
+ RefreshContent();
507
+ return;
508
+ }
509
+
510
+ if (Equals(updated, value)) return;
500
511
  Undo.RecordObject(Authoring, $"Edit {descriptor.Name}");
501
- field.SetValue(value, next);
502
- if (_previewWorld.TryWrite(authoring, data, descriptor, value, out EcsWriteError writeError))
512
+ if (_previewWorld.TryWrite(authoring, data, descriptor, updated, out EcsWriteError writeError))
503
513
  {
504
- current = next;
514
+ value = updated;
505
515
  MarkSceneDirty();
506
516
  }
507
517
  else
@@ -509,66 +519,13 @@ namespace Delta.ECS.Unity.Editor
509
519
  Debug.LogError($"Could not write {descriptor.Name}: {writeError.Code}.", Authoring);
510
520
  RefreshContent();
511
521
  }
512
- });
513
- body.Add(control);
514
- }
515
- }
522
+ },
523
+ (label, current, onChanged) => CreateEntityReferenceField(label, current, onChanged));
516
524
 
517
- private VisualElement CreateFieldControl(FieldInfo field, object value, Action<object> onChanged)
518
- {
519
- string label = ObjectNames.NicifyVariableName(field.Name);
520
- Type type = field.FieldType;
521
- if (type == typeof(float))
522
- {
523
- var fieldControl = new FloatField(label) { value = (float)value, isDelayed = true };
524
- AddInspectorFieldClasses(fieldControl);
525
- fieldControl.RegisterValueChangedCallback(evt => onChanged(evt.newValue));
526
- return fieldControl;
527
- }
528
-
529
- if (type == typeof(byte) || type == typeof(int))
530
- {
531
- var fieldControl = new IntegerField(label) { value = Convert.ToInt32(value), isDelayed = true };
532
- AddInspectorFieldClasses(fieldControl);
533
- fieldControl.RegisterValueChangedCallback(evt => onChanged(type == typeof(byte)
534
- ? (object)(byte)Mathf.Clamp(evt.newValue, byte.MinValue, byte.MaxValue)
535
- : evt.newValue));
536
- return fieldControl;
537
- }
538
-
539
- if (type == typeof(bool))
540
- {
541
- var fieldControl = new Toggle(label) { value = (bool)value };
542
- AddInspectorFieldClasses(fieldControl);
543
- fieldControl.RegisterValueChangedCallback(evt => onChanged(evt.newValue));
544
- return fieldControl;
545
- }
546
-
547
- if (type == typeof(float3))
548
- {
549
- float3 vector = (float3)value;
550
- var fieldControl = new Vector3Field(label) { value = new Vector3(vector.x, vector.y, vector.z) };
551
- AddInspectorFieldClasses(fieldControl);
552
- fieldControl.RegisterValueChangedCallback(evt => onChanged(new float3(evt.newValue.x, evt.newValue.y, evt.newValue.z)));
553
- return fieldControl;
554
- }
555
-
556
- if (type == typeof(Entity))
557
- {
558
- return CreateEntityReferenceField(label, (Entity)value, onChanged);
559
- }
560
-
561
- if (type.IsEnum)
525
+ if (bindings.Length == 0 && body.childCount == previousChildCount)
562
526
  {
563
- var fieldControl = new EnumField(label, (Enum)value);
564
- AddInspectorFieldClasses(fieldControl);
565
- fieldControl.RegisterValueChangedCallback(evt => onChanged(evt.newValue));
566
- return fieldControl;
527
+ body.Add(CreateClassLabel("Component has no exposed properties.", "ecs-empty-component"));
567
528
  }
568
-
569
- var unsupported = new Label($"{label} · Unsupported: {type.Name}");
570
- unsupported.AddToClassList("ecs-unsupported-field");
571
- return unsupported;
572
529
  }
573
530
 
574
531
  private VisualElement CreateEntityReferenceField(string label, Entity current, Action<object> onChanged)
@@ -640,13 +597,19 @@ namespace Delta.ECS.Unity.Editor
640
597
  {
641
598
  return BuildComponentCard(descriptor, body =>
642
599
  {
643
- if (!world.Integration.TryRead(entity, descriptor.Id, out ComponentSnapshot snapshot, out EcsReadError error))
600
+ if (descriptor.IsTag)
601
+ {
602
+ body.Add(CreateClassLabel("Tag · membership only", "ecs-empty-component"));
603
+ return;
604
+ }
605
+
606
+ if (!world.TryRead(entity, descriptor, out ComponentSnapshot snapshot, out EcsReadError error))
644
607
  {
645
608
  body.Add(new HelpBox($"Could not read component: {error.Code}.", HelpBoxMessageType.Error));
646
609
  return;
647
610
  }
648
611
 
649
- DrawReadOnlyValue(body, descriptor, snapshot.Value, world);
612
+ DrawRuntimeValue(body, world, entity, descriptor, snapshot);
650
613
  });
651
614
  }
652
615
 
@@ -654,7 +617,6 @@ namespace Delta.ECS.Unity.Editor
654
617
  {
655
618
  _componentItems.Clear();
656
619
  _componentItems.AddRange(_componentEntries);
657
- if (_authoringEntity != null) _componentItems.Add(default);
658
620
  _componentList.itemsSource = _componentItems;
659
621
  _componentList.Rebuild();
660
622
  }
@@ -662,19 +624,10 @@ namespace Delta.ECS.Unity.Editor
662
624
  private void BindComponentItem(VisualElement row, int index)
663
625
  {
664
626
  row.Clear();
665
- bool isAddButton = _authoringEntity != null && index == _componentEntries.Count;
666
- row.parent.parent.EnableInClassList("ecs-add-component-row", isAddButton);
667
- row.parent.parent.EnableInClassList("ecs-component-last-bound-row",
627
+ SetReorderableItemClass(row, "ecs-component-last-bound-row",
668
628
  _embedded && _target.IsRuntime && index == _componentEntries.Count - 1);
669
- row.EnableInClassList("ecs-component-row", !isAddButton);
670
- if (isAddButton)
671
- {
672
- row.userData = null;
673
- row.Add(BuildAddComponentMenu(_authoringEntity));
674
- return;
675
- }
676
-
677
629
  ComponentEntry entry = _componentItems[index];
630
+ row.EnableInClassList("ecs-component-row", true);
678
631
  row.userData = entry;
679
632
  row.Add(_target.IsRuntime
680
633
  ? BuildRuntimeComponentCard(_target.RuntimeWorld, _target.RuntimeEntity, entry.Descriptor.Value)
@@ -683,6 +636,20 @@ namespace Delta.ECS.Unity.Editor
683
636
  : BuildUnknownComponentCard(_authoringEntity, entry.Data));
684
637
  }
685
638
 
639
+ private void SetReorderableItemClass(VisualElement row, string className, bool enabled)
640
+ {
641
+ for (VisualElement ancestor = row.parent; ancestor != null && ancestor != _componentList; ancestor = ancestor.parent)
642
+ {
643
+ if (ancestor.Q<VisualElement>(className: "unity-list-view__reorderable-handle") == null)
644
+ {
645
+ continue;
646
+ }
647
+
648
+ ancestor.EnableInClassList(className, enabled);
649
+ return;
650
+ }
651
+ }
652
+
686
653
  private void UnbindComponentItem(VisualElement row, int index)
687
654
  {
688
655
  if (row.userData is ComponentEntry entry && entry.Descriptor.HasValue)
@@ -752,7 +719,7 @@ namespace Delta.ECS.Unity.Editor
752
719
  {
753
720
  ReadOnlyMemory<ComponentDescriptor> catalog = world.Integration.Catalog.Components;
754
721
  _runtimeComponentBuffer = new ComponentId[catalog.Length];
755
- if (!world.Integration.TryGetComponents(entity, _runtimeComponentBuffer, out int count))
722
+ if (!world.TryGetComponents(entity, _runtimeComponentBuffer, out int count))
756
723
  {
757
724
  _runtimeComponentIds = null;
758
725
  return null;
@@ -794,31 +761,113 @@ namespace Delta.ECS.Unity.Editor
794
761
  return card;
795
762
  }
796
763
 
797
- private void DrawReadOnlyValue(VisualElement body, ComponentDescriptor descriptor, object value, SceneWorld world)
764
+ private void DrawRuntimeValue(VisualElement body, SceneWorld world, Entity entity,
765
+ ComponentDescriptor descriptor, ComponentSnapshot snapshot)
798
766
  {
799
- FieldInfo[] fields = GetComponentFields(descriptor.ValueType);
800
- if (fields.Length == 0)
767
+ bool canWrite = (descriptor.Capabilities & ComponentCapabilities.Write) != 0
768
+ && descriptor.ValueType.IsValueType;
769
+ int previousChildCount = body.childCount;
770
+ ComponentPropertyBinding[] properties = ComponentPropertyBagFields.Build(body, descriptor,
771
+ snapshot.Value, canWrite,
772
+ (path, next) => WriteRuntimeField(world, entity, descriptor, path, next),
773
+ (label, current, onChanged) => CreateRuntimeEntityReferenceField(world, label, current, onChanged));
774
+
775
+ if (properties.Length > 0)
801
776
  {
802
- body.Add(CreateClassLabel("Component has no public fields.", "ecs-empty-component"));
777
+ _runtimeBindings.Add(new RuntimeValueBinding(descriptor, properties));
778
+ }
779
+ else if (body.childCount == previousChildCount)
780
+ {
781
+ body.Add(CreateClassLabel("Component has no exposed properties.", "ecs-empty-component"));
782
+ }
783
+ }
784
+
785
+ private VisualElement CreateRuntimeEntityReferenceField(SceneWorld world, string label, Entity current,
786
+ Action<object> onChanged)
787
+ {
788
+ Entity[] authored = world.AuthoredEntities;
789
+ var values = new List<Entity>(authored.Length + 2) { default };
790
+ var options = new List<string>(authored.Length + 2) { "None" };
791
+ var names = new List<string>(authored.Length);
792
+ for (int i = 0; i < authored.Length; i++)
793
+ {
794
+ Entity candidate = authored[i];
795
+ if (!world.Integration.IsAlive(candidate)) continue;
796
+ names.Add(GetRuntimeEntityName(world, candidate));
797
+ }
798
+
799
+ HashSet<string> duplicateNames = names
800
+ .GroupBy(name => name, StringComparer.Ordinal)
801
+ .Where(group => group.Count() > 1)
802
+ .Select(group => group.Key)
803
+ .ToHashSet(StringComparer.Ordinal);
804
+
805
+ int currentIndex = current.IsValid ? -1 : 0;
806
+ int nameIndex = 0;
807
+ for (int i = 0; i < authored.Length; i++)
808
+ {
809
+ Entity candidate = authored[i];
810
+ if (!world.Integration.IsAlive(candidate)) continue;
811
+ string name = names[nameIndex++];
812
+ string stableId = world.TryGetStableId(candidate, out string id) ? id : string.Empty;
813
+ values.Add(candidate);
814
+ options.Add(duplicateNames.Contains(name) && !string.IsNullOrEmpty(stableId)
815
+ ? $"{name} ({stableId.Substring(0, Math.Min(8, stableId.Length))})"
816
+ : name);
817
+ if (candidate == current) currentIndex = values.Count - 1;
818
+ }
819
+
820
+ if (current.IsValid && currentIndex < 0)
821
+ {
822
+ values.Add(current);
823
+ options.Add($"Current ({FormatValue(typeof(Entity), current, world)})");
824
+ currentIndex = values.Count - 1;
825
+ }
826
+
827
+ var fieldControl = new DropdownField(label, options, currentIndex);
828
+ AddInspectorFieldClasses(fieldControl);
829
+ fieldControl.userData = new RuntimeEntityReferenceChoices(options.ToArray(), values.ToArray());
830
+ fieldControl.RegisterValueChangedCallback(evt =>
831
+ {
832
+ int index = options.IndexOf(evt.newValue);
833
+ Entity next = index >= 0 && index < values.Count ? values[index] : default;
834
+ onChanged(next);
835
+ });
836
+ return fieldControl;
837
+ }
838
+
839
+ private string GetRuntimeEntityName(SceneWorld world, Entity entity)
840
+ {
841
+ return world.TryGetStableId(entity, out string stableId)
842
+ && world.TryGetAuthoring(stableId, out EntityAuthoring authoring)
843
+ ? authoring.Name
844
+ : entity.ToString();
845
+ }
846
+
847
+ private void WriteRuntimeField(SceneWorld world, Entity entity, ComponentDescriptor descriptor,
848
+ string[] path, object next)
849
+ {
850
+ if (!world.Integration.TryRead(entity, descriptor.Id, out ComponentSnapshot snapshot, out EcsReadError readError))
851
+ {
852
+ Debug.LogWarning($"Could not read {descriptor.Name} before editing: {readError.Code}.");
853
+ RefreshRuntimeView();
803
854
  return;
804
855
  }
805
856
 
806
- var labels = new TextField[fields.Length];
807
- for (int i = 0; i < fields.Length; i++)
857
+ object updated = snapshot.Value;
858
+ if (!PropertyBagValueAccess.TrySetValue(ref updated, descriptor.ValueType, path, next))
808
859
  {
809
- FieldInfo field = fields[i];
810
- object fieldValue = field.GetValue(value);
811
- string display = FormatValue(field.FieldType, fieldValue, world);
812
- labels[i] = new TextField(ObjectNames.NicifyVariableName(field.Name))
813
- {
814
- value = display,
815
- isReadOnly = true
816
- };
817
- AddInspectorFieldClasses(labels[i]);
818
- body.Add(labels[i]);
860
+ Debug.LogWarning($"Could not edit {descriptor.Name}: the property path is unavailable.");
861
+ RefreshRuntimeView();
862
+ return;
819
863
  }
820
864
 
821
- _runtimeBindings.Add(new RuntimeValueBinding(descriptor, fields, labels));
865
+ if (!world.Integration.TryWrite(entity, descriptor.Id, updated, snapshot.Stamp,
866
+ out _, out EcsWriteError writeError))
867
+ {
868
+ Debug.LogWarning($"Could not edit {descriptor.Name}: {writeError.Code}.");
869
+ RefreshRuntimeView();
870
+ }
822
871
  }
823
872
 
824
873
  private string FormatValue(Type type, object value, SceneWorld world)
@@ -842,9 +891,6 @@ namespace Delta.ECS.Unity.Editor
842
891
  return value?.ToString() ?? "None";
843
892
  }
844
893
 
845
- private static FieldInfo[] GetComponentFields(Type type) =>
846
- type.GetFields(BindingFlags.Instance | BindingFlags.Public);
847
-
848
894
  private static Label CreateClassLabel(string text, string className)
849
895
  {
850
896
  var label = new Label(text);
@@ -887,7 +933,7 @@ namespace Delta.ECS.Unity.Editor
887
933
  return;
888
934
  }
889
935
 
890
- if (!world.Integration.TryGetComponents(entity, _runtimeComponentBuffer, out int count)
936
+ if (!world.TryGetComponents(entity, _runtimeComponentBuffer, out int count)
891
937
  || count != _runtimeComponentIds.Length)
892
938
  {
893
939
  RefreshContent();
@@ -911,18 +957,93 @@ namespace Delta.ECS.Unity.Editor
911
957
  continue;
912
958
  }
913
959
 
914
- for (int fieldIndex = 0; fieldIndex < binding.Fields.Length; fieldIndex++)
960
+ for (int fieldIndex = 0; fieldIndex < binding.Properties.Length; fieldIndex++)
915
961
  {
916
- FieldInfo field = binding.Fields[fieldIndex];
917
- string text = FormatValue(field.FieldType, field.GetValue(snapshot.Value), world);
918
- if (!string.Equals(binding.Labels[fieldIndex].value, text, StringComparison.Ordinal))
962
+ ComponentPropertyBinding property = binding.Properties[fieldIndex];
963
+ VisualElement control = property.Control;
964
+ VisualElement focused = control.panel?.focusController?.focusedElement as VisualElement;
965
+ if (focused != null && control.Contains(focused))
966
+ {
967
+ continue;
968
+ }
969
+
970
+ if (PropertyBagValueAccess.TryGetValue(snapshot.Value, binding.Descriptor.ValueType,
971
+ property.Path, out object value))
919
972
  {
920
- binding.Labels[fieldIndex].SetValueWithoutNotify(text);
973
+ SetRuntimeFieldValue(control, property.ValueType, value, world);
921
974
  }
922
975
  }
923
976
  }
924
977
  }
925
978
 
979
+ private void SetRuntimeFieldValue(VisualElement control, Type type, object value, SceneWorld world)
980
+ {
981
+ if (control is FloatField floatField)
982
+ {
983
+ floatField.SetValueWithoutNotify(value == null ? 0f : (float)value);
984
+ }
985
+ else if (control is DoubleField doubleField)
986
+ {
987
+ doubleField.SetValueWithoutNotify(value == null ? 0d : (double)value);
988
+ }
989
+ else if (control is TextField textField)
990
+ {
991
+ textField.SetValueWithoutNotify(type == typeof(string) ? (string)value ?? string.Empty
992
+ : type == typeof(char) ? value == null ? string.Empty : value.ToString()
993
+ : FormatValue(type, value, world));
994
+ }
995
+ else if (control is IntegerField integerField)
996
+ {
997
+ integerField.SetValueWithoutNotify(value == null ? 0 : Convert.ToInt32(value));
998
+ }
999
+ else if (control is LongField longField)
1000
+ {
1001
+ longField.SetValueWithoutNotify(value == null ? 0L : Convert.ToInt64(value));
1002
+ }
1003
+ else if (control is Toggle toggle)
1004
+ {
1005
+ toggle.SetValueWithoutNotify(value != null && (bool)value);
1006
+ }
1007
+ else if (control is Vector2Field vector2Field && value is Vector2 vector2)
1008
+ {
1009
+ vector2Field.SetValueWithoutNotify(vector2);
1010
+ }
1011
+ else if (control is Vector3Field vectorField && value is Vector3 vector3)
1012
+ {
1013
+ vectorField.SetValueWithoutNotify(vector3);
1014
+ }
1015
+ else if (control is Vector3Field float3Field && value is float3 vector)
1016
+ {
1017
+ float3Field.SetValueWithoutNotify(new Vector3(vector.x, vector.y, vector.z));
1018
+ }
1019
+ else if (control is Vector4Field vector4Field && value is Vector4 vector4)
1020
+ {
1021
+ vector4Field.SetValueWithoutNotify(vector4);
1022
+ }
1023
+ else if (control is ColorField colorField && value is Color color)
1024
+ {
1025
+ colorField.SetValueWithoutNotify(color);
1026
+ }
1027
+ else if (control is EnumField enumField && value is Enum enumValue)
1028
+ {
1029
+ enumField.SetValueWithoutNotify(enumValue);
1030
+ }
1031
+ else if (control is ObjectField objectField)
1032
+ {
1033
+ objectField.SetValueWithoutNotify(value as UnityEngine.Object);
1034
+ }
1035
+ else if (control is DropdownField entityField
1036
+ && type == typeof(Entity)
1037
+ && entityField.userData is RuntimeEntityReferenceChoices choices)
1038
+ {
1039
+ int index = Array.IndexOf(choices.Entities, (Entity)value);
1040
+ if (index >= 0)
1041
+ {
1042
+ entityField.SetValueWithoutNotify(choices.Labels[index]);
1043
+ }
1044
+ }
1045
+ }
1046
+
926
1047
  private ComponentEntry[] ProjectAuthoringComponents(EntityAuthoring authoring)
927
1048
  {
928
1049
  Dictionary<ulong, ComponentDescriptor> descriptors = _previewWorld.Integration.Catalog.Components
@@ -1089,14 +1210,24 @@ namespace Delta.ECS.Unity.Editor
1089
1210
  private readonly struct RuntimeValueBinding
1090
1211
  {
1091
1212
  public readonly ComponentDescriptor Descriptor;
1092
- public readonly FieldInfo[] Fields;
1093
- public readonly TextField[] Labels;
1213
+ public readonly ComponentPropertyBinding[] Properties;
1094
1214
 
1095
- public RuntimeValueBinding(ComponentDescriptor descriptor, FieldInfo[] fields, TextField[] labels)
1215
+ public RuntimeValueBinding(ComponentDescriptor descriptor, ComponentPropertyBinding[] properties)
1096
1216
  {
1097
1217
  Descriptor = descriptor;
1098
- Fields = fields;
1218
+ Properties = properties;
1219
+ }
1220
+ }
1221
+
1222
+ private sealed class RuntimeEntityReferenceChoices
1223
+ {
1224
+ public readonly string[] Labels;
1225
+ public readonly Entity[] Entities;
1226
+
1227
+ public RuntimeEntityReferenceChoices(string[] labels, Entity[] entities)
1228
+ {
1099
1229
  Labels = labels;
1230
+ Entities = entities;
1100
1231
  }
1101
1232
  }
1102
1233
  }
package/Editor.meta ADDED
@@ -0,0 +1,8 @@
1
+ fileFormatVersion: 2
2
+ guid: 51f385a11fe94398b8d8db41a03ab731
3
+ folderAsset: yes
4
+ DefaultImporter:
5
+ externalObjects: {}
6
+ userData:
7
+ assetBundleName:
8
+ assetBundleVariant:
package/README.md CHANGED
@@ -18,7 +18,7 @@ Add the npm-compatible registry and package to the Unity project's
18
18
  }
19
19
  ],
20
20
  "dependencies": {
21
- "com.artromskiy.deltaecs.unity": "0.0.37"
21
+ "com.artromskiy.deltaecs.unity": "0.0.39"
22
22
  }
23
23
  }
24
24
  ```
@@ -1,6 +1,5 @@
1
1
  using System;
2
2
  using System.Collections.Generic;
3
- using System.Reflection;
4
3
  using Delta.ECS;
5
4
  using Delta.ECS.Integration;
6
5
  using UnityEngine;
@@ -47,19 +46,16 @@ namespace Delta.ECS.Unity
47
46
  value = Activator.CreateInstance(componentType);
48
47
  }
49
48
 
50
- FieldInfo[] fields = componentType.GetFields(BindingFlags.Instance | BindingFlags.Public);
51
49
  List<EntityReference> references = EntityReferenceList;
52
50
  for (int i = 0; i < references.Count; i++)
53
51
  {
54
52
  EntityReference reference = references[i];
55
- for (int fieldIndex = 0; fieldIndex < fields.Length; fieldIndex++)
53
+ object resolvedValue = resolveEntity(reference.TargetEntityId);
54
+ object current = value;
55
+ if (PropertyBagValueAccess.TrySetValue(ref current, componentType,
56
+ PropertyBagValueAccess.ParsePath(reference.FieldName), resolvedValue))
56
57
  {
57
- FieldInfo field = fields[fieldIndex];
58
- if (field.Name == reference.FieldName && field.FieldType == typeof(Entity))
59
- {
60
- field.SetValue(value, resolveEntity(reference.TargetEntityId));
61
- break;
62
- }
58
+ value = current;
63
59
  }
64
60
  }
65
61
 
@@ -75,23 +71,13 @@ namespace Delta.ECS.Unity
75
71
 
76
72
  _json = JsonUtility.ToJson(value);
77
73
  EntityReferenceList.Clear();
74
+ PropertyBagValueAccess.CollectEntityReferences(value, value.GetType(), stableIdResolver, EntityReferenceList);
75
+ }
78
76
 
79
- FieldInfo[] fields = value.GetType().GetFields(BindingFlags.Instance | BindingFlags.Public);
80
- for (int i = 0; i < fields.Length; i++)
81
- {
82
- FieldInfo field = fields[i];
83
- if (field.FieldType != typeof(Entity))
84
- {
85
- continue;
86
- }
87
-
88
- Entity target = (Entity)field.GetValue(value);
89
- string targetId = stableIdResolver(target) ?? string.Empty;
90
- if (!string.IsNullOrEmpty(targetId))
91
- {
92
- EntityReferenceList.Add(new EntityReference(field.Name, targetId));
93
- }
94
- }
77
+ public void StoreDefaultTag()
78
+ {
79
+ _json = "{}";
80
+ EntityReferenceList.Clear();
95
81
  }
96
82
 
97
83
  public string GetEntityReference(string fieldName)
@@ -113,6 +99,11 @@ namespace Delta.ECS.Unity
113
99
 
114
100
  public static ComponentData CreateDefault(ComponentDescriptor descriptor)
115
101
  {
102
+ if (descriptor.IsTag)
103
+ {
104
+ return new ComponentData(descriptor.Schema.Value, "{}");
105
+ }
106
+
116
107
  object value = Activator.CreateInstance(descriptor.ValueType);
117
108
  return new ComponentData(descriptor.Schema.Value, JsonUtility.ToJson(value));
118
109
  }