Deserialization first version

This commit is contained in:
Pascal Serrarens 2026-07-10 12:49:14 +02:00
parent 27f4237890
commit 85017861b5
6 changed files with 118 additions and 53 deletions

View File

@ -15,12 +15,24 @@ namespace NanoBrain.Unity {
void OnEnable() { void OnEnable() {
clusterPrefab = (ClusterPrefab)target; clusterPrefab = (ClusterPrefab)target;
clusterPrefab.cluster.name = clusterPrefab.name;
view = ClusterView.GetClusterView(serializedObject); view = ClusterView.GetClusterView(serializedObject);
string assetPath = AssetDatabase.GetAssetPath(clusterPrefab);
if (!string.IsNullOrEmpty(assetPath)) {
string folder = System.IO.Path.GetDirectoryName(assetPath);
string jsonPath = System.IO.Path.Combine(folder, clusterPrefab.name + ".json");
if (System.IO.File.Exists(jsonPath)) {
ClusterData newClusterData = Cluster.Import(jsonPath);
clusterPrefab.cluster = new(newClusterData);
}
}
view.currentCluster ??= clusterPrefab.cluster; view.currentCluster ??= clusterPrefab.cluster;
view.currentNucleus = clusterPrefab.cluster.defaultOutput; view.currentNucleus = clusterPrefab.cluster.defaultOutput;
view.selectedOutput = view.currentNucleus; view.selectedOutput = view.currentNucleus;
clusterPrefab.cluster.name = clusterPrefab.name;
clusterPrefab.cluster.Cleanup(); clusterPrefab.cluster.Cleanup();
} }
@ -218,25 +230,25 @@ namespace NanoBrain.Unity {
showSynapses = EditorGUILayout.Foldout(showSynapses, "Synapses", true); showSynapses = EditorGUILayout.Foldout(showSynapses, "Synapses", true);
if (showSynapses) { if (showSynapses) {
EditorGUI.indentLevel--; EditorGUI.indentLevel--;
if (this.view.currentNucleus is Neuron neuron2) { if (this.view.currentNucleus is Neuron neuron) {
Neuron.CombinatorType newCombinator = (Neuron.CombinatorType)EditorGUILayout.EnumPopup("Combinator", neuron2.combinator); Neuron.CombinatorType newCombinator = (Neuron.CombinatorType)EditorGUILayout.EnumPopup("Combinator", neuron.combinator);
anythingChanged |= newCombinator != neuron2.combinator; anythingChanged |= newCombinator != neuron.combinator;
neuron2.combinator = newCombinator; neuron.combinator = newCombinator;
EditorGUIUtility.wideMode = true; EditorGUIUtility.wideMode = true;
float previousLabelWidth = EditorGUIUtility.labelWidth; float previousLabelWidth = EditorGUIUtility.labelWidth;
EditorGUIUtility.labelWidth = 100; EditorGUIUtility.labelWidth = 100;
Vector3 newBias = EditorGUILayout.Vector3Field("Bias", neuron2.bias); Vector3 newBias = EditorGUILayout.Vector3Field("Bias", neuron.bias);
if (newBias != neuron2.bias) { if (newBias != neuron.bias) {
anythingChanged = true; anythingChanged = true;
neuron2.bias = newBias; neuron.bias = newBias;
} }
bool newTrainable = EditorGUILayout.Toggle("Trainable", neuron2.trainable); bool newTrainable = EditorGUILayout.Toggle("Trainable", neuron.trainable);
if (newTrainable != neuron2.trainable) { if (newTrainable != neuron.trainable) {
anythingChanged = true; anythingChanged = true;
neuron2.trainable = newTrainable; neuron.trainable = newTrainable;
} }
EditorGUIUtility.labelWidth = previousLabelWidth; EditorGUIUtility.labelWidth = previousLabelWidth;

View File

@ -41,7 +41,8 @@ namespace NanoBrain.Unity {
); );
propertyExtraHeight = 2 + 2 * EditorGUIUtility.singleLineHeight; propertyExtraHeight = 2 + 2 * EditorGUIUtility.singleLineHeight;
EditorGUI.HelpBox(helpRect, "Selected asset is not a .json file.", MessageType.Error); EditorGUI.HelpBox(helpRect, "Selected asset is not a .json file.", MessageType.Error);
} else }
else
propertyExtraHeight = 0; propertyExtraHeight = 0;
EditorGUI.EndProperty(); EditorGUI.EndProperty();
@ -56,16 +57,19 @@ namespace NanoBrain.Unity {
private readonly Dictionary<EntityId, bool> _invalidCache = new(); private readonly Dictionary<EntityId, bool> _invalidCache = new();
private bool IsInvalidJson(SerializedProperty jsonFileProp) { private bool IsInvalidJson(SerializedProperty jsonFileProp) {
TextAsset current = jsonFileProp.objectReferenceValue as TextAsset; TextAsset jsonFile = jsonFileProp.objectReferenceValue as TextAsset;
if (current == null) return false; if (jsonFile == null)
return false;
EntityId id = current.GetEntityId(); EntityId id = jsonFile.GetEntityId();
if (_invalidCache.TryGetValue(id, out bool invalid)) if (_invalidCache.TryGetValue(id, out bool invalid))
return invalid; return invalid;
string path = AssetDatabase.GetAssetPath(current); string path = AssetDatabase.GetAssetPath(jsonFile);
invalid = !path.EndsWith(".json", System.StringComparison.OrdinalIgnoreCase); invalid = !path.EndsWith(".json", System.StringComparison.OrdinalIgnoreCase);
_invalidCache[id] = invalid; _invalidCache[id] = invalid;
return invalid; return invalid;
} }
} }

View File

@ -44,7 +44,7 @@ namespace NanoBrain.Unity {
EditorGUILayout.Space(); EditorGUILayout.Space();
scroll = EditorGUILayout.BeginScrollView(scroll); scroll = EditorGUILayout.BeginScrollView(scroll);
foreach (var it in items) { foreach (ClusterPrefab it in this.items) {
if (!string.IsNullOrEmpty(search) && it.name.IndexOf(search, StringComparison.OrdinalIgnoreCase) < 0) if (!string.IsNullOrEmpty(search) && it.name.IndexOf(search, StringComparison.OrdinalIgnoreCase) < 0)
continue; continue;

View File

@ -93,7 +93,7 @@ namespace NanoBrain.Unity {
} }
// If a brain has been selected // If a brain has been selected
//if (prefabProp.objectReferenceValue != null) { if (prefabProp.objectReferenceValue != null) {
// Graph is not shown when multi-editing // Graph is not shown when multi-editing
if (property.serializedObject.targetObjects.Length == 1) { if (property.serializedObject.targetObjects.Length == 1) {
UnityEngine.Object targetObject = property.serializedObject.targetObject; UnityEngine.Object targetObject = property.serializedObject.targetObject;
@ -101,11 +101,11 @@ namespace NanoBrain.Unity {
Cluster cluster = SerializedPropertyUtility.GetManagedObjectForProperty(targetObject, property.propertyPath) as Cluster; Cluster cluster = SerializedPropertyUtility.GetManagedObjectForProperty(targetObject, property.propertyPath) as Cluster;
if (cluster != null) { if (cluster != null) {
// if (cluster.version != cluster.prefab.version) { if (cluster.version != cluster.prefab.version) {
// // Debug.Log($"prefab version: {cluster.prefab.version} cluster version: {cluster.version}"); // Debug.Log($"prefab version: {cluster.prefab.version} cluster version: {cluster.version}");
// clusterView.initialized = false; clusterView.initialized = false;
// EditorApplication.delayCall += () => InstantiateCluster(property, clusterView); EditorApplication.delayCall += () => InstantiateCluster(property, clusterView);
// } }
// foldout header rect // foldout header rect
Rect headerRect = new(fieldRect.x, fieldRect.yMax + 4f, fieldRect.width, EditorGUIUtility.singleLineHeight); Rect headerRect = new(fieldRect.x, fieldRect.yMax + 4f, fieldRect.width, EditorGUIUtility.singleLineHeight);
@ -127,7 +127,7 @@ namespace NanoBrain.Unity {
} }
} }
//} }
EditorGUI.indentLevel = indent; EditorGUI.indentLevel = indent;
EditorGUI.EndProperty(); EditorGUI.EndProperty();

View File

@ -25,6 +25,7 @@ namespace NanoBrain {
/// </summary> /// </summary>
/// Cluster should always be created from prefabs /// Cluster should always be created from prefabs
public ClusterPrefab prefab; public ClusterPrefab prefab;
public ClusterJson json;
//[HideInInspector] //[HideInInspector]
@ -129,6 +130,46 @@ namespace NanoBrain {
} }
} }
} }
public Cluster(ClusterData clusterData) {
this.name = clusterData.name;
// First create all neurons
foreach (NeuronData neuronData in clusterData.neurons) {
if (neuronData.type == Type.MemoryCell)
new MemoryCell(this, neuronData.name) {
bias = neuronData.bias,
combinator = neuronData.combinatorType,
activator = neuronData.activationType
};
else
new Neuron(this, neuronData.name) {
bias = neuronData.bias,
combinator = neuronData.combinatorType,
activator = neuronData.activationType
};
}
// Now create the synapses between them
foreach (NeuronData neuronData in clusterData.neurons) {
Neuron receiver = this.GetNeuron(neuronData.name);
foreach (SynapseData synapseData in neuronData.synapses) {
if (synapseData.clusterName != this.name) {
// Add reference to external cluster
ClusterPrefab extPrefab = Resources.Load(synapseData.clusterName) as ClusterPrefab;
if (extPrefab == null)
Debug.LogError($"Could not find cluster Resource {synapseData.clusterName}");
else {
Cluster extCluster = new Cluster(extPrefab, this);
Neuron extNeuron = extCluster.GetNeuron(synapseData.neuronName);
extNeuron.AddReceiver(receiver);
}
}
else {
Neuron sender = this.GetNeuron(synapseData.neuronName);
sender?.AddReceiver(receiver, synapseData.weight);
}
}
}
}
/// <summary> /// <summary>
@ -804,8 +845,9 @@ namespace NanoBrain {
System.IO.File.WriteAllText(path, json); System.IO.File.WriteAllText(path, json);
} }
public ClusterData Import(string path) { public static ClusterData Import(string path) {
string json = File.ReadAllText(path); string json = File.ReadAllText(path);
Debug.Log($"Importing json from {path}");
return JsonUtility.FromJson<ClusterData>(json); return JsonUtility.FromJson<ClusterData>(json);
} }
@ -824,14 +866,16 @@ namespace NanoBrain {
if (nucleus is Neuron neuron) { if (nucleus is Neuron neuron) {
NeuronData neuronData = new(neuron); NeuronData neuronData = new(neuron);
this.neurons.Add(neuronData); this.neurons.Add(neuronData);
} foreach (Synapse synapse in neuron.synapses) {
else if (nucleus is Cluster extCluster) { if (synapse.neuron.parent.name != cluster.name) {
ExternalClusterData clusterData = new(extCluster); ExternalClusterData clusterData = new(synapse.neuron.parent);
this.clusters.Add(clusterData); this.clusters.Add(clusterData);
} }
} }
} }
} }
}
}
[Serializable] [Serializable]
public class ExternalClusterData { public class ExternalClusterData {

View File

@ -737,12 +737,17 @@ namespace NanoBrain {
[Serializable] [Serializable]
public class NeuronData { public class NeuronData {
public string name; public string name;
public Nucleus.Type type;
public Vector3 bias = Vector3.zero; public Vector3 bias = Vector3.zero;
public Neuron.CombinatorType combinatorType; public Neuron.CombinatorType combinatorType;
public List<SynapseData> synapses = new(); public List<SynapseData> synapses = new();
public Neuron.ActivationType activationType; public Neuron.ActivationType activationType;
public NeuronData(Neuron neuron) { public NeuronData(Neuron neuron) {
if (neuron is MemoryCell)
this.type = Nucleus.Type.MemoryCell;
else
this.type = Nucleus.Type.Neuron;
this.name = neuron.name; this.name = neuron.name;
this.bias = neuron.bias; this.bias = neuron.bias;
this.combinatorType = neuron.combinator; this.combinatorType = neuron.combinator;