From 04bab9264faa6844665423b89f2b9da97a45f386 Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Wed, 22 Apr 2026 12:44:36 +0200 Subject: [PATCH] Fix links to multiple cluster neurons & cleanup --- Editor/ClusterInspector.cs | 149 +++++++++++++++++--------------- Editor/ClusterViewer.cs | 58 ++++--------- Runtime/Scripts/Core/Cluster.cs | 7 +- 3 files changed, 99 insertions(+), 115 deletions(-) diff --git a/Editor/ClusterInspector.cs b/Editor/ClusterInspector.cs index 1adbe18..a7dc1f2 100644 --- a/Editor/ClusterInspector.cs +++ b/Editor/ClusterInspector.cs @@ -153,15 +153,11 @@ namespace NanoBrain { fontStyle = FontStyle.Bold }; + // Nucleus type string nucleusType = this.currentNucleus.GetType().Name; - // if (this.currentNucleus.parent != null) { - // string clusterName = this.currentNucleus.parent.name; - // GUILayout.Label(clusterName + ": " + nucleusType, headerStyle); - // } - // else GUILayout.Label(nucleusType, headerStyle); - + // Nucleus name if (this.currentNucleus.parent is Cluster parentCluster) { EditorGUILayout.BeginHorizontal(); if (GUILayout.Button(this.currentNucleus.parent.name)) @@ -183,6 +179,7 @@ namespace NanoBrain { } } + // Current output value if (Application.isPlaying) { if (currentNucleus is Neuron currentNeuron1) { GUIContent nameLabel = new("Output", currentNeuron1.outputValue.ToString()); @@ -194,44 +191,63 @@ namespace NanoBrain { else EditorGUILayout.LabelField(" "); - if (this.currentNucleus is MemoryCell memory) { - memory.staticMemory = EditorGUILayout.Toggle("Static Memory", memory.staticMemory); - } + // Memory cell + if (this.currentNucleus is MemoryCell memory) + MemoryCellInspector(memory, ref anythingChanged); + // Cluster + else if (this.currentNucleus is Cluster cluster) + ClusterInspector(cluster, ref anythingChanged); + // Other + else + NucleusInspector(this.currentNucleus, ref anythingChanged); - if (this.currentNucleus is Cluster cluster) { - EditorGUILayout.BeginHorizontal(); - if (cluster.instanceCount > 1) - EditorGUILayout.IntField("Array size", cluster.instanceCount, GUILayout.MinWidth(150)); - else if (cluster.siblingClusters != null && cluster.siblingClusters.Length > 1) - EditorGUILayout.IntField("Array size", cluster.siblingClusters.Count(), GUILayout.MinWidth(150)); - else - EditorGUILayout.IntField("Array size", 1, GUILayout.MinWidth(150)); - if (GUILayout.Button("Add")) { - Undo.RecordObject(prefabAsset, "Array add " + prefabAsset.name); - //cluster.AddInstance(this.prefab); - cluster.AddInstance(); - anythingChanged = true; - } - if (GUILayout.Button("Del")) { - Undo.RecordObject(prefabAsset, "Array delete " + prefabAsset.name); - cluster.RemoveInstance(); - anythingChanged = true; - } - EditorGUILayout.EndHorizontal(); - } - - SynapsesInspector(ref anythingChanged); - ActivationInspector(ref anythingChanged); - - if (GUILayout.Button("Delete this neuron")) + if (GUILayout.Button("Delete")) DeleteNucleus(this.currentNucleus); - if (this.currentNucleus is Cluster subCluster) { - if (GUILayout.Button("Reimport Cluster")) - ReimportCluster(subCluster); - if (GUILayout.Button("Edit Cluster")) - EditCluster(subCluster); + serializedObject.ApplyModifiedProperties(); + if (anythingChanged) { + EditorUtility.SetDirty(prefabAsset); + AssetDatabase.SaveAssets(); } + } + + protected void MemoryCellInspector(MemoryCell memoryCell, ref bool anythingChanged) { + memoryCell.staticMemory = EditorGUILayout.Toggle("Static Memory", memoryCell.staticMemory); + NucleusInspector(memoryCell, ref anythingChanged); + } + + protected void ClusterInspector(Cluster cluster, ref bool anythingChanged) { + EditorGUILayout.BeginHorizontal(); + + int instanceCount = cluster.instanceCount; + if (instanceCount <= 1) { + if (cluster.siblingClusters != null && cluster.siblingClusters.Length > 1) + instanceCount = cluster.siblingClusters.Count(); + else + instanceCount = 1; + } + EditorGUILayout.IntField("Instances", instanceCount, GUILayout.MinWidth(150)); + + if (GUILayout.Button("Add")) { + Undo.RecordObject(prefabAsset, "Array add " + prefabAsset.name); + //cluster.AddInstance(this.prefab); + cluster.AddInstance(); + anythingChanged = true; + } + if (GUILayout.Button("Del")) { + Undo.RecordObject(prefabAsset, "Array delete " + prefabAsset.name); + cluster.RemoveInstance(); + anythingChanged = true; + } + EditorGUILayout.EndHorizontal(); + + if (GUILayout.Button("Reimport Cluster")) + ReimportCluster(cluster); + } + + protected void NucleusInspector(Nucleus nucleus, ref bool anythingChanged) { + SynapsesInspector(ref anythingChanged); + ActivationInspector(ref anythingChanged); EditorGUILayout.Space(); breakOnWake = EditorGUILayout.Toggle("Break on wake", breakOnWake); @@ -242,11 +258,6 @@ namespace NanoBrain { trace = EditorGUILayout.Toggle("Trace", trace); this.currentNucleus.trace = trace; - serializedObject.ApplyModifiedProperties(); - if (anythingChanged) { - EditorUtility.SetDirty(prefabAsset); - AssetDatabase.SaveAssets(); - } } protected void SynapsesInspector(ref bool anythingChanged) { @@ -361,35 +372,31 @@ namespace NanoBrain { } protected void ActivationInspector(ref bool anythingChanged) { - - if (this.currentNucleus is not Cluster) { - EditorGUILayout.Space(); - showActivation = EditorGUILayout.BeginFoldoutHeaderGroup(showActivation, "Activation"); - if (showActivation) { - if (this.currentNucleus is Neuron neuron) { - if (this.currentNucleus is not MemoryCell) { - EditorGUILayout.BeginHorizontal(); - EditorGUILayout.LabelField("Activation Curve", GUILayout.MinWidth(60)); - if (neuron.curveMax > 0) - EditorGUILayout.CurveField(neuron.curve, Color.cyan, new Rect(0, 0, 1, neuron.curveMax), GUILayout.Width(40)); - else - EditorGUILayout.CurveField(neuron.curve, Color.cyan, new Rect(0, neuron.curveMax, 1, -neuron.curveMax), GUILayout.Width(40)); - Neuron.ActivationType newPreset = (Neuron.ActivationType)EditorGUILayout.EnumPopup(neuron.curvePreset, GUILayout.MinWidth(50)); - anythingChanged |= newPreset != neuron.curvePreset; - neuron.curvePreset = newPreset; - EditorGUILayout.EndHorizontal(); - } - // if (neuron is Receptor receptor2) { - // if (receptor2.nucleiArray == null || receptor2.nucleiArray.Count() == 0) - // receptor2.array = new NucleusArray(neuron); - // } + EditorGUILayout.Space(); + showActivation = EditorGUILayout.BeginFoldoutHeaderGroup(showActivation, "Activation"); + if (showActivation) { + if (this.currentNucleus is Neuron neuron) { + if (this.currentNucleus is not MemoryCell) { + EditorGUILayout.BeginHorizontal(); + EditorGUILayout.LabelField("Activation Curve", GUILayout.MinWidth(60)); + if (neuron.curveMax > 0) + EditorGUILayout.CurveField(neuron.curve, Color.cyan, new Rect(0, 0, 1, neuron.curveMax), GUILayout.Width(40)); + else + EditorGUILayout.CurveField(neuron.curve, Color.cyan, new Rect(0, neuron.curveMax, 1, -neuron.curveMax), GUILayout.Width(40)); + Neuron.ActivationType newPreset = (Neuron.ActivationType)EditorGUILayout.EnumPopup(neuron.curvePreset, GUILayout.MinWidth(50)); + anythingChanged |= newPreset != neuron.curvePreset; + neuron.curvePreset = newPreset; + EditorGUILayout.EndHorizontal(); } - - EditorGUILayout.Space(); + // if (neuron is Receptor receptor2) { + // if (receptor2.nucleiArray == null || receptor2.nucleiArray.Count() == 0) + // receptor2.array = new NucleusArray(neuron); + // } } - EditorGUILayout.EndFoldoutHeaderGroup(); - } + EditorGUILayout.Space(); + } + EditorGUILayout.EndFoldoutHeaderGroup(); } #region Synapses diff --git a/Editor/ClusterViewer.cs b/Editor/ClusterViewer.cs index 2784689..b5727a2 100644 --- a/Editor/ClusterViewer.cs +++ b/Editor/ClusterViewer.cs @@ -447,28 +447,20 @@ namespace NanoBrain { // This is used to 'scale' the output value colors of the nuclei float maxValue = 0; int neuronCount = 0; - //List drawnArrays = new(); - Cluster[] drawnCluster = null; + List drawnNeurons = new(); foreach (Synapse synapse in nucleus.synapses) { if (synapse.neuron == null) continue; - if (synapse.neuron.parent is Cluster cluster && - //cluster.siblingClusters != null && - synapse.neuron.parent != nucleus.parent) { + // Draw multiple synapses to the same neuron only once + if (drawnNeurons.Contains(synapse.neuron)) + continue; + drawnNeurons.Add(synapse.neuron); + + float value = synapse.neuron.outputMagnitude * synapse.weight; + if (value > maxValue) + maxValue = value; - //if (drawnArrays.Contains(cluster.siblingClusters)) - if (drawnCluster is not null && cluster.SameSiblingsAs(drawnCluster)) - continue; - //drawnArrays.Add(cluster.siblingClusters); - drawnCluster = cluster.siblingClusters; - } - if (synapse.neuron is Neuron synapseNeuron) { - float value = synapseNeuron.outputMagnitude * synapse.weight; - // Debug.Log($"{synapse.nucleus.name}: {value} {length(synapse.nucleus.outputValue)} {synapse.weight}"); - if (value > maxValue) - maxValue = value; - } neuronCount++; } @@ -477,23 +469,15 @@ namespace NanoBrain { float margin = 10 + spacing / 2; int row = 0; - //drawnArrays = new(); - drawnCluster = null; + drawnNeurons = new(); foreach (Synapse synapse in nucleus.synapses) { if (synapse.neuron is null) continue; - if (synapse.neuron.parent is Cluster cluster && - //cluster.siblingClusters != null && - synapse.neuron.parent != nucleus.parent) { + if (drawnNeurons.Contains(synapse.neuron)) + continue; + drawnNeurons.Add(synapse.neuron); - // if (drawnArrays.Contains(cluster.siblingClusters)) - // continue; - // drawnArrays.Add(cluster.siblingClusters); - if (drawnCluster is not null && cluster.SameSiblingsAs(drawnCluster)) - continue; - drawnCluster = cluster.siblingClusters; - } Vector3 pos = new(250, margin + row * spacing, 0.0f); Handles.color = Color.white; Handles.DrawLine(parentPos, pos); @@ -502,18 +486,10 @@ namespace NanoBrain { if (maxValue == 0 || !float.IsFinite(maxValue)) maxValue = 1; float brightness = 0; - if (synapse.neuron is Neuron synapseNeuron) - brightness = synapseNeuron.outputMagnitude * synapse.weight / maxValue; + brightness = synapse.neuron.outputMagnitude * synapse.weight / maxValue; color = new Color(brightness, brightness, brightness, 1f); } - if (synapse.neuron.parent != null && synapse.neuron.parent != this.currentNucleus.parent) { - // the synapse nucleus is part of a subcluster - //DrawNucleus(synapse.neuron.parent, pos, maxValue, size, color); - DrawNucleus(synapse.neuron, pos, size, color); - } - else { - DrawNucleus(synapse.neuron, pos, size, color); - } + DrawNucleus(synapse.neuron, pos, size, color); row++; } } @@ -619,7 +595,7 @@ namespace NanoBrain { } } - private void DrawCluster(Cluster cluster, Vector3 position, Color color, float size) { + protected void DrawCluster(Cluster cluster, Vector3 position, Color color, float size) { GUIStyle labelTextStyle = new(EditorStyles.label) { normal = { textColor = Color.white }, fontStyle = FontStyle.Bold, @@ -704,7 +680,7 @@ namespace NanoBrain { Handles.DrawLine(from, to); } - private void HandleMouseHover(Nucleus nucleus, Rect rect) { + protected void HandleMouseHover(Nucleus nucleus, Rect rect) { GUIContent tooltip; if (nucleus is Neuron neuron) { tooltip = new( diff --git a/Runtime/Scripts/Core/Cluster.cs b/Runtime/Scripts/Core/Cluster.cs index f58f539..acb312a 100644 --- a/Runtime/Scripts/Core/Cluster.cs +++ b/Runtime/Scripts/Core/Cluster.cs @@ -468,9 +468,10 @@ namespace NanoBrain { } public void AddArrayReceiver(Nucleus receiverToAdd, float weight = 1) { - foreach (Cluster cluster in this.siblingClusters) { - cluster.defaultOutput.AddReceiver(receiverToAdd, weight); - } + this.defaultOutput.AddReceiver(receiverToAdd, weight); + // foreach (Cluster cluster in this.siblingClusters) { + // cluster.defaultOutput.AddReceiver(receiverToAdd, weight); + // } }