public Symbol ReadSymbol(Model model, JToken o, bool allowNonOperatorInstanceType = false) { var id = Guid.Parse(o["Id"].Value <string>()); if (SymbolRegistry.Entries.ContainsKey(id)) { return(null); // symbol already in registry - nothing to do } var name = o["Name"].Value <string>(); var @namespace = o["Namespace"]?.Value <string>() ?? ""; var symbolChildren = new List <SymbolChild>(); var missingSymbolChildIds = new HashSet <Guid>(); var missingSymbolsIds = new HashSet <Guid>(); foreach (var childJson in ((JArray)o["Children"])) { SymbolChild symbolChild = ReadSymbolChild(model, childJson); if (symbolChild == null) { var childId = Guid.Parse((childJson["Id"] ?? "").Value <string>() ?? string.Empty); var symbolId = Guid.Parse((childJson["SymbolId"] ?? "").Value <string>() ?? string.Empty); Log.Warning($"Skipping child of undefined type {symbolId} in {name}"); if (childId != Guid.Empty) { missingSymbolChildIds.Add(childId); } if (symbolId != Guid.Empty) { missingSymbolsIds.Add(symbolId); } } else { symbolChildren.Add(symbolChild); } } var connections = new List <Symbol.Connection>(); foreach (var c in ((JArray)o["Connections"])) { Symbol.Connection connection = ReadConnection(c); if (connection == null) { Log.Warning($"Skipping invalid connection in {name}"); } else if (missingSymbolChildIds.Contains(connection.TargetParentOrChildId) || missingSymbolChildIds.Contains(connection.SourceParentOrChildId) ) { Log.Warning("Skipping connection to child of undefined type"); } else { connections.Add(connection); } } var orderedInputIds = (from jsonInput in (JArray)o["Inputs"] let idAndValue = ReadSymbolInputDefaults(jsonInput) select idAndValue.Item1).ToArray(); var inputDefaultValues = (from jsonInput in (JArray)o["Inputs"] let idAndValue = ReadSymbolInputDefaults(jsonInput) select idAndValue).ToDictionary(entry => entry.Item1, entry => entry.Item2); var animatorData = (JArray)o["Animator"]; string namespaceId = id.ToString().ToLower().Replace('-', '_'); string instanceTypeName = "T3.Operators.Types.Id_" + namespaceId + "." + name + ", Operators, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null"; Type instanceType = Type.GetType(instanceTypeName); if (instanceType == null) { if (allowNonOperatorInstanceType) { instanceType = typeof(object); } else { throw new Exception($"The type for '{instanceTypeName}' could not be found in Operator assembly."); } } var symbol = new Symbol(instanceType, id, orderedInputIds, symbolChildren) { Name = name, Namespace = @namespace, }; symbol.Connections.AddRange(connections); if (animatorData != null) { symbol.Animator.Read(animatorData); } foreach (var input in symbol.InputDefinitions) { // if no entry is present just the value default is used, happens for new inputs if (inputDefaultValues.TryGetValue(input.Id, out var jsonDefaultValue)) { input.DefaultValue.SetValueFromJson(jsonDefaultValue); } } var jAudioClipArray = (JArray)o[nameof(symbol.AudioClips)]; if (jAudioClipArray != null) { foreach (var c in jAudioClipArray) { AudioClip clip = AudioClip.FromJson(c); symbol.AudioClips.Add(clip); } } return(symbol); }