-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
- Loading branch information
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
{ | ||
"name": "10101Software.DOTS.HybridSimulation.Editor", | ||
"rootNamespace": "Software10101.DOTS.Editor", | ||
"references": [ | ||
"GUID:852fdcd981c08e249a237d901a75e290", | ||
"GUID:e0cd26848372d4e5c891c569017e11f1" | ||
], | ||
"includePlatforms": [ | ||
"Editor" | ||
], | ||
"excludePlatforms": [], | ||
"allowUnsafeCode": false, | ||
"overrideReferences": false, | ||
"precompiledReferences": [], | ||
"autoReferenced": true, | ||
"defineConstraints": [], | ||
"versionDefines": [], | ||
"noEngineReferences": false | ||
} |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
using Software10101.DOTS.Editor.GraphEditor; | ||
using Software10101.DOTS.MonoBehaviours; | ||
using UnityEditor; | ||
using UnityEngine.UIElements; | ||
|
||
namespace Software10101.DOTS.Editor.Drawers { | ||
[CustomPropertyDrawer(typeof(WorldBehaviour.GraphSystemGroupData))] | ||
public class GraphSystemGroupDataDrawer : PropertyDrawer { | ||
public override VisualElement CreatePropertyGUI(SerializedProperty property) { | ||
// Create property container element. | ||
VisualElement container = new(); | ||
|
||
// Create property fields. | ||
Button editButton = new(() => { | ||
GraphSystemGroupEditorWindow window = EditorWindow.GetWindow<GraphSystemGroupEditorWindow>(); | ||
|
||
WorldBehaviour wb = (WorldBehaviour)property.serializedObject.targetObject; | ||
window.Initialize(wb, property.name); | ||
}) { | ||
text = $"Edit {property.displayName}" | ||
}; | ||
|
||
// Add fields to the container. | ||
container.Add(editButton); | ||
|
||
return container; | ||
} | ||
} | ||
} |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,292 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using Software10101.DOTS.MonoBehaviours; | ||
using Unity.Collections; | ||
using UnityEditor; | ||
using UnityEditor.Experimental.GraphView; | ||
using UnityEditor.UIElements; | ||
using UnityEngine; | ||
using UnityEngine.UIElements; | ||
using Object = UnityEngine.Object; | ||
|
||
namespace Software10101.DOTS.Editor.GraphEditor { | ||
public class GraphSystemGroupEditorWindow : EditorWindow { | ||
private Object _serializedObjectPrev; | ||
private bool _worldBehaviourPrevExist; | ||
private string _propertyNamePrev; | ||
|
||
private Object _serializedObject; | ||
private string _propertyName; | ||
|
||
private Toolbar _toolbar; | ||
private Label _loadedLabel; | ||
|
||
private GraphSystemGroupGraphView _graphView; | ||
|
||
private readonly List<string> _addNodeChoices = new(); | ||
|
||
private bool _populateNodeCreationChoices = false; | ||
|
||
private void CreateGUI() { | ||
titleContent = new GUIContent("Graph System Group"); | ||
|
||
_graphView = new GraphSystemGroupGraphView { | ||
name = "World Name > System Name" | ||
}; | ||
_graphView.StretchToParentSize(); | ||
_graphView.graphViewChanged += change => { | ||
if (change.elementsToRemove != null) { | ||
_populateNodeCreationChoices = true; | ||
} | ||
|
||
return change; | ||
}; | ||
rootVisualElement.Add(_graphView); | ||
|
||
Node selectGraphNode = new() { | ||
title = "Open a graph system group to use the editor." | ||
}; | ||
|
||
selectGraphNode.SetPosition(new Rect(0, 20, 150, 100)); | ||
selectGraphNode.RefreshExpandedState(); | ||
selectGraphNode.RefreshPorts(); | ||
|
||
_graphView.AddElement(selectGraphNode); | ||
_graphView.UpdateViewTransform(Vector3.zero, Vector3.one); | ||
_graphView.SetEnabled(false); | ||
|
||
_toolbar = new(); | ||
|
||
PopulateNodeCreationChoices(); | ||
DropdownField nodeCreateDropDown = new("Create Node", _addNodeChoices, -1); | ||
nodeCreateDropDown.RegisterValueChangedCallback(evt => { | ||
if (string.IsNullOrEmpty(evt.newValue)) { | ||
return; | ||
} | ||
|
||
SystemTypeReference systemReference = AssetDatabase.LoadAssetAtPath<SystemTypeReference>(evt.newValue); | ||
_graphView.AddSystemNode(systemReference.GetInstanceID()); | ||
nodeCreateDropDown.index = -1; | ||
PopulateNodeCreationChoices(); | ||
}); | ||
_toolbar.Add(nodeCreateDropDown); | ||
|
||
_loadedLabel = new Label(""); | ||
_toolbar.Add(_loadedLabel); | ||
|
||
Button saveButton = new(Save) { | ||
text = "Save" | ||
}; | ||
_toolbar.Add(saveButton); | ||
|
||
rootVisualElement.Add(_toolbar); | ||
_toolbar.SetEnabled(false); | ||
} | ||
|
||
private void OnFocus() { | ||
PopulateNodeCreationChoices(); | ||
} | ||
|
||
private void PopulateNodeCreationChoices() { | ||
if (_graphView == null) { | ||
return; | ||
} | ||
|
||
_addNodeChoices.Clear(); | ||
|
||
int[] existingInstanceIds = _graphView.nodes | ||
.Where(node => node is SystemNode systemNode && systemNode.InstanceId.HasValue) | ||
// ReSharper disable once PossibleInvalidOperationException // HasValue check is on the line above | ||
.Select(node => ((SystemNode)node).InstanceId.Value) | ||
.ToArray(); | ||
NativeArray<int> existingInstanceIdsNative = new(existingInstanceIds.Length, Allocator.Persistent); | ||
for (int i = 0; i < existingInstanceIds.Length; i++) { | ||
int existingInstanceId = existingInstanceIds[i]; | ||
existingInstanceIdsNative[i] = existingInstanceId; | ||
} | ||
|
||
NativeArray<GUID> existingNodeGuidsNative = new(existingInstanceIds.Length, Allocator.Persistent); | ||
|
||
AssetDatabase.InstanceIDsToGUIDs(existingInstanceIdsNative, existingNodeGuidsNative); | ||
|
||
existingInstanceIdsNative.Dispose(); | ||
|
||
HashSet<string> existingNodeGuids = new(); | ||
for (int i = 0; i < existingNodeGuidsNative.Length; i++) { | ||
GUID existingGuid = existingNodeGuidsNative[i]; | ||
existingNodeGuids.Add(existingGuid.ToString()); | ||
} | ||
|
||
_addNodeChoices.AddRange( | ||
AssetDatabase.FindAssets($"t:{nameof(SystemTypeReference)}") | ||
.Where(guid => !existingNodeGuids.Contains(guid)) | ||
.Select(AssetDatabase.GUIDToAssetPath) | ||
); | ||
|
||
existingNodeGuidsNative.Dispose(); | ||
} | ||
|
||
private void OnGUI() { | ||
if (_graphView == null) { | ||
return; | ||
} | ||
|
||
if (_populateNodeCreationChoices) { | ||
_populateNodeCreationChoices = false; | ||
PopulateNodeCreationChoices(); | ||
} | ||
|
||
if (EditorPrefs.HasKey("graph_editing_world_instance")) { | ||
int instanceId = EditorPrefs.GetInt("graph_editing_world_instance"); | ||
_serializedObject = (WorldBehaviour)EditorUtility.InstanceIDToObject(instanceId); | ||
|
||
if (_serializedObject) { | ||
if (EditorPrefs.HasKey("graph_editing_save_callback")) { | ||
_propertyName = EditorPrefs.GetString("graph_editing_save_callback"); | ||
} | ||
} | ||
} | ||
|
||
if (_serializedObjectPrev != _serializedObject || _propertyNamePrev != _propertyName || _worldBehaviourPrevExist != _serializedObject) { | ||
_graphView.DeleteElements(_graphView.graphElements); | ||
|
||
if (!_serializedObject) { | ||
_toolbar.SetEnabled(false); | ||
|
||
Node selectGraphNode = new() { | ||
title = "Open a graph system group to use the editor." | ||
}; | ||
|
||
selectGraphNode.SetPosition(new Rect(0, 20, 150, 100)); | ||
selectGraphNode.RefreshExpandedState(); | ||
selectGraphNode.RefreshPorts(); | ||
|
||
_graphView.AddElement(selectGraphNode); | ||
_graphView.UpdateViewTransform(Vector3.zero, Vector3.one); | ||
_graphView.SetEnabled(false); | ||
} else { | ||
_toolbar.SetEnabled(true); | ||
_graphView.SetEnabled(true); | ||
|
||
Load(); | ||
} | ||
} else if (_serializedObject && _graphView.enabledSelf == false) { | ||
_graphView.DeleteElements(_graphView.graphElements); | ||
|
||
_toolbar.SetEnabled(true); | ||
_graphView.SetEnabled(true); | ||
|
||
Load(); | ||
} | ||
|
||
if (_serializedObject) { | ||
string dirtyFlag = _graphView.Dirty ? " *" : ""; | ||
_loadedLabel.text = $"{_serializedObject.name} - {_propertyName}{dirtyFlag}"; | ||
} else { | ||
_loadedLabel.text = ""; | ||
} | ||
|
||
_worldBehaviourPrevExist = _serializedObject; | ||
_serializedObjectPrev = _serializedObject; | ||
_propertyNamePrev = _propertyName; | ||
} | ||
|
||
public void Initialize(Object serializedObject, string propertyName) { | ||
_serializedObject = serializedObject; | ||
_propertyName = propertyName; | ||
|
||
EditorPrefs.SetInt("graph_editing_world_instance", serializedObject.GetInstanceID()); | ||
EditorPrefs.SetString("graph_editing_save_callback", propertyName); | ||
} | ||
|
||
private void OnDisable() { | ||
rootVisualElement.Clear(); | ||
_serializedObject = null; | ||
_propertyName = null; | ||
} | ||
|
||
private void Save() { | ||
SerializedObject so = new(_serializedObject); | ||
|
||
WorldBehaviour.GraphSystemGroupData graphData = WorldBehaviour.GraphSystemGroupData.CreateEmpty(); | ||
|
||
HashSet<int> rootDependencies = new(); | ||
Dictionary<int, HashSet<int>> dependencies = new(); | ||
|
||
_graphView.edges.ForEach(edge => { | ||
int? dependent = ((SystemNode)edge.input.node).InstanceId; | ||
// ReSharper disable once PossibleInvalidOperationException // not possible - root is never a dependency | ||
int dependency = ((SystemNode)edge.output.node).InstanceId.Value; | ||
|
||
HashSet<int> existingDependencies; | ||
|
||
if (!dependent.HasValue) { | ||
existingDependencies = rootDependencies; | ||
} else if (!dependencies.TryGetValue(dependent.Value, out existingDependencies)) { | ||
existingDependencies = new HashSet<int>(); | ||
dependencies[dependent.Value] = existingDependencies; | ||
} | ||
|
||
existingDependencies.Add(dependency); | ||
}); | ||
|
||
graphData.Nodes = _graphView.nodes | ||
.OfType<SystemNode>() | ||
.Select(systemNode => new WorldBehaviour.GraphSystemGroupData.SystemNodeData( | ||
systemNode.InstanceId.HasValue | ||
? (SystemTypeReference)EditorUtility.InstanceIDToObject(systemNode.InstanceId.Value) | ||
: null, | ||
systemNode.GetPosition().position, | ||
systemNode.InstanceId.HasValue | ||
? dependencies.ContainsKey(systemNode.InstanceId.Value) | ||
? dependencies[systemNode.InstanceId.Value]? | ||
.Select(instanceId => (SystemTypeReference)EditorUtility.InstanceIDToObject(instanceId)) | ||
.ToArray() ?? Array.Empty<SystemTypeReference>() | ||
: Array.Empty<SystemTypeReference>() | ||
: rootDependencies | ||
.Select(instanceId => (SystemTypeReference)EditorUtility.InstanceIDToObject(instanceId)) | ||
.ToArray())) | ||
.ToArray(); | ||
|
||
so.FindProperty(_propertyName).boxedValue = graphData; | ||
so.ApplyModifiedProperties(); | ||
|
||
_graphView.Dirty = false; | ||
} | ||
|
||
private void Load() { | ||
SerializedObject so = new(_serializedObject); | ||
object graphDataRaw = so.FindProperty(_propertyName).boxedValue; | ||
WorldBehaviour.GraphSystemGroupData graphData = (WorldBehaviour.GraphSystemGroupData)graphDataRaw; | ||
|
||
SystemNode rootNode = null; | ||
Dictionary<int, SystemNode> nodesByInstanceId = new(); | ||
|
||
foreach (WorldBehaviour.GraphSystemGroupData.SystemNodeData systemNodeData in graphData.Nodes) { | ||
if (systemNodeData.SystemReference) { | ||
int instanceId = systemNodeData.SystemReference.GetInstanceID(); | ||
|
||
SystemNode node = _graphView.AddSystemNode(instanceId, systemNodeData.NodePosition); | ||
nodesByInstanceId[instanceId] = node; | ||
} else { | ||
rootNode = _graphView.AddSystemNode(null, systemNodeData.NodePosition); | ||
} | ||
} | ||
|
||
foreach (WorldBehaviour.GraphSystemGroupData.SystemNodeData systemNodeData in graphData.Nodes) { | ||
if (systemNodeData.SystemReference) { | ||
SystemNode dependent = nodesByInstanceId[systemNodeData.SystemReference.GetInstanceID()]; | ||
|
||
foreach (SystemTypeReference systemTypeReference in systemNodeData.Dependencies) { | ||
_graphView.AddSystemDependency(dependent, nodesByInstanceId[systemTypeReference.GetInstanceID()]); | ||
} | ||
} else { | ||
foreach (SystemTypeReference systemTypeReference in systemNodeData.Dependencies) { | ||
_graphView.AddSystemDependency(rootNode, nodesByInstanceId[systemTypeReference.GetInstanceID()]); | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} |