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 CHANGED
@@ -1,5 +1,9 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.0.39
4
+
5
+ - Published with the matching DeltaECS NuGet packages.
6
+
3
7
  ## 0.0.38
4
8
 
5
9
  - Align the Unity integration release with the DeltaECS 0.0.38 NuGet packages.
@@ -0,0 +1,7 @@
1
+ fileFormatVersion: 2
2
+ guid: 1db0f7b3d49f411c925b360d9bf72de4
3
+ TextScriptImporter:
4
+ externalObjects: {}
5
+ userData:
6
+ assetBundleName:
7
+ assetBundleVariant:
@@ -20,7 +20,9 @@ namespace Delta.ECS.Unity.Editor
20
20
  return null;
21
21
  }
22
22
 
23
- if (objects == null || objects.Length != 1 || objects[0] is not GameObject gameObject)
23
+ if (objects == null || objects.Length != 1
24
+ || objects[0] is not GameObject gameObject
25
+ || gameObject == null)
24
26
  {
25
27
  return null;
26
28
  }
@@ -43,6 +45,11 @@ namespace Delta.ECS.Unity.Editor
43
45
 
44
46
  internal static UnityEditor.Editor CreateDefaultGameObjectEditor(GameObject gameObject)
45
47
  {
48
+ if (gameObject == null)
49
+ {
50
+ return null;
51
+ }
52
+
46
53
  _creatingDefaultGameObjectEditor = true;
47
54
  try
48
55
  {
@@ -68,7 +75,7 @@ namespace Delta.ECS.Unity.Editor
68
75
 
69
76
  private void OnEnable()
70
77
  {
71
- if (target is GameObject gameObject)
78
+ if (target is GameObject gameObject && gameObject != null)
72
79
  {
73
80
  _gameObjectEditor = BoundEntityRootEditorSelector.CreateDefaultGameObjectEditor(gameObject);
74
81
  }
@@ -143,10 +150,7 @@ namespace Delta.ECS.Unity.Editor
143
150
  {
144
151
  root.Add(new IMGUIContainer(() =>
145
152
  {
146
- if (_gameObjectEditor != null)
147
- {
148
- _gameObjectEditor.DrawHeader();
149
- }
153
+ DrawGameObjectHeader(_gameObjectEditor);
150
154
  }));
151
155
  }
152
156
 
@@ -182,6 +186,19 @@ namespace Delta.ECS.Unity.Editor
182
186
  return root;
183
187
  }
184
188
 
189
+ private void DrawGameObjectHeader(UnityEditor.Editor gameObjectEditor)
190
+ {
191
+ if (gameObjectEditor == null
192
+ || target is not GameObject gameObject
193
+ || gameObject == null
194
+ || gameObjectEditor.target == null)
195
+ {
196
+ return;
197
+ }
198
+
199
+ gameObjectEditor.DrawHeader();
200
+ }
201
+
185
202
  private void RefreshComponentInspectors()
186
203
  {
187
204
  if (_componentInspectorRoot != null && !HaveSameComponents())
@@ -0,0 +1,280 @@
1
+ using System;
2
+ using System.Collections.Generic;
3
+ using Delta;
4
+ using Delta.ECS;
5
+ using Delta.ECS.Integration;
6
+ using Delta.ECS.Unity;
7
+ using Unity.Properties;
8
+ using UnityEditor;
9
+ using UnityEditor.UIElements;
10
+ using UnityEngine;
11
+ using UnityEngine.UIElements;
12
+
13
+ namespace Delta.ECS.Unity.Editor
14
+ {
15
+ internal readonly struct ComponentPropertyBinding
16
+ {
17
+ internal readonly string[] Path;
18
+ internal readonly Type ValueType;
19
+ internal readonly VisualElement Control;
20
+
21
+ internal ComponentPropertyBinding(string[] path, Type valueType, VisualElement control)
22
+ {
23
+ Path = path;
24
+ ValueType = valueType;
25
+ Control = control;
26
+ }
27
+ }
28
+
29
+ internal static class ComponentPropertyBagFields
30
+ {
31
+ internal static ComponentPropertyBinding[] Build(VisualElement parent, ComponentDescriptor descriptor,
32
+ object value, bool canWrite, Action<string[], object> onChanged,
33
+ Func<string, Entity, Action<object>, VisualElement> createEntityField)
34
+ {
35
+ if (value == null)
36
+ {
37
+ return Array.Empty<ComponentPropertyBinding>();
38
+ }
39
+
40
+ IPropertyBag propertyBag = PropertyBag.GetPropertyBag(descriptor.ValueType);
41
+ if (propertyBag == null)
42
+ {
43
+ return Array.Empty<ComponentPropertyBinding>();
44
+ }
45
+
46
+ var bindings = new List<ComponentPropertyBinding>();
47
+ var visitor = new PropertyFieldVisitor(parent, canWrite, Array.Empty<string>(), 0,
48
+ bindings, onChanged, createEntityField);
49
+ propertyBag.Accept(visitor, ref value);
50
+ return bindings.ToArray();
51
+ }
52
+
53
+ private sealed class PropertyFieldVisitor : IPropertyBagVisitor, IPropertyVisitor
54
+ {
55
+ private readonly VisualElement _parent;
56
+ private readonly bool _canWrite;
57
+ private readonly string[] _path;
58
+ private readonly int _depth;
59
+ private readonly List<ComponentPropertyBinding> _bindings;
60
+ private readonly Action<string[], object> _onChanged;
61
+ private readonly Func<string, Entity, Action<object>, VisualElement> _createEntityField;
62
+
63
+ internal PropertyFieldVisitor(VisualElement parent, bool canWrite, string[] path, int depth,
64
+ List<ComponentPropertyBinding> bindings, Action<string[], object> onChanged,
65
+ Func<string, Entity, Action<object>, VisualElement> createEntityField)
66
+ {
67
+ _parent = parent;
68
+ _canWrite = canWrite;
69
+ _path = path;
70
+ _depth = depth;
71
+ _bindings = bindings;
72
+ _onChanged = onChanged;
73
+ _createEntityField = createEntityField;
74
+ }
75
+
76
+ public void Visit<TContainer>(IPropertyBag<TContainer> properties, ref TContainer container)
77
+ {
78
+ foreach (var property in properties.GetProperties(ref container))
79
+ {
80
+ ((IPropertyAccept<TContainer>)property).Accept(this, ref container);
81
+ }
82
+ }
83
+
84
+ public void Visit<TContainer, TValue>(Property<TContainer, TValue> property, ref TContainer container)
85
+ {
86
+ TValue value = property.GetValue(ref container);
87
+ Type valueType = typeof(TValue);
88
+ string[] path = Append(_path, property.Name);
89
+ string label = GetLabel(property.Name);
90
+ bool canWrite = _canWrite && !property.IsReadOnly;
91
+
92
+ VisualElement control = CreateFieldControl(label, valueType, value,
93
+ next => _onChanged(path, next), canWrite, _createEntityField);
94
+ if (control != null)
95
+ {
96
+ _parent.Add(control);
97
+ _bindings.Add(new ComponentPropertyBinding(path, valueType, control));
98
+ return;
99
+ }
100
+
101
+ if (value != null && _depth < 24)
102
+ {
103
+ object nestedValue = value;
104
+ IPropertyBag nestedBag = PropertyBag.GetPropertyBag(nestedValue.GetType());
105
+ if (nestedBag != null)
106
+ {
107
+ var foldout = new Foldout { text = label, value = true };
108
+ foldout.AddToClassList("ecs-property-foldout");
109
+ _parent.Add(foldout);
110
+ int previousCount = _bindings.Count;
111
+ bool canWriteNested = canWrite && valueType.IsValueType;
112
+ var nestedVisitor = new PropertyFieldVisitor(foldout, canWriteNested, path,
113
+ _depth + 1, _bindings, _onChanged, _createEntityField);
114
+ nestedBag.Accept(nestedVisitor, ref nestedValue);
115
+ if (_bindings.Count == previousCount)
116
+ {
117
+ var empty = new Label("No exposed properties.");
118
+ empty.AddToClassList("ecs-empty-component");
119
+ foldout.Add(empty);
120
+ }
121
+
122
+ return;
123
+ }
124
+ }
125
+
126
+ string detail = value == null ? "Null" : $"Unsupported: {valueType.Name}";
127
+ var unsupported = new Label($"{label} · {detail}");
128
+ unsupported.AddToClassList("ecs-unsupported-field");
129
+ _parent.Add(unsupported);
130
+ }
131
+ }
132
+
133
+ private static VisualElement CreateFieldControl(string label, Type type, object value,
134
+ Action<object> onChanged, bool canWrite,
135
+ Func<string, Entity, Action<object>, VisualElement> createEntityField)
136
+ {
137
+ VisualElement control;
138
+ if (type == typeof(float))
139
+ {
140
+ var field = new FloatField(label) { value = value == null ? 0f : (float)value, isDelayed = true };
141
+ field.RegisterValueChangedCallback(evt => onChanged(evt.newValue));
142
+ control = field;
143
+ }
144
+ else if (type == typeof(double))
145
+ {
146
+ var field = new DoubleField(label) { value = value == null ? 0d : (double)value, isDelayed = true };
147
+ field.RegisterValueChangedCallback(evt => onChanged(evt.newValue));
148
+ control = field;
149
+ }
150
+ else if (type == typeof(string))
151
+ {
152
+ var field = new TextField(label) { value = (string)value ?? string.Empty, isDelayed = true };
153
+ field.RegisterValueChangedCallback(evt => onChanged(evt.newValue));
154
+ control = field;
155
+ }
156
+ else if (type == typeof(char))
157
+ {
158
+ var field = new TextField(label) { value = value == null ? string.Empty : value.ToString(), isDelayed = true };
159
+ field.RegisterValueChangedCallback(evt => onChanged(string.IsNullOrEmpty(evt.newValue) ? '\0' : evt.newValue[0]));
160
+ control = field;
161
+ }
162
+ else if (type == typeof(byte) || type == typeof(sbyte) || type == typeof(short)
163
+ || type == typeof(ushort) || type == typeof(int))
164
+ {
165
+ var field = new IntegerField(label) { value = value == null ? 0 : Convert.ToInt32(value), isDelayed = true };
166
+ field.RegisterValueChangedCallback(evt => onChanged(ConvertInteger(type, evt.newValue)));
167
+ control = field;
168
+ }
169
+ else if (type == typeof(uint) || type == typeof(long))
170
+ {
171
+ var field = new LongField(label) { value = value == null ? 0L : Convert.ToInt64(value), isDelayed = true };
172
+ field.RegisterValueChangedCallback(evt => onChanged(type == typeof(uint)
173
+ ? (object)(uint)Math.Max(0L, Math.Min(uint.MaxValue, evt.newValue))
174
+ : evt.newValue));
175
+ control = field;
176
+ }
177
+ else if (type == typeof(ulong))
178
+ {
179
+ var field = new TextField(label) { value = value == null ? "0" : ((ulong)value).ToString(), isDelayed = true };
180
+ field.RegisterValueChangedCallback(evt =>
181
+ {
182
+ if (ulong.TryParse(evt.newValue, out ulong parsed)) onChanged(parsed);
183
+ });
184
+ control = field;
185
+ }
186
+ else if (type == typeof(bool))
187
+ {
188
+ var field = new Toggle(label) { value = value != null && (bool)value };
189
+ field.RegisterValueChangedCallback(evt => onChanged(evt.newValue));
190
+ control = field;
191
+ }
192
+ else if (type == typeof(float3))
193
+ {
194
+ float3 vector = value == null ? default : (float3)value;
195
+ var field = new Vector3Field(label) { value = new Vector3(vector.x, vector.y, vector.z) };
196
+ field.RegisterValueChangedCallback(evt => onChanged(new float3(evt.newValue.x, evt.newValue.y, evt.newValue.z)));
197
+ control = field;
198
+ }
199
+ else if (type == typeof(Vector2))
200
+ {
201
+ var field = new Vector2Field(label) { value = value == null ? default : (Vector2)value };
202
+ field.RegisterValueChangedCallback(evt => onChanged(evt.newValue));
203
+ control = field;
204
+ }
205
+ else if (type == typeof(Vector3))
206
+ {
207
+ var field = new Vector3Field(label) { value = value == null ? default : (Vector3)value };
208
+ field.RegisterValueChangedCallback(evt => onChanged(evt.newValue));
209
+ control = field;
210
+ }
211
+ else if (type == typeof(Vector4))
212
+ {
213
+ var field = new Vector4Field(label) { value = value == null ? default : (Vector4)value };
214
+ field.RegisterValueChangedCallback(evt => onChanged(evt.newValue));
215
+ control = field;
216
+ }
217
+ else if (type == typeof(Color))
218
+ {
219
+ var field = new ColorField(label) { value = value == null ? default : (Color)value };
220
+ field.RegisterValueChangedCallback(evt => onChanged(evt.newValue));
221
+ control = field;
222
+ }
223
+ else if (type == typeof(Entity))
224
+ {
225
+ Entity current = value == null ? default : (Entity)value;
226
+ control = createEntityField(label, current, onChanged);
227
+ }
228
+ else if (type.IsEnum)
229
+ {
230
+ var field = new EnumField(label, (Enum)value);
231
+ field.RegisterValueChangedCallback(evt => onChanged(evt.newValue));
232
+ control = field;
233
+ }
234
+ else if (typeof(UnityEngine.Object).IsAssignableFrom(type))
235
+ {
236
+ var field = new ObjectField(label)
237
+ {
238
+ objectType = type,
239
+ allowSceneObjects = true,
240
+ value = value as UnityEngine.Object
241
+ };
242
+ field.RegisterValueChangedCallback(evt => onChanged(evt.newValue));
243
+ control = field;
244
+ }
245
+ else
246
+ {
247
+ return null;
248
+ }
249
+
250
+ control.AddToClassList(BaseField<float>.alignedFieldUssClassName);
251
+ control.AddToClassList("ecs-value-field");
252
+ control.SetEnabled(canWrite);
253
+ return control;
254
+ }
255
+
256
+ private static object ConvertInteger(Type type, int value)
257
+ {
258
+ if (type == typeof(byte)) return (byte)Mathf.Clamp(value, byte.MinValue, byte.MaxValue);
259
+ if (type == typeof(sbyte)) return (sbyte)Mathf.Clamp(value, sbyte.MinValue, sbyte.MaxValue);
260
+ if (type == typeof(short)) return (short)Mathf.Clamp(value, short.MinValue, short.MaxValue);
261
+ if (type == typeof(ushort)) return (ushort)Mathf.Clamp(value, ushort.MinValue, ushort.MaxValue);
262
+ return value;
263
+ }
264
+
265
+ private static string[] Append(string[] path, string name)
266
+ {
267
+ var result = new string[path.Length + 1];
268
+ Array.Copy(path, result, path.Length);
269
+ result[path.Length] = name;
270
+ return result;
271
+ }
272
+
273
+ private static string GetLabel(string name)
274
+ {
275
+ return int.TryParse(name, out int index)
276
+ ? $"Element {index}"
277
+ : ObjectNames.NicifyVariableName(name);
278
+ }
279
+ }
280
+ }
@@ -0,0 +1,2 @@
1
+ fileFormatVersion: 2
2
+ guid: f7962dd16f630406081c0af7d11bd0ab
@@ -81,12 +81,6 @@
81
81
  border-bottom-color: var(--unity-colors-inspector_titlebar-border_accent);
82
82
  }
83
83
 
84
- .ecs-component-list .ecs-add-component-row,
85
- .ecs-component-list .ecs-add-component-row:hover,
86
- .ecs-component-list .ecs-add-component-row:selected {
87
- border-bottom-width: 0;
88
- }
89
-
90
84
  .ecs-component-list .ecs-component-last-bound-row,
91
85
  .ecs-component-list .ecs-component-last-bound-row:hover,
92
86
  .ecs-component-list .ecs-component-last-bound-row:selected {
@@ -97,10 +91,6 @@
97
91
  background-color: var(--unity-colors-inspector_titlebar-background-hover);
98
92
  }
99
93
 
100
- .ecs-add-component-row > .unity-list-view__reorderable-handle {
101
- display: none;
102
- }
103
-
104
94
  .ecs-entity-header {
105
95
  margin-bottom: 4px;
106
96
  }
@@ -132,8 +122,8 @@
132
122
  }
133
123
 
134
124
  .ecs-view-binding {
135
- flex-direction: row;
136
- align-items: center;
125
+ flex-direction: column;
126
+ align-items: stretch;
137
127
  margin-top: 6px;
138
128
  }
139
129
 
@@ -143,7 +133,8 @@
143
133
  }
144
134
 
145
135
  .ecs-view-binding > .unity-button {
146
- margin-left: 4px;
136
+ margin-top: 4px;
137
+ margin-left: 0;
147
138
  }
148
139
 
149
140
  .ecs-entity-metadata {
@@ -269,10 +260,18 @@
269
260
  font-size: 14px;
270
261
  }
271
262
 
272
- .ecs-add-component {
273
- width: 230px;
263
+ .ecs-action-button {
264
+ width: 100%;
265
+ min-width: 0;
274
266
  height: 24px;
275
- align-self: center;
267
+ min-height: 24px;
268
+ max-height: 24px;
269
+ flex-grow: 1;
270
+ flex-shrink: 0;
271
+ }
272
+
273
+ .ecs-add-component {
274
+ align-self: stretch;
276
275
  margin-top: 5px;
277
276
  margin-bottom: 4px;
278
277
  }
@@ -1,5 +1,5 @@
1
1
  <ui:UXML xmlns:ui="UnityEngine.UIElements">
2
- <ui:Style src="DeltaEcsSceneAuthoringEditor.uss" />
2
+ <ui:Style src="SceneAuthoringEditor.uss" />
3
3
  <ui:VisualElement name="inspectorRoot" class="ecs-inspector-root">
4
4
  <ui:VisualElement name="inspectorHeader" class="ecs-inspector-header" />
5
5
  <ui:ListView name="componentList" class="ecs-component-list" virtualization-method="DynamicHeight" reorderable="true" reorder-mode="Animated" selection-type="None" />