com.artromskiy.deltaecs.unity 0.0.37
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 +6 -0
- package/Editor/BoundEntityRootEditor.cs +288 -0
- package/Editor/BoundEntityRootEditor.cs.meta +2 -0
- package/Editor/ComponentDropdown.cs +73 -0
- package/Editor/ComponentDropdown.cs.meta +2 -0
- package/Editor/ComponentListController.cs +26 -0
- package/Editor/ComponentListController.cs.meta +2 -0
- package/Editor/DeltaECS.Unity.Editor.asmdef +18 -0
- package/Editor/DeltaECS.Unity.Editor.asmdef.meta +7 -0
- package/Editor/EditorLifecycle.cs +143 -0
- package/Editor/EditorLifecycle.cs.meta +2 -0
- package/Editor/EntityInspectorTarget.cs +26 -0
- package/Editor/EntityInspectorTarget.cs.meta +3 -0
- package/Editor/HierarchyMenu.cs +85 -0
- package/Editor/HierarchyMenu.cs.meta +2 -0
- package/Editor/HierarchyNodeHandler.cs +950 -0
- package/Editor/HierarchyNodeHandler.cs.meta +2 -0
- package/Editor/HierarchySelection.cs +171 -0
- package/Editor/HierarchySelection.cs.meta +3 -0
- package/Editor/InspectorState.cs +220 -0
- package/Editor/InspectorState.cs.meta +2 -0
- package/Editor/Resources/Inspector/BoundEntityRootEditor.uss +28 -0
- package/Editor/Resources/Inspector/BoundEntityRootEditor.uss.meta +2 -0
- package/Editor/Resources/Inspector/SceneAuthoringEditor.uss +282 -0
- package/Editor/Resources/Inspector/SceneAuthoringEditor.uss.meta +12 -0
- package/Editor/Resources/Inspector/SceneAuthoringEditor.uxml +8 -0
- package/Editor/Resources/Inspector/SceneAuthoringEditor.uxml.meta +10 -0
- package/Editor/Resources/Inspector.meta +8 -0
- package/Editor/Resources.meta +8 -0
- package/Editor/SceneEntityInspectorView.cs +1103 -0
- package/Editor/SceneEntityInspectorView.cs.meta +2 -0
- package/Editor/SelectionProxy.cs +19 -0
- package/Editor/SelectionProxy.cs.meta +2 -0
- package/Editor/SelectionProxyBridge.cs +64 -0
- package/Editor/SelectionProxyBridge.cs.meta +2 -0
- package/Editor/SelectionProxyEditor.cs +33 -0
- package/Editor/SelectionProxyEditor.cs.meta +2 -0
- package/LICENSE.md +21 -0
- package/LICENSE.md.meta +7 -0
- package/README.md +66 -0
- package/README.md.meta +2 -0
- package/Runtime/AssemblyInfo.cs +3 -0
- package/Runtime/AssemblyInfo.cs.meta +2 -0
- package/Runtime/ComponentData.cs +120 -0
- package/Runtime/ComponentData.cs.meta +2 -0
- package/Runtime/DeltaECS.Unity.asmdef +14 -0
- package/Runtime/DeltaECS.Unity.asmdef.meta +7 -0
- package/Runtime/Editor.meta +8 -0
- package/Runtime/EntityAuthoring.cs +47 -0
- package/Runtime/EntityAuthoring.cs.meta +2 -0
- package/Runtime/EntityReference.cs +21 -0
- package/Runtime/EntityReference.cs.meta +2 -0
- package/Runtime/SceneAuthoring.cs +202 -0
- package/Runtime/SceneAuthoring.cs.meta +2 -0
- package/Runtime/SceneData.cs +120 -0
- package/Runtime/SceneData.cs.meta +2 -0
- package/Runtime/SceneWorld.cs +618 -0
- package/Runtime/SceneWorld.cs.meta +2 -0
- package/Runtime/ThrowHelpers.cs +44 -0
- package/Runtime/ThrowHelpers.cs.meta +2 -0
- package/package.json +31 -0
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
using UnityEngine;
|
|
2
|
+
|
|
3
|
+
namespace Delta.ECS.Unity.Editor
|
|
4
|
+
{
|
|
5
|
+
internal sealed class SelectionProxy : ScriptableObject
|
|
6
|
+
{
|
|
7
|
+
internal EntityInspectorTarget Target { get; private set; }
|
|
8
|
+
|
|
9
|
+
internal void SetTarget(EntityInspectorTarget target)
|
|
10
|
+
{
|
|
11
|
+
Target = target;
|
|
12
|
+
name = target.Authoring != null
|
|
13
|
+
? target.Authoring.SceneData.TryGetEntity(target.StableId, out EntityAuthoring authoring)
|
|
14
|
+
? authoring.Name
|
|
15
|
+
: "ECS Entity"
|
|
16
|
+
: $"Entity {target.RuntimeEntity.Index}";
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
using System.Collections.Generic;
|
|
2
|
+
using Unity.Hierarchy;
|
|
3
|
+
using UnityEditor;
|
|
4
|
+
using UnityEngine;
|
|
5
|
+
|
|
6
|
+
namespace Delta.ECS.Unity.Editor
|
|
7
|
+
{
|
|
8
|
+
[InitializeOnLoad]
|
|
9
|
+
internal static class SelectionProxyBridge
|
|
10
|
+
{
|
|
11
|
+
private static readonly Dictionary<(HierarchyNodeHandler Handler, HierarchyNode Node), SelectionProxy> Proxies = new();
|
|
12
|
+
|
|
13
|
+
static SelectionProxyBridge()
|
|
14
|
+
{
|
|
15
|
+
AssemblyReloadEvents.beforeAssemblyReload += DisposeAll;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
internal static EntityId GetEntityId(HierarchyNodeHandler handler, HierarchyNode node, EntityInspectorTarget target)
|
|
19
|
+
{
|
|
20
|
+
var key = (handler, node);
|
|
21
|
+
if (!Proxies.TryGetValue(key, out var proxy))
|
|
22
|
+
{
|
|
23
|
+
proxy = ScriptableObject.CreateInstance<SelectionProxy>();
|
|
24
|
+
proxy.hideFlags = HideFlags.DontSaveInEditor | HideFlags.DontSaveInBuild;
|
|
25
|
+
Proxies.Add(key, proxy);
|
|
26
|
+
}
|
|
27
|
+
proxy.SetTarget(target);
|
|
28
|
+
return proxy.GetEntityId();
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
internal static HierarchyNode GetNode(HierarchyNodeHandler handler, EntityId entityId)
|
|
32
|
+
{
|
|
33
|
+
foreach (var pair in Proxies)
|
|
34
|
+
if (pair.Key.Handler == handler && pair.Value.GetEntityId() == entityId)
|
|
35
|
+
return pair.Key.Node;
|
|
36
|
+
return HierarchyNode.Null;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
internal static void UpdateTarget(HierarchyNodeHandler handler, HierarchyNode node, EntityInspectorTarget target)
|
|
40
|
+
{
|
|
41
|
+
if (Proxies.TryGetValue((handler, node), out var proxy))
|
|
42
|
+
proxy.SetTarget(target);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
internal static void Select(HierarchyNodeHandler handler, HierarchyNode node, EntityInspectorTarget target)
|
|
46
|
+
{
|
|
47
|
+
GetEntityId(handler, node, target);
|
|
48
|
+
var proxy = Proxies[(handler, node)];
|
|
49
|
+
if (Selection.activeObject != proxy) Selection.activeObject = proxy;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
internal static void Remove(HierarchyNodeHandler handler, HierarchyNode node)
|
|
53
|
+
{
|
|
54
|
+
if (Proxies.Remove((handler, node), out var proxy))
|
|
55
|
+
Object.DestroyImmediate(proxy);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
private static void DisposeAll()
|
|
59
|
+
{
|
|
60
|
+
foreach (var proxy in Proxies.Values) Object.DestroyImmediate(proxy);
|
|
61
|
+
Proxies.Clear();
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
using UnityEditor;
|
|
2
|
+
using UnityEngine.UIElements;
|
|
3
|
+
|
|
4
|
+
namespace Delta.ECS.Unity.Editor
|
|
5
|
+
{
|
|
6
|
+
[CustomEditor(typeof(SelectionProxy))]
|
|
7
|
+
internal sealed class SelectionProxyEditor : UnityEditor.Editor
|
|
8
|
+
{
|
|
9
|
+
private SceneEntityInspectorView _view;
|
|
10
|
+
|
|
11
|
+
public override bool UseDefaultMargins() => false;
|
|
12
|
+
|
|
13
|
+
public override bool RequiresConstantRepaint() => EditorApplication.isPlaying;
|
|
14
|
+
|
|
15
|
+
private void OnEnable()
|
|
16
|
+
{
|
|
17
|
+
_view?.Dispose();
|
|
18
|
+
_view = new SceneEntityInspectorView(ResolveTarget);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
private EntityInspectorTarget ResolveTarget() => target is SelectionProxy proxy && proxy != null
|
|
22
|
+
? proxy.Target
|
|
23
|
+
: default;
|
|
24
|
+
|
|
25
|
+
private void OnDisable()
|
|
26
|
+
{
|
|
27
|
+
_view?.Dispose();
|
|
28
|
+
_view = null;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
public override VisualElement CreateInspectorGUI() => _view.CreateGUI();
|
|
32
|
+
}
|
|
33
|
+
}
|
package/LICENSE.md
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Artromskiy
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/LICENSE.md.meta
ADDED
package/README.md
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# DeltaECS Unity
|
|
2
|
+
|
|
3
|
+
Unity scene authoring and editor integration for DeltaECS. This package
|
|
4
|
+
requires Unity 6.7 (`6000.7`) or newer.
|
|
5
|
+
|
|
6
|
+
## Install
|
|
7
|
+
|
|
8
|
+
Add the npm-compatible registry and package to the Unity project's
|
|
9
|
+
`Packages/manifest.json`:
|
|
10
|
+
|
|
11
|
+
```json
|
|
12
|
+
{
|
|
13
|
+
"scopedRegistries": [
|
|
14
|
+
{
|
|
15
|
+
"name": "Artromskiy",
|
|
16
|
+
"url": "https://registry.npmjs.org",
|
|
17
|
+
"scopes": ["com.artromskiy"]
|
|
18
|
+
}
|
|
19
|
+
],
|
|
20
|
+
"dependencies": {
|
|
21
|
+
"com.artromskiy.deltaecs.unity": "0.0.37"
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Keep the project's existing `dependencies` and `scopedRegistries` entries when
|
|
27
|
+
adding these values. The core `DeltaECS` runtime and `DeltaECS.Generators` are
|
|
28
|
+
separate NuGet packages and are not included in this UPM package.
|
|
29
|
+
|
|
30
|
+
## Register components
|
|
31
|
+
|
|
32
|
+
Install `DeltaECS.Generators` in the assembly that declares components, then
|
|
33
|
+
mark component structs with `DeltaEcsComponentAttribute`:
|
|
34
|
+
|
|
35
|
+
```csharp
|
|
36
|
+
using Delta.ECS;
|
|
37
|
+
|
|
38
|
+
[DeltaEcsComponent]
|
|
39
|
+
public struct Health
|
|
40
|
+
{
|
|
41
|
+
public float Value;
|
|
42
|
+
}
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Generated module initializers register typed component factories. Create a
|
|
46
|
+
world with the generated layout catalog:
|
|
47
|
+
|
|
48
|
+
```csharp
|
|
49
|
+
using var world = new World(GeneratedComponentCatalog.CreateLayoutRegistry());
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
The generator reports the stable schema ID for each component. Set
|
|
53
|
+
`SchemaId` explicitly when a component's serialized identity must remain
|
|
54
|
+
unchanged after a type rename:
|
|
55
|
+
|
|
56
|
+
```csharp
|
|
57
|
+
[DeltaEcsComponent(SchemaId = 0x1234UL)]
|
|
58
|
+
public struct Position
|
|
59
|
+
{
|
|
60
|
+
public float X;
|
|
61
|
+
public float Y;
|
|
62
|
+
}
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
See the [DeltaECS documentation](https://github.com/Artromskiy/DeltaECS/wiki)
|
|
66
|
+
for the runtime and generator APIs.
|
package/README.md.meta
ADDED
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
using System;
|
|
2
|
+
using System.Collections.Generic;
|
|
3
|
+
using System.Reflection;
|
|
4
|
+
using Delta.ECS;
|
|
5
|
+
using Delta.ECS.Integration;
|
|
6
|
+
using UnityEngine;
|
|
7
|
+
|
|
8
|
+
namespace Delta.ECS.Unity
|
|
9
|
+
{
|
|
10
|
+
[Serializable]
|
|
11
|
+
internal sealed class ComponentData
|
|
12
|
+
{
|
|
13
|
+
[SerializeField] private string _schemaId;
|
|
14
|
+
[SerializeField, TextArea(2, 8)] private string _json;
|
|
15
|
+
[SerializeField] private List<EntityReference> _entityReferences = new();
|
|
16
|
+
|
|
17
|
+
public string SchemaIdText => _schemaId;
|
|
18
|
+
public string Json => _json;
|
|
19
|
+
public IReadOnlyList<EntityReference> EntityReferences => _entityReferences ??= new List<EntityReference>();
|
|
20
|
+
|
|
21
|
+
public ComponentData(ulong schemaId, string json)
|
|
22
|
+
{
|
|
23
|
+
_schemaId = schemaId.ToString("X16");
|
|
24
|
+
_json = json;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
public bool TryGetSchemaId(out SchemaId schemaId)
|
|
28
|
+
{
|
|
29
|
+
if (ulong.TryParse(_schemaId, System.Globalization.NumberStyles.HexNumber, null, out ulong value))
|
|
30
|
+
{
|
|
31
|
+
schemaId = new SchemaId(value);
|
|
32
|
+
return true;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
schemaId = default;
|
|
36
|
+
return false;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
public object CreateValue(Type componentType, Func<string, Entity> resolveEntity)
|
|
40
|
+
{
|
|
41
|
+
object value = string.IsNullOrEmpty(_json)
|
|
42
|
+
? Activator.CreateInstance(componentType)
|
|
43
|
+
: JsonUtility.FromJson(_json, componentType);
|
|
44
|
+
|
|
45
|
+
if (value == null)
|
|
46
|
+
{
|
|
47
|
+
value = Activator.CreateInstance(componentType);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
FieldInfo[] fields = componentType.GetFields(BindingFlags.Instance | BindingFlags.Public);
|
|
51
|
+
List<EntityReference> references = EntityReferenceList;
|
|
52
|
+
for (int i = 0; i < references.Count; i++)
|
|
53
|
+
{
|
|
54
|
+
EntityReference reference = references[i];
|
|
55
|
+
for (int fieldIndex = 0; fieldIndex < fields.Length; fieldIndex++)
|
|
56
|
+
{
|
|
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
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
return value;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
public void StoreValue(object value, Func<Entity, string> stableIdResolver)
|
|
70
|
+
{
|
|
71
|
+
if (value == null)
|
|
72
|
+
{
|
|
73
|
+
UnityThrowHelpers.ThrowArgumentNull(nameof(value));
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
_json = JsonUtility.ToJson(value);
|
|
77
|
+
EntityReferenceList.Clear();
|
|
78
|
+
|
|
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
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
public string GetEntityReference(string fieldName)
|
|
98
|
+
{
|
|
99
|
+
List<EntityReference> references = EntityReferenceList;
|
|
100
|
+
for (int i = 0; i < references.Count; i++)
|
|
101
|
+
{
|
|
102
|
+
if (string.Equals(references[i].FieldName, fieldName, StringComparison.Ordinal))
|
|
103
|
+
{
|
|
104
|
+
return references[i].TargetEntityId;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
return string.Empty;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
private List<EntityReference> EntityReferenceList =>
|
|
112
|
+
_entityReferences ??= new List<EntityReference>();
|
|
113
|
+
|
|
114
|
+
public static ComponentData CreateDefault(ComponentDescriptor descriptor)
|
|
115
|
+
{
|
|
116
|
+
object value = Activator.CreateInstance(descriptor.ValueType);
|
|
117
|
+
return new ComponentData(descriptor.Schema.Value, JsonUtility.ToJson(value));
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "DeltaECS.Unity",
|
|
3
|
+
"rootNamespace": "Delta.ECS.Unity",
|
|
4
|
+
"references": [],
|
|
5
|
+
"includePlatforms": [],
|
|
6
|
+
"excludePlatforms": [],
|
|
7
|
+
"allowUnsafeCode": false,
|
|
8
|
+
"overrideReferences": false,
|
|
9
|
+
"precompiledReferences": [],
|
|
10
|
+
"autoReferenced": true,
|
|
11
|
+
"defineConstraints": [],
|
|
12
|
+
"versionDefines": [],
|
|
13
|
+
"noEngineReferences": false
|
|
14
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
using System;
|
|
2
|
+
using System.Collections.Generic;
|
|
3
|
+
using UnityEngine;
|
|
4
|
+
|
|
5
|
+
namespace Delta.ECS.Unity
|
|
6
|
+
{
|
|
7
|
+
[Serializable]
|
|
8
|
+
internal sealed class EntityAuthoring
|
|
9
|
+
{
|
|
10
|
+
[SerializeField] private string _stableId;
|
|
11
|
+
[SerializeField] private string _name = "Entity";
|
|
12
|
+
[SerializeField] private List<ComponentData> _components = new();
|
|
13
|
+
|
|
14
|
+
public string StableId
|
|
15
|
+
{
|
|
16
|
+
get
|
|
17
|
+
{
|
|
18
|
+
EnsureStableId();
|
|
19
|
+
return _stableId;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
public string Name
|
|
24
|
+
{
|
|
25
|
+
get => string.IsNullOrEmpty(_name) ? "Entity" : _name;
|
|
26
|
+
set => _name = string.IsNullOrWhiteSpace(value) ? "Entity" : value;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
public IList<ComponentData> Components => _components ??= new List<ComponentData>();
|
|
30
|
+
|
|
31
|
+
internal bool EnsureStableId()
|
|
32
|
+
{
|
|
33
|
+
if (!string.IsNullOrEmpty(_stableId))
|
|
34
|
+
{
|
|
35
|
+
return false;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
_stableId = Guid.NewGuid().ToString("N");
|
|
39
|
+
return true;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
internal void ReplaceStableId()
|
|
43
|
+
{
|
|
44
|
+
_stableId = Guid.NewGuid().ToString("N");
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
using System;
|
|
2
|
+
using UnityEngine;
|
|
3
|
+
|
|
4
|
+
namespace Delta.ECS.Unity
|
|
5
|
+
{
|
|
6
|
+
[Serializable]
|
|
7
|
+
internal sealed class EntityReference
|
|
8
|
+
{
|
|
9
|
+
[SerializeField] private string _fieldName;
|
|
10
|
+
[SerializeField] private string _targetEntityId;
|
|
11
|
+
|
|
12
|
+
public string FieldName => _fieldName;
|
|
13
|
+
public string TargetEntityId => _targetEntityId;
|
|
14
|
+
|
|
15
|
+
public EntityReference(string fieldName, string targetEntityId)
|
|
16
|
+
{
|
|
17
|
+
_fieldName = fieldName;
|
|
18
|
+
_targetEntityId = targetEntityId;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
using System;
|
|
2
|
+
using System.Collections.Generic;
|
|
3
|
+
using UnityEngine;
|
|
4
|
+
using UnityEngine.SceneManagement;
|
|
5
|
+
|
|
6
|
+
namespace Delta.ECS.Unity
|
|
7
|
+
{
|
|
8
|
+
/// <summary>
|
|
9
|
+
/// Stores entities authored for a Delta ECS scene. The Unity editor integration
|
|
10
|
+
/// creates a hidden scene object for it automatically; it does not own a Delta ECS World.
|
|
11
|
+
/// </summary>
|
|
12
|
+
[DisallowMultipleComponent]
|
|
13
|
+
[AddComponentMenu("Delta ECS/Scene Authoring")]
|
|
14
|
+
public sealed class SceneAuthoring : MonoBehaviour
|
|
15
|
+
{
|
|
16
|
+
internal const string AuthoringObjectName = "Delta ECS Scene Authoring";
|
|
17
|
+
|
|
18
|
+
[SerializeField, HideInInspector]
|
|
19
|
+
private SceneData _sceneData = new();
|
|
20
|
+
[SerializeField, HideInInspector]
|
|
21
|
+
private List<SceneViewBinding> _viewBindings = new();
|
|
22
|
+
|
|
23
|
+
[NonSerialized] private Dictionary<string, GameObject> _viewsByStableId;
|
|
24
|
+
[NonSerialized] private Dictionary<UnityEngine.EntityId, string> _stableIdsByView;
|
|
25
|
+
|
|
26
|
+
internal SceneData SceneData => _sceneData ??= new SceneData();
|
|
27
|
+
|
|
28
|
+
internal bool TryGetView(string stableId, out GameObject view)
|
|
29
|
+
{
|
|
30
|
+
EnsureBindingIndex();
|
|
31
|
+
if (!string.IsNullOrEmpty(stableId) && _viewsByStableId.TryGetValue(stableId, out view) && view != null)
|
|
32
|
+
{
|
|
33
|
+
return true;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
view = null;
|
|
37
|
+
return false;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
internal bool TryGetStableId(GameObject view, out string stableId)
|
|
41
|
+
{
|
|
42
|
+
EnsureBindingIndex();
|
|
43
|
+
if (view != null && _stableIdsByView.TryGetValue(view.GetEntityId(), out stableId))
|
|
44
|
+
{
|
|
45
|
+
return true;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
stableId = null;
|
|
49
|
+
return false;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/// <summary>Persists a same-scene Unity view binding for an authored ECS entity.</summary>
|
|
53
|
+
internal bool SetView(string stableId, GameObject view)
|
|
54
|
+
{
|
|
55
|
+
if (string.IsNullOrEmpty(stableId)
|
|
56
|
+
|| (view != null && !SceneData.TryGetEntity(stableId, out _))
|
|
57
|
+
|| (view != null && view.scene != gameObject.scene))
|
|
58
|
+
{
|
|
59
|
+
return false;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
EnsureBindingIndex();
|
|
63
|
+
UnityEngine.EntityId viewId = view != null ? view.GetEntityId() : UnityEngine.EntityId.None;
|
|
64
|
+
for (int i = _viewBindings.Count - 1; i >= 0; i--)
|
|
65
|
+
{
|
|
66
|
+
SceneViewBinding binding = _viewBindings[i];
|
|
67
|
+
bool sameEntity = string.Equals(binding.StableId, stableId, StringComparison.Ordinal);
|
|
68
|
+
bool sameView = view != null && binding.View != null && binding.View.GetEntityId() == viewId;
|
|
69
|
+
if (sameEntity || sameView)
|
|
70
|
+
{
|
|
71
|
+
_viewBindings.RemoveAt(i);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
if (view != null)
|
|
76
|
+
{
|
|
77
|
+
_viewBindings.Add(new SceneViewBinding(stableId, view));
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
InvalidateBindingIndex();
|
|
81
|
+
EnsureBindingIndex();
|
|
82
|
+
return true;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
internal bool RemoveView(string stableId) => SetView(stableId, null);
|
|
86
|
+
|
|
87
|
+
internal static SceneAuthoring FindForScene(Scene scene)
|
|
88
|
+
{
|
|
89
|
+
if (!scene.IsValid())
|
|
90
|
+
{
|
|
91
|
+
return null;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
SceneAuthoring[] authorings = Resources.FindObjectsOfTypeAll<SceneAuthoring>();
|
|
95
|
+
for (int i = 0; i < authorings.Length; i++)
|
|
96
|
+
{
|
|
97
|
+
SceneAuthoring authoring = authorings[i];
|
|
98
|
+
if (authoring != null && authoring.gameObject.scene == scene)
|
|
99
|
+
{
|
|
100
|
+
return authoring;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
return null;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
internal static SceneAuthoring GetOrCreateForScene(Scene scene)
|
|
108
|
+
{
|
|
109
|
+
if (!scene.IsValid() || !scene.isLoaded)
|
|
110
|
+
{
|
|
111
|
+
UnityThrowHelpers.ThrowArgument("Scene authoring requires a valid, loaded scene.", nameof(scene));
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
SceneAuthoring existing = FindForScene(scene);
|
|
115
|
+
if (existing != null)
|
|
116
|
+
{
|
|
117
|
+
return existing;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
var authoringObject = new GameObject(AuthoringObjectName);
|
|
121
|
+
SceneManager.MoveGameObjectToScene(authoringObject, scene);
|
|
122
|
+
SceneAuthoring authoring = authoringObject.AddComponent<SceneAuthoring>();
|
|
123
|
+
authoringObject.hideFlags |= HideFlags.HideInHierarchy;
|
|
124
|
+
return authoring;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
private void OnValidate()
|
|
128
|
+
{
|
|
129
|
+
SceneData.EnsureStableIds();
|
|
130
|
+
InvalidateBindingIndex();
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
private void OnEnable()
|
|
134
|
+
{
|
|
135
|
+
SceneData.Changed -= OnSceneDataChanged;
|
|
136
|
+
SceneData.Changed += OnSceneDataChanged;
|
|
137
|
+
InvalidateBindingIndex();
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
private void OnDisable()
|
|
141
|
+
{
|
|
142
|
+
if (_sceneData != null)
|
|
143
|
+
{
|
|
144
|
+
_sceneData.Changed -= OnSceneDataChanged;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
private void OnSceneDataChanged(SceneDataChange change)
|
|
149
|
+
{
|
|
150
|
+
if (change.Kind == SceneDataChangeKind.EntityDestroyed)
|
|
151
|
+
{
|
|
152
|
+
RemoveView(change.StableId);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
private void EnsureBindingIndex()
|
|
157
|
+
{
|
|
158
|
+
if (_viewsByStableId != null && _stableIdsByView != null)
|
|
159
|
+
{
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
_viewsByStableId = new Dictionary<string, GameObject>(StringComparer.Ordinal);
|
|
164
|
+
_stableIdsByView = new Dictionary<UnityEngine.EntityId, string>();
|
|
165
|
+
_viewBindings ??= new List<SceneViewBinding>();
|
|
166
|
+
for (int i = 0; i < _viewBindings.Count; i++)
|
|
167
|
+
{
|
|
168
|
+
SceneViewBinding binding = _viewBindings[i];
|
|
169
|
+
if (string.IsNullOrEmpty(binding.StableId) || binding.View == null)
|
|
170
|
+
{
|
|
171
|
+
continue;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
UnityEngine.EntityId viewId = binding.View.GetEntityId();
|
|
175
|
+
_viewsByStableId[binding.StableId] = binding.View;
|
|
176
|
+
_stableIdsByView[viewId] = binding.StableId;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
private void InvalidateBindingIndex()
|
|
181
|
+
{
|
|
182
|
+
_viewsByStableId = null;
|
|
183
|
+
_stableIdsByView = null;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
[Serializable]
|
|
188
|
+
internal struct SceneViewBinding
|
|
189
|
+
{
|
|
190
|
+
[SerializeField] private string _stableId;
|
|
191
|
+
[SerializeField] private GameObject _view;
|
|
192
|
+
|
|
193
|
+
public string StableId => _stableId;
|
|
194
|
+
public GameObject View => _view;
|
|
195
|
+
|
|
196
|
+
public SceneViewBinding(string stableId, GameObject view)
|
|
197
|
+
{
|
|
198
|
+
_stableId = stableId;
|
|
199
|
+
_view = view;
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
}
|