From abbce409927a730b196e9e793b8e54ad30582e9b Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Tue, 3 Mar 2026 12:19:41 +0100 Subject: [PATCH] Process clusterreceptor per thingId --- ClusterReceptor.cs | 72 +++++++++++++++++++++++++++++++++++++- Editor/ClusterInspector.cs | 21 ++++------- Neuron.cs | 5 ++- 3 files changed, 81 insertions(+), 17 deletions(-) diff --git a/ClusterReceptor.cs b/ClusterReceptor.cs index b5aef2c..2ecbd8f 100644 --- a/ClusterReceptor.cs +++ b/ClusterReceptor.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using UnityEngine; using Unity.Mathematics; using static Unity.Mathematics.math; +using System.Linq; [Serializable] public class ClusterReceptor : Cluster, IReceptor { @@ -71,7 +72,7 @@ public class ClusterReceptor : Cluster, IReceptor { foreach (Nucleus outputNucleus in clusterElement.clusterNuclei) { if (outputNucleus is not Neuron output) continue; - + // this should be clusterElement.outputs, // but outputs is not updated when correctly and may contain old data... foreach (Nucleus receiver in output.receivers) { @@ -138,4 +139,73 @@ public class ClusterReceptor : Cluster, IReceptor { this._array ??= new NucleusArray(this.parent); this._array.ProcessStimulus(thingId, inputValue, thingName); } + + private Dictionary thingReceivers = new(); + + public virtual void ProcessStimulus(Neuron input, Vector3 inputValue, int thingId = 0, string thingName = null) { + inputValue = input.Activator(inputValue); + + if (!thingReceivers.TryGetValue(thingId, out ClusterReceptor selectedReceiver)) + selectedReceiver = FindReceiver(thingId, inputValue); + if (selectedReceiver == null) + return; + + if (thingName != null) { + string baseName = selectedReceiver.name; + int colonPos = selectedReceiver.name.IndexOf(":"); + if (colonPos > 0) + baseName = selectedReceiver.name[..colonPos]; + selectedReceiver.name = baseName + ": " + thingName; + } + + int inputIx = this.GetNucleusIndex(this.clusterNuclei, input); + if (inputIx < 0) + return; + + if (selectedReceiver.clusterNuclei[inputIx] is Neuron selectedNeuron) + selectedNeuron.ProcessStimulusDirect(inputValue); + } + + private ClusterReceptor FindReceiver(int thingId, float3 inputValue) { + // No existing nucleus for this thing + float inputMagnitude = length(inputValue); + ClusterReceptor selectedReceiver = null; + float selectedMagnitude = 0; + foreach (ClusterReceptor receiver in nucleiArray.Cast()) { + if (thingReceivers.ContainsValue(receiver) == false) { + // We found an unusued receiver + thingReceivers.Add(thingId, receiver); + return receiver; + } + else if (receiver.isSleeping) { + // A sleeping receiver is not active and can therefore always be used + thingReceivers.Add(thingId, receiver); + return receiver; + } + else if (selectedReceiver == null) { + // If we haven't found a receiver yet, just start by taking the first + selectedReceiver = receiver; + selectedMagnitude = length(selectedReceiver.outputValue); + } + // Look for the receiver with the lowest magnitude + else { + float magnitude = length(receiver.outputValue); + + if (magnitude < inputMagnitude && length(receiver.outputValue) < selectedMagnitude) { + selectedReceiver = receiver; + selectedMagnitude = length(selectedReceiver.outputValue); + } + } + } + if (selectedReceiver != null) { + // Replace the receiver + // Find the thingId current associated with the receiver + int keyToRemove = thingReceivers.FirstOrDefault(r => r.Value.Equals(selectedReceiver)).Key; + if (keyToRemove != 0 || thingReceivers.ContainsKey(keyToRemove)) + thingReceivers.Remove(keyToRemove); + // And add the new association + thingReceivers.Add(thingId, selectedReceiver); + } + return selectedReceiver; + } } \ No newline at end of file diff --git a/Editor/ClusterInspector.cs b/Editor/ClusterInspector.cs index 5c18824..2ec258a 100644 --- a/Editor/ClusterInspector.cs +++ b/Editor/ClusterInspector.cs @@ -806,16 +806,8 @@ public class ClusterInspector : Editor { void OnSceneGUI(SceneView sceneView) { if (this.gameObject != null) { - // if (this.currentNucleus is ReceptorArray receptor && expandArray) { - // foreach (Nucleus nucleus in receptor.instances) { - // Vector3 worldVector = this.gameObject.transform.TransformVector(nucleus.outputValue); - // Handles.color = Color.yellow; - // Handles.DrawLine(this.gameObject.transform.position, this.gameObject.transform.position + worldVector); - // } - // } - // else { - if (this.currentNucleus is Receptor receptor1) { - foreach (Nucleus nucleus in receptor1.nucleiArray) { + if (this.currentNucleus is IReceptor receptor) { + foreach (Nucleus nucleus in receptor.nucleiArray) { Vector3 worldVector = this.gameObject.transform.TransformVector(nucleus.outputValue); Handles.color = Color.yellow; Handles.DrawLine(this.gameObject.transform.position, this.gameObject.transform.position + worldVector); @@ -825,9 +817,7 @@ public class ClusterInspector : Editor { Vector3 worldVector = this.gameObject.transform.TransformVector(this.currentNucleus.outputValue); Handles.color = Color.yellow; Handles.DrawLine(this.gameObject.transform.position, this.gameObject.transform.position + worldVector); - } - // } } } @@ -1016,7 +1006,7 @@ public class ClusterInspector : Editor { // so we have to change all synapses to this nucleus array elements int oldNucleusIx = subCluster.GetNucleusIndex(subCluster.clusterNuclei, synapse.nucleus); int newNucleusIx = subCluster.GetNucleusIndex(subCluster.clusterNuclei, newNucleus); - foreach(Nucleus element in receptor.nucleiArray) { + foreach (Nucleus element in receptor.nucleiArray) { if (element is not ClusterReceptor clusterReceptor) continue; // Get the same neuron as the synapse.nucleus in a different element @@ -1029,14 +1019,15 @@ public class ClusterInspector : Editor { Nucleus newElementNucleus = clusterReceptor.clusterNuclei[newNucleusIx]; if (newElementNucleus is not Neuron newElementNeuron) continue; - + oldElementNeuron.RemoveReceiver(this.currentNucleus); newElementNeuron.AddReceiver(this.currentNucleus); // Now find the synapse which pointed to the old Neuron // Synapse synapseForUpdate = this.currentNucleus.GetSynapse(oldElementNeuron); // synapseForUpdate.nucleus = newElementNeuron; } - } else { + } + else { // it is a neuron in a subcluster synapseNeuron.RemoveReceiver(this.currentNucleus); newNucleus.AddReceiver(this.currentNucleus); diff --git a/Neuron.cs b/Neuron.cs index 8fcc529..92b9c7d 100644 --- a/Neuron.cs +++ b/Neuron.cs @@ -312,7 +312,10 @@ public class Neuron : Nucleus { #endregion Receivers public override void ProcessStimulus(Vector3 inputValue, int thingId = 0, string thingName = null) { - ProcessStimulusDirect(inputValue, thingId, thingName); + if (this.parent is ClusterReceptor clusterReceptor) { + clusterReceptor.ProcessStimulus(this, inputValue, thingId, thingName); + } else + ProcessStimulusDirect(inputValue, thingId, thingName); // this.stale = 0; // this.bias = inputValue; // this.parent.UpdateFromNucleus(this);