diff --git a/Cluster.cs b/Cluster.cs index e2a9fae..e9eeb18 100644 --- a/Cluster.cs +++ b/Cluster.cs @@ -185,12 +185,10 @@ public class Cluster : Nucleus { get { if (this._inputs == null) { this._inputs = new(); - foreach (Nucleus receptor in this.nuclei) { - if (receptor is Nucleus nucleus) { - // inputs have no incoming synapses yet. - if (nucleus.synapses.Count == 0) - this._inputs.Add(nucleus); - } + foreach (Nucleus nucleus in this.nuclei) { + // inputs have no synapses + if (nucleus.synapses.Count == 0) + this._inputs.Add(nucleus); } } return this._inputs; @@ -204,6 +202,20 @@ public class Cluster : Nucleus { return null; } } + public List _outputs = null; + public List outputs { + get { + if (this._outputs == null) { + this._outputs = new(); + foreach (Nucleus nucleus in this.nuclei) { + // outputs have not receivers + if (nucleus.receivers.Count == 0) + this._outputs.Add(nucleus); + } + } + return this._outputs; + } + } public bool TryGetNucleus(string nucleusName, out Nucleus foundNucleus) { foreach (Nucleus receptor in this.nuclei) { diff --git a/ClusterPrefab.cs b/ClusterPrefab.cs index 5a390e8..ad98aac 100644 --- a/ClusterPrefab.cs +++ b/ClusterPrefab.cs @@ -28,6 +28,29 @@ public class ClusterPrefab : ScriptableObject { return this._inputs; } } + private List _outputs = null; + public List outputs { + get { + if (this._outputs == null) + RefreshOutputs(); + return this._outputs; + } + } + public void RefreshOutputs() { + this._outputs = new(); + foreach (Nucleus nucleus in this.nuclei) { + if (nucleus.receivers.Count == 0) + this._outputs.Add(nucleus); + } + } + + public Nucleus GetNucleus(string nucleusName) { + foreach (Nucleus nucleus in this.nuclei) { + if (nucleus.name == nucleusName) + return nucleus; + } + return null; + } // Call this function to ensure that there is at least one nucleus // This is an invariant and should be ensured before the nucleus is used diff --git a/Editor/ClusterInspector.cs b/Editor/ClusterInspector.cs index 972c955..e1928f9 100644 --- a/Editor/ClusterInspector.cs +++ b/Editor/ClusterInspector.cs @@ -46,7 +46,7 @@ public class ClusterInspector : Editor { flexDirection = FlexDirection.Row } }; - GraphView graph = new(); + GraphView graph = new(cluster); graph.style.flexGrow = 1; inspectorContainer = new VisualElement { @@ -61,14 +61,14 @@ public class ClusterInspector : Editor { mainContainer.Add(inspectorContainer); root.Add(mainContainer); - graph.SetGraph(null, cluster, cluster.output, inspectorContainer); + graph.SetGraph(null, cluster.output, inspectorContainer); return graph; } public class GraphView : VisualElement { - ClusterPrefab cluster; + readonly ClusterPrefab cluster; SerializedObject serializedBrain; Nucleus currentNucleus; GameObject gameObject; @@ -77,35 +77,59 @@ public class ClusterInspector : Editor { private bool expandArray = false; ClusterWrapper currentWrapper; + PopupField outputsField; - public enum OutputNodes { - Output, - Output2, - Output3 - } + public GraphView(ClusterPrefab prefab) { + this.cluster = prefab; - public GraphView() { name = "content"; style.flexGrow = 1; - IMGUIContainer imguiContainer = new(OnIMGUI); - imguiContainer.style.position = Position.Absolute; - imguiContainer.style.left = 0; imguiContainer.style.top = 0; - imguiContainer.style.right = 0; imguiContainer.style.bottom = 0; - imguiContainer.pickingMode = PickingMode.Position; - imguiContainer.focusable = true; - Add(imguiContainer); + IMGUIContainer graphContainer = new(OnIMGUI); + graphContainer.style.position = Position.Absolute; + graphContainer.style.left = 0; graphContainer.style.top = 0; + graphContainer.style.right = 0; graphContainer.style.bottom = 0; + graphContainer.pickingMode = PickingMode.Position; + graphContainer.focusable = true; + Add(graphContainer); - PopupField enumField = new(System.Enum.GetValues(typeof(OutputNodes)).Cast().ToList(), OutputNodes.Output); - enumField.RegisterValueChangedCallback(evt => OnOutputChanged(evt.newValue)); - Add(enumField); + VisualElement outputContainer = new() { + style = { + flexDirection = FlexDirection.Row, + alignItems = Align.Center, + } + }; + + List names = this.cluster.outputs.Select(output => output.name).ToList(); + outputsField = new(names, names.First()) { + style = { flexGrow = 1 } + }; + outputsField.RegisterValueChangedCallback(evt => OnOutputChanged(evt.newValue)); + outputContainer.Add(outputsField); + + Button addButton = new(() => OnAddClusterOutput()) { + text = "Add" + }; + outputContainer.Add(addButton); + + Add(outputContainer); // Subscribe when added to panel (editor UI ready) RegisterCallback(evt => Subscribe()); RegisterCallback(evt => Unsubscribe()); } - void OnOutputChanged(OutputNodes output) { + void OnOutputChanged(string outputName) { + this.currentNucleus = this.cluster.GetNucleus(outputName); + } + + void OnAddClusterOutput() { + Nucleus newOutput = new Neuron(this.cluster, "Output 2"); + + outputsField.choices = this.cluster.outputs.Select(output => output.name).ToList(); + outputsField.value = newOutput.name; + + this.currentNucleus = newOutput; } bool subscribed = false; @@ -122,11 +146,11 @@ public class ClusterInspector : Editor { subscribed = false; } - public void SetGraph(GameObject gameObject, ClusterPrefab brain, Nucleus nucleus, VisualElement inspectorContainer) { + public void SetGraph(GameObject gameObject, Nucleus nucleus, VisualElement inspectorContainer) { this.gameObject = gameObject; - this.cluster = brain; + //this.cluster = brain; if (Application.isPlaying == false) - this.serializedBrain = new SerializedObject(brain); + this.serializedBrain = new SerializedObject(this.cluster); this.currentNucleus = nucleus; Rebuild(inspectorContainer); }