213 lines
7.2 KiB
C#

using System;
using System.Collections.Generic;
using UnityEngine;
using Unity.Mathematics;
using static Unity.Mathematics.math;
public class Receptor : IReceptor {
[SerializeField]
protected string _name;
public virtual string name {
get => _name;
set => _name = value;
}
public Receptor(Cluster parent) {
this.parent = parent;
if (parent != null)
parent.nuclei.Add(this);
}
public Receptor(ClusterPrefab cluster) {
this.cluster = cluster;
if (cluster != null)
cluster.nuclei.Add(this);
}
// public Receptor(ClusterPrefab cluster, INucleus nucleus) {
// this.cluster = cluster;
// if (cluster != null)
// cluster.nuclei.Add(this);
// this.AddReceiver(nucleus);
// }
public Receptor(Cluster parent, string name, string nucleusName) {
this.parent = parent ?? throw new ArgumentNullException(nameof(parent), "Parent cannot be null.");
this.name = name;
this.parent.nuclei.Add(this);
foreach (INucleus nucleus in parent.inputs) {
if (nucleus != null && nucleus.name == nucleusName) {
this.AddReceiver(nucleus);
}
}
}
[Obsolete("This method is deprecated. Use Receptor() constructor instead.")]
public static Receptor CreateReceptor(Cluster cluster, string nucleusName) {
return new Receptor(cluster, "Receptor", nucleusName);
// if (cluster == null)
// return null;
// Receptor receptor = new(cluster);
// foreach (INucleus nucleus in cluster.inputs) {
// if (nucleus != null && nucleus.name == nucleusName) {
// receptor.AddReceiver(nucleus);
// }
// }
// if (receptor._receivers.Count == 0)
// return null;
// else
// return receptor;
}
private ClusterPrefab cluster;
private Cluster parent;
public virtual IReceptor ShallowCloneTo(Cluster parent) {
Receptor clone = new(parent);
return clone;
}
// public virtual IReceptor ShallowCloneTo(ClusterPrefab parent) {
// Receptor clone = new(parent);
// return clone;
// }
// public virtual IReceptor CloneTo(ClusterPrefab parent) {
// Receptor clone = new(parent);
// foreach (INucleus receiver in this.receivers) {
// clone.AddReceiver(receiver);
// }
// return clone;
// }
public virtual IReceptor Clone() {
Receptor clone = new(this.cluster);
foreach (INucleus receiver in this.receivers) {
clone.AddReceiver(receiver);
}
return clone;
}
class Receiver {
public INucleus nucleus;
public int thingId;
public string thingName;
public Receiver(INucleus nucleus, int thingId, string thingName) {
this.nucleus = nucleus;
this.thingId = thingId;
this.thingName = thingName;
}
}
[SerializeReference]
private List<INucleus> _receivers = new();
public List<INucleus> receivers {
get { return _receivers; }
set { _receivers = value; }
}
protected int[] thingIds; // every receiver can handle a thing with this id
public virtual void AddReceiver(INucleus receivingNucleus, float weight = 1) {
this._receivers.Add(receivingNucleus);
receivingNucleus.AddSynapse(this, weight);
}
public void RemoveReceiver(INucleus receiverNucleus) {
this._receivers.RemoveAll(receiver => receiver == receiverNucleus);
receiverNucleus.synapses.RemoveAll(synapse => synapse.nucleus == this);
}
private int stale = 1000;
private bool _isSleeping = false;
public bool isSleeping => _isSleeping;
public Vector3 localPosition {
set {
this.stale = 0;
this._isSleeping = false;
this._outputValue = value;
}
}
public float distanceResolution = 0.1f;
public float directionResolution = 5;
private float3 _outputValue;
public float3 outputValue {
get { return this._outputValue; }
set {
this.stale = 0;
this._isSleeping = false;
this._outputValue = value;
}
}
public virtual void ProcessStimulus(int thingId, Vector3 newLocalPositionVector, string thingName = null) {
this.localPosition = newLocalPositionVector;
if (this._receivers == null)
return;
thingIds ??= new int[this._receivers.Count];
int receiverIx = 0;
INucleus selectedReceiver = null;
int selectedReceiverIx = 0;
foreach (INucleus receiver in this.receivers) {
if (thingIds[receiverIx] == thingId) {
// We found an existing receiver for this thing
selectedReceiver = receiver;
selectedReceiverIx = receiverIx;
// Do not look any further
break;
}
else if (receiver.isSleeping) {
// A sleeping receiver is not active and can therefore always be used
selectedReceiver = receiver;
selectedReceiverIx = receiverIx;
// Look further because we may find an existing receiver for this thing
}
else if (selectedReceiver == null) {
// If we haven't found a receiver yet, just start by taking the first
selectedReceiver = receiver;
selectedReceiverIx = receiverIx;
}
else if (selectedReceiver.isSleeping == false) {
// If no existing or sleeping receiver is found, we look for
// the receiver with the furthest/least interesting stimulus
if (length(receiver.outputValue) < length(selectedReceiver.outputValue)) {
// Debug.Log($"{selectedReceiver.name}[{selectedReceiverIx}] {length(selectedReceiver.outputValue)}" +
// $" {receiver.name}[{receiverIx}] {length(receiver.outputValue)} ");
selectedReceiver = receiver;
selectedReceiverIx = receiverIx;
}
}
receiverIx++;
}
if (selectedReceiverIx >= thingIds.Length)
return;
thingIds[selectedReceiverIx] = thingId;
if (thingName != null) {
string baseName = selectedReceiver.name;
int colonPos = selectedReceiver.name.IndexOf(":");
if (colonPos > 0)
baseName = selectedReceiver.name.Substring(0, colonPos);
selectedReceiver.name = baseName + ": " + thingName;
}
Debug.Log($"Receiver {selectedReceiver.name}[{selectedReceiverIx}] for thing {thingId}");
selectedReceiver.parent.UpdateStateIsolated();
}
public void UpdateNuclei() {
this.stale++;
this._isSleeping = this.stale > 2;
if (isSleeping)
this._outputValue = Vector3.zero;
}
}