using UnityEngine; using System.Collections; using System.Collections.Generic; using System; using System.Reflection; using System.Globalization; using BehaviorDesigner.Runtime.Tasks; namespace BehaviorDesigner.Runtime { public class JSONDeserialization : UnityEngine.Object { public struct TaskField { public TaskField(Task t, FieldInfo f) { task = t; fieldInfo = f; } public Task task; public FieldInfo fieldInfo; } private static Dictionary> taskIDs = null; public static Dictionary> TaskIDs { get { return taskIDs; } set { taskIDs = value; } } private static GlobalVariables globalVariables = null; public static bool updatedSerialization = true; private static Dictionary> serializationCache = new Dictionary>(); public static void Load(TaskSerializationData taskData, BehaviorSource behaviorSource, bool loadTasks) { behaviorSource.EntryTask = null; behaviorSource.RootTask = null; behaviorSource.DetachedTasks = null; behaviorSource.Variables = null; Dictionary dict; if (!serializationCache.TryGetValue(taskData.JSONSerialization.GetHashCode(), out dict)) { dict = MiniJSON.Deserialize(taskData.JSONSerialization) as Dictionary; serializationCache.Add(taskData.JSONSerialization.GetHashCode(), dict); } if (dict == null) { Debug.Log("Failed to deserialize"); return; } taskIDs = new Dictionary>(); var treeVersion = new Version(taskData.Version); updatedSerialization = treeVersion.CompareTo(new Version("1.5.7")) >= 0; var IDtoTask = new Dictionary(); // deserialize the variables first so the tasks can reference them DeserializeVariables(behaviorSource, dict, taskData.fieldSerializationData.unityObjects); // Local behavior trees do not need to consume external behavior tree tasks at edit time. if (!loadTasks) { return; } if (dict.ContainsKey("EntryTask")) { behaviorSource.EntryTask = DeserializeTask(behaviorSource, dict["EntryTask"] as Dictionary, ref IDtoTask, taskData.fieldSerializationData.unityObjects); } if (dict.ContainsKey("RootTask")) { behaviorSource.RootTask = DeserializeTask(behaviorSource, dict["RootTask"] as Dictionary, ref IDtoTask, taskData.fieldSerializationData.unityObjects); } if (dict.ContainsKey("DetachedTasks")) { var detachedTasks = new List(); foreach (Dictionary detachedTaskDict in (dict["DetachedTasks"] as IEnumerable)) { detachedTasks.Add(DeserializeTask(behaviorSource, detachedTaskDict, ref IDtoTask, taskData.fieldSerializationData.unityObjects)); } behaviorSource.DetachedTasks = detachedTasks; } // deserialization is complete besides assigning the correct tasks based off of the id if (taskIDs != null && taskIDs.Count > 0) { foreach (TaskField taskField in taskIDs.Keys) { var idList = taskIDs[taskField] as List; var fieldType = taskField.fieldInfo.FieldType; if (taskField.fieldInfo.FieldType.IsArray) { // task array var count = 0; for (int i = 0; i < idList.Count; ++i) { var task = IDtoTask[idList[i]]; if (task.GetType().Equals(fieldType.GetElementType()) || task.GetType().IsSubclassOf(fieldType.GetElementType())) { count++; } } var taskArray = Array.CreateInstance(fieldType.GetElementType(), count); int index = 0; for (int i = 0; i < idList.Count; ++i) { var task = IDtoTask[idList[i]]; if (task.GetType().Equals(fieldType.GetElementType()) || task.GetType().IsSubclassOf(fieldType.GetElementType())) { taskArray.SetValue(task, index); index++; } } taskField.fieldInfo.SetValue(taskField.task, taskArray); } else if (IDtoTask.TryGetValue(idList[0], out var idTask)) { // single task if (idTask.GetType().Equals(taskField.fieldInfo.FieldType) || idTask.GetType().IsSubclassOf(taskField.fieldInfo.FieldType)) { taskField.fieldInfo.SetValue(taskField.task, idTask); } } } taskIDs = null; } } public static void Load(string serialization, GlobalVariables globalVariables, string version) { if (globalVariables == null) return; var dict = MiniJSON.Deserialize(serialization) as Dictionary; if (dict == null) { Debug.Log("Failed to deserialize"); return; } if (globalVariables.VariableData == null) { globalVariables.VariableData = new VariableSerializationData(); } var variableVersion = new Version(globalVariables.Version); updatedSerialization = variableVersion.CompareTo(new Version("1.5.7")) >= 0; DeserializeVariables(globalVariables, dict, globalVariables.VariableData.fieldSerializationData.unityObjects); } private static void DeserializeVariables(IVariableSource variableSource, Dictionary dict, List unityObjects) { object dictObj; if (dict.TryGetValue("Variables", out dictObj)) { var variables = new List(); var variablesList = dictObj as IList; for (int i = 0; i < variablesList.Count; ++i) { var sharedVariable = DeserializeSharedVariable(variablesList[i] as Dictionary, variableSource, true, unityObjects); variables.Add(sharedVariable); } variableSource.SetAllVariables(variables); } } public static Task DeserializeTask(BehaviorSource behaviorSource, Dictionary dict, ref Dictionary IDtoTask, List unityObjects) { Task task = null; try { var type = TaskUtility.GetTypeWithinAssembly(dict["Type"] as string); // Change the type to an unknown type if the type doesn't exist anymore. if (type == null) { if (dict.ContainsKey("Children")) { type = typeof(UnknownParentTask); } else { type = typeof(UnknownTask); } } task = TaskUtility.CreateInstance(type) as Task; if (task is UnknownTask) { var unknownTask = task as UnknownTask; unknownTask.JSONSerialization = MiniJSON.Serialize(dict); } } catch (Exception /*e*/) { } // What happened? if (task == null) { return null; } task.Owner = behaviorSource.Owner.GetObject() as Behavior; task.ID = Convert.ToInt32(dict["ID"], CultureInfo.InvariantCulture); object dictObj; if (dict.TryGetValue("Name", out dictObj)) { task.FriendlyName = (string)dictObj; } if (dict.TryGetValue("Instant", out dictObj)) { task.IsInstant = Convert.ToBoolean(dictObj, CultureInfo.InvariantCulture); } if (dict.TryGetValue("Disabled", out dictObj)) { task.Disabled = Convert.ToBoolean(dictObj, CultureInfo.InvariantCulture); } IDtoTask.Add(task.ID, task); #if UNITY_EDITOR || DLL_DEBUG || DLL_RELEASE task.NodeData = DeserializeNodeData(dict["NodeData"] as Dictionary, task); // give a little warning if the task is an unknown type if (task.GetType().Equals(typeof(UnknownTask)) || task.GetType().Equals(typeof(UnknownParentTask))) { if (!task.FriendlyName.Contains("Unknown ")) { task.FriendlyName = string.Format("Unknown {0}", task.FriendlyName); } task.NodeData.Comment = "Unknown Task. Right click and Replace to locate new task."; } #endif DeserializeObject(task, task, dict, behaviorSource, unityObjects); if (task is ParentTask && dict.TryGetValue("Children", out dictObj)) { var parentTask = task as ParentTask; if (parentTask != null) { foreach (Dictionary childDict in (dictObj as IEnumerable)) { var child = DeserializeTask(behaviorSource, childDict, ref IDtoTask, unityObjects); int index = (parentTask.Children == null ? 0 : parentTask.Children.Count); parentTask.AddChild(child, index); } } } return task; } #if UNITY_EDITOR || DLL_DEBUG || DLL_RELEASE private static NodeData DeserializeNodeData(Dictionary dict, Task task) { var nodeData = new NodeData(); object dictObj; if (dict.TryGetValue("Offset", out dictObj)) { nodeData.Offset = StringToVector2((string)dictObj); } if (dict.TryGetValue("FriendlyName", out dictObj)) { task.FriendlyName = (string)dictObj; } if (dict.TryGetValue("Comment", out dictObj)) { nodeData.Comment = (string)dictObj; } if (dict.TryGetValue("IsBreakpoint", out dictObj)) { nodeData.IsBreakpoint = Convert.ToBoolean(dictObj, CultureInfo.InvariantCulture); } if (dict.TryGetValue("Collapsed", out dictObj)) { nodeData.Collapsed = Convert.ToBoolean(dictObj, CultureInfo.InvariantCulture); } if (dict.TryGetValue("ColorIndex", out dictObj)) { nodeData.ColorIndex = Convert.ToInt32(dictObj, CultureInfo.InvariantCulture); } if (dict.TryGetValue("WatchedFields", out dictObj)) { nodeData.WatchedFieldNames = new List(); nodeData.WatchedFields = new List(); var objectValues = dictObj as IList; for (int i = 0; i < objectValues.Count; ++i) { var field = task.GetType().GetField((string)objectValues[i], BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (field != null) { nodeData.WatchedFieldNames.Add(field.Name); nodeData.WatchedFields.Add(field); } } } return nodeData; } #endif // If the serialized variable is from the source then just create a new variable and don't check to see if it already exists private static SharedVariable DeserializeSharedVariable(Dictionary dict, IVariableSource variableSource, bool fromSource, List unityObjects) { if (dict == null) { return null; } SharedVariable sharedVariable = null; object nameObj; // the shared variable may be referencing the variable within the behavior if (!fromSource && variableSource != null && dict.TryGetValue("Name", out nameObj) && (BehaviorManager.IsPlaying || !dict.ContainsKey("IsDynamic"))) { object globalObj; dict.TryGetValue("IsGlobal", out globalObj); if (!dict.TryGetValue("IsGlobal", out globalObj) || Convert.ToBoolean(globalObj, CultureInfo.InvariantCulture) == false) { sharedVariable = variableSource.GetVariable(nameObj as string); } else { if (globalVariables == null) { globalVariables = GlobalVariables.Instance; } if (globalVariables != null) { sharedVariable = globalVariables.GetVariable(nameObj as string); } } } var variableType = TaskUtility.GetTypeWithinAssembly(dict["Type"] as string); if (variableType == null) { return null; } bool typesEqual = true; if (sharedVariable == null || !(typesEqual = sharedVariable.GetType().Equals(variableType))) { sharedVariable = TaskUtility.CreateInstance(variableType) as SharedVariable; sharedVariable.Name = dict["Name"] as string; object dictValue; if (dict.TryGetValue("IsShared", out dictValue)) { sharedVariable.IsShared = Convert.ToBoolean(dictValue, CultureInfo.InvariantCulture); } if (dict.TryGetValue("IsGlobal", out dictValue)) { sharedVariable.IsGlobal = Convert.ToBoolean(dictValue, CultureInfo.InvariantCulture); } if (dict.TryGetValue("IsDynamic", out dictValue)) { sharedVariable.IsDynamic = Convert.ToBoolean(dictValue, CultureInfo.InvariantCulture); // The new dynamic variable has been created. if (BehaviorManager.IsPlaying) { variableSource.SetVariable(sharedVariable.Name, sharedVariable); } } #if UNITY_EDITOR if (dict.TryGetValue("Tooltip", out dictValue)) { sharedVariable.Tooltip = dictValue as string; } #endif if (!sharedVariable.IsGlobal && dict.TryGetValue("PropertyMapping", out dictValue)) { sharedVariable.PropertyMapping = dictValue as string; if (dict.TryGetValue("PropertyMappingOwner", out dictValue)) { sharedVariable.PropertyMappingOwner = IndexToUnityObject(Convert.ToInt32(dictValue, CultureInfo.InvariantCulture), unityObjects) as GameObject; } sharedVariable.InitializePropertyMapping(variableSource as BehaviorSource); } // if the types are not equal then this shared variable used to be a different type so it should be shared if (!typesEqual) { sharedVariable.IsShared = true; } DeserializeObject(null, sharedVariable, dict, variableSource, unityObjects); } return sharedVariable; } private static void DeserializeObject(Task task, object obj, Dictionary dict, IVariableSource variableSource, List unityObjects) { if (dict == null || obj == null) return; var fields = TaskUtility.GetSerializableFields(obj.GetType()); for (int i = 0; i < fields.Length; ++i) { object dictObject = null; var fieldKey = updatedSerialization ? (fields[i].FieldType.Name + fields[i].Name) : (fields[i].FieldType.Name.GetHashCode() + fields[i].Name.GetHashCode()).ToString(); if (!dict.TryGetValue(fieldKey, out dictObject)) { UnityEngine.Serialization.FormerlySerializedAsAttribute formallySerializedAs; if ((formallySerializedAs = fields[i].GetCustomAttribute(typeof(UnityEngine.Serialization.FormerlySerializedAsAttribute), true) as UnityEngine.Serialization.FormerlySerializedAsAttribute) != null) { dict.TryGetValue(fields[i].FieldType.Name + formallySerializedAs.oldName, out dictObject); } } if (dictObject != null) { if (typeof(IList).IsAssignableFrom(fields[i].FieldType)) { var objectValues = dictObject as IList; if (objectValues != null) { Type type; if (fields[i].FieldType.IsArray) { type = fields[i].FieldType.GetElementType(); } else { var baseFieldType = fields[i].FieldType; #if NETFX_CORE && !UNITY_EDITOR while (!baseFieldType.IsGenericType()) { baseFieldType = baseFieldType.BaseType(); } #else while (!baseFieldType.IsGenericType) { baseFieldType = baseFieldType.BaseType; } #endif type = baseFieldType.GetGenericArguments()[0]; } bool isIDList = (type.Equals(typeof(Task)) || type.IsSubclassOf(typeof(Task))) && !TaskUtility.HasAttribute(fields[i], typeof(InspectTaskAttribute)); if (isIDList) { if (taskIDs != null) { var objectList = new List(); for (int j = 0; j < objectValues.Count; ++j) { objectList.Add(Convert.ToInt32(objectValues[j], CultureInfo.InvariantCulture)); } taskIDs.Add(new TaskField(task, fields[i]), objectList); } } else { if (fields[i].FieldType.IsArray) { var objectArray = Array.CreateInstance(type, objectValues.Count); for (int j = 0; j < objectValues.Count; ++j) { if (objectValues[j] == null) { objectArray.SetValue(null, j); continue; } Type elementType; object value; if (objectValues[j] is Dictionary) { var elementDict = (Dictionary)objectValues[j]; elementType = TaskUtility.GetTypeWithinAssembly((string)elementDict["Type"]); if (!elementDict.TryGetValue("Value", out value)) { value = objectValues[j]; } } else { elementType = type; value = objectValues[j]; } var element = ValueToObject(task, elementType, value, variableSource, unityObjects); if (!type.IsInstanceOfType(element)) { objectArray.SetValue(null, j); continue; } objectArray.SetValue(element, j); } fields[i].SetValue(obj, objectArray); } else { IList objectList; #if NETFX_CORE && !UNITY_EDITOR if (fields[i].FieldType.IsGenericType()) { #else if (fields[i].FieldType.IsGenericType) { #endif objectList = TaskUtility.CreateInstance(typeof(List<>).MakeGenericType(type)) as IList; } else { objectList = TaskUtility.CreateInstance(fields[i].FieldType) as IList; } for (int j = 0; j < objectValues.Count; ++j) { if (objectValues[j] == null) { objectList.Add(null); continue; } Type elementType = type; object objVal = objectValues[j]; if (objVal is Dictionary) { var elementDict = (Dictionary)objVal; object elementObj; if (elementDict.TryGetValue("Type", out elementObj)) { elementType = TaskUtility.GetTypeWithinAssembly((string)elementObj); if (!elementDict.TryGetValue("Value", out objVal)) { objVal = objectValues[j]; } } } var value = ValueToObject(task, elementType, objVal, variableSource, unityObjects); if (value != null && !value.Equals(null)) { objectList.Add(value); } else { objectList.Add(null); } } fields[i].SetValue(obj, objectList); } } } } else { var type = fields[i].FieldType; // If the type is a Task then the task ID was stored. Because the task may not exist yet, wait to reference the task until all deserialization has been completed if (type.Equals(typeof(Task)) || type.IsSubclassOf(typeof(Task))) { if (TaskUtility.HasAttribute(fields[i], typeof(InspectTaskAttribute))) { var referencedTaskDict = dictObject as Dictionary; var referencedTaskType = TaskUtility.GetTypeWithinAssembly(referencedTaskDict["Type"] as string); if (referencedTaskType != null) { var referencedTask = TaskUtility.CreateInstance(referencedTaskType) as Task; DeserializeObject(referencedTask, referencedTask, referencedTaskDict, variableSource, unityObjects); fields[i].SetValue(task, referencedTask); } } else if (taskIDs != null) { var idList = new List(); idList.Add(Convert.ToInt32(dictObject, CultureInfo.InvariantCulture)); taskIDs.Add(new TaskField(task, fields[i]), idList); } } else { var value = ValueToObject(task, type, dictObject, variableSource, unityObjects); if (value != null && !value.Equals(null) && type.IsAssignableFrom(value.GetType())) { fields[i].SetValue(obj, value); } } } #if NETFX_CORE && !UNITY_EDITOR } else if (typeof(SharedVariable).IsAssignableFrom(fields[i].FieldType) && !fields[i].FieldType.GetTypeInfo().IsAbstract) { #else } else if (typeof(SharedVariable).IsAssignableFrom(fields[i].FieldType) && !fields[i].FieldType.IsAbstract) { #endif if (dict.TryGetValue((fields[i].FieldType.Name.GetHashCode() + fields[i].Name.GetHashCode()).ToString(), out dictObject)) { var sharedVariable = TaskUtility.CreateInstance(fields[i].FieldType) as SharedVariable; sharedVariable.SetValue(ValueToObject(task, fields[i].FieldType, dictObject, variableSource, unityObjects)); fields[i].SetValue(obj, sharedVariable); } else { var sharedVariable = TaskUtility.CreateInstance(fields[i].FieldType) as SharedVariable; var sharedVariableValue = (fields[i].GetValue(obj) as SharedVariable); if (sharedVariableValue != null) { sharedVariable.SetValue(sharedVariableValue.GetValue()); } fields[i].SetValue(obj, sharedVariable); } } } } private static object ValueToObject(Task task, Type type, object obj, IVariableSource variableSource, List unityObjects) { if (typeof(SharedVariable).IsAssignableFrom(type)) { var value = DeserializeSharedVariable(obj as Dictionary, variableSource, false, unityObjects); if (value == null && !type.IsAbstract) { // Create a blank shared variable so a value is assigned value = TaskUtility.CreateInstance(type) as SharedVariable; } return value; } else if (type.Equals(typeof(UnityEngine.Object)) || type.IsSubclassOf(typeof(UnityEngine.Object))) { return IndexToUnityObject(Convert.ToInt32(obj, CultureInfo.InvariantCulture), unityObjects); #if NETFX_CORE && !UNITY_EDITOR } else if (type.IsPrimitive() || type.Equals(typeof(string)) ) { #else } else if (type.IsPrimitive || type.Equals(typeof(string)) ) { #endif try { return Convert.ChangeType(obj, type); } catch (Exception /*e*/) { return null; } } else if (type.IsSubclassOf(typeof(Enum))) { try { return Enum.Parse(type, (string)obj); } catch (Exception /*e*/) { return null; } } else if (type.Equals(typeof(Vector2))) { return StringToVector2((string)obj); } else if (type.Equals(typeof(Vector2Int))) { return StringToVector2Int((string)obj); } else if (type.Equals(typeof(Vector3))) { return StringToVector3((string)obj); } else if (type.Equals(typeof(Vector3Int))) { return StringToVector3Int((string)obj); } else if (type.Equals(typeof(Vector4))) { return StringToVector4((string)obj); } else if (type.Equals(typeof(Quaternion))) { return StringToQuaternion((string)obj); } else if (type.Equals(typeof(Matrix4x4))) { return StringToMatrix4x4((string)obj); } else if (type.Equals(typeof(Color))) { return StringToColor((string)obj); } else if (type.Equals(typeof(Rect))) { return StringToRect((string)obj); } else if (type.Equals(typeof(LayerMask))) { return ValueToLayerMask(Convert.ToInt32(obj, CultureInfo.InvariantCulture)); } else if (type.Equals(typeof(AnimationCurve))) { return ValueToAnimationCurve((Dictionary)obj); } else { var unknownObj = TaskUtility.CreateInstance(type); DeserializeObject(task, unknownObj, obj as Dictionary, variableSource, unityObjects); return unknownObj; } } private static Vector2 StringToVector2(string vector2String) { var stringSplit = vector2String.Substring(1, vector2String.Length - 2).Split(','); return new Vector2(float.Parse(stringSplit[0], CultureInfo.InvariantCulture), float.Parse(stringSplit[1], CultureInfo.InvariantCulture)); } private static Vector2Int StringToVector2Int(string vector2String) { var stringSplit = vector2String.Substring(1, vector2String.Length - 2).Split(','); return new Vector2Int(int.Parse(stringSplit[0], CultureInfo.InvariantCulture), int.Parse(stringSplit[1], CultureInfo.InvariantCulture)); } private static Vector3 StringToVector3(string vector3String) { var stringSplit = vector3String.Substring(1, vector3String.Length - 2).Split(','); return new Vector3(float.Parse(stringSplit[0], CultureInfo.InvariantCulture), float.Parse(stringSplit[1], CultureInfo.InvariantCulture), float.Parse(stringSplit[2], CultureInfo.InvariantCulture)); } private static Vector3Int StringToVector3Int(string vector3String) { var stringSplit = vector3String.Substring(1, vector3String.Length - 2).Split(','); return new Vector3Int(int.Parse(stringSplit[0], CultureInfo.InvariantCulture), int.Parse(stringSplit[1], CultureInfo.InvariantCulture), int.Parse(stringSplit[2], CultureInfo.InvariantCulture)); } private static Vector4 StringToVector4(string vector4String) { var stringSplit = vector4String.Substring(1, vector4String.Length - 2).Split(','); return new Vector4(float.Parse(stringSplit[0], CultureInfo.InvariantCulture), float.Parse(stringSplit[1], CultureInfo.InvariantCulture), float.Parse(stringSplit[2], CultureInfo.InvariantCulture), float.Parse(stringSplit[3], CultureInfo.InvariantCulture)); } private static Quaternion StringToQuaternion(string quaternionString) { var stringSplit = quaternionString.Substring(1, quaternionString.Length - 2).Split(','); return new Quaternion(float.Parse(stringSplit[0]), float.Parse(stringSplit[1], CultureInfo.InvariantCulture), float.Parse(stringSplit[2], CultureInfo.InvariantCulture), float.Parse(stringSplit[3], CultureInfo.InvariantCulture)); } private static Matrix4x4 StringToMatrix4x4(string matrixString) { var stringSplit = matrixString.Split(null); var matrix = new Matrix4x4(); matrix.m00 = float.Parse(stringSplit[0], CultureInfo.InvariantCulture); matrix.m01 = float.Parse(stringSplit[1], CultureInfo.InvariantCulture); matrix.m02 = float.Parse(stringSplit[2], CultureInfo.InvariantCulture); matrix.m03 = float.Parse(stringSplit[3], CultureInfo.InvariantCulture); matrix.m10 = float.Parse(stringSplit[4], CultureInfo.InvariantCulture); matrix.m11 = float.Parse(stringSplit[5], CultureInfo.InvariantCulture); matrix.m12 = float.Parse(stringSplit[6], CultureInfo.InvariantCulture); matrix.m13 = float.Parse(stringSplit[7], CultureInfo.InvariantCulture); matrix.m20 = float.Parse(stringSplit[8], CultureInfo.InvariantCulture); matrix.m21 = float.Parse(stringSplit[9], CultureInfo.InvariantCulture); matrix.m22 = float.Parse(stringSplit[10], CultureInfo.InvariantCulture); matrix.m23 = float.Parse(stringSplit[11], CultureInfo.InvariantCulture); matrix.m30 = float.Parse(stringSplit[12], CultureInfo.InvariantCulture); matrix.m31 = float.Parse(stringSplit[13], CultureInfo.InvariantCulture); matrix.m32 = float.Parse(stringSplit[14], CultureInfo.InvariantCulture); matrix.m33 = float.Parse(stringSplit[15], CultureInfo.InvariantCulture); return matrix; } private static Color StringToColor(string colorString) { var stringSplit = colorString.Substring(5, colorString.Length - 6).Split(','); return new Color(float.Parse(stringSplit[0], CultureInfo.InvariantCulture), float.Parse(stringSplit[1], CultureInfo.InvariantCulture), float.Parse(stringSplit[2], CultureInfo.InvariantCulture), float.Parse(stringSplit[3], CultureInfo.InvariantCulture)); } private static Rect StringToRect(string rectString) { var stringSplit = rectString.Substring(1, rectString.Length - 2).Split(','); return new Rect(float.Parse(stringSplit[0].Substring(2, stringSplit[0].Length - 2), CultureInfo.InvariantCulture), //x:0.00 float.Parse(stringSplit[1].Substring(3, stringSplit[1].Length - 3), CultureInfo.InvariantCulture), // y:0.00 float.Parse(stringSplit[2].Substring(7, stringSplit[2].Length - 7), CultureInfo.InvariantCulture), // width:0.00 float.Parse(stringSplit[3].Substring(8, stringSplit[3].Length - 8), CultureInfo.InvariantCulture)); // height:0.00 } private static LayerMask ValueToLayerMask(int value) { var layerMask = new LayerMask(); layerMask.value = value; return layerMask; } private static AnimationCurve ValueToAnimationCurve(Dictionary value) { var animationCurve = new AnimationCurve(); object obj; if (value.TryGetValue("Keys", out obj)) { var keys = obj as List; for (int i = 0; i < keys.Count; ++i) { var keyValue = keys[i] as List; var keyframe = new Keyframe((float)Convert.ChangeType(keyValue[0], typeof(float), CultureInfo.InvariantCulture), (float)Convert.ChangeType(keyValue[1], typeof(float), CultureInfo.InvariantCulture), (float)Convert.ChangeType(keyValue[2], typeof(float), CultureInfo.InvariantCulture), (float)Convert.ChangeType(keyValue[3], typeof(float), CultureInfo.InvariantCulture)); animationCurve.AddKey(keyframe); } } if (value.TryGetValue("PreWrapMode", out obj)) { animationCurve.preWrapMode = (WrapMode)Enum.Parse(typeof(WrapMode), (string)obj); } if (value.TryGetValue("PostWrapMode", out obj)) { animationCurve.postWrapMode = (WrapMode)Enum.Parse(typeof(WrapMode), (string)obj); } return animationCurve; } private static UnityEngine.Object IndexToUnityObject(int index, List unityObjects) { if (index < 0 || index >= unityObjects.Count) { return null; } return unityObjects[index]; } } }