public void AfterDeserialize() { // resolve references foreach (var cmp in components) { System.Type type = cmp.GetType(); foreach (var pair in refs) { string fieldName = pair.Key.Substring(1); System.Reflection.FieldInfo fi = type.GetField(fieldName); if (fi == null) { continue; } SerializedComponent resolvedComponent = ResolveComponentFromId(pair.Value); if (resolvedComponent != null) { if (fi.FieldType != resolvedComponent.GetType()) { Debug.LogWarning("deserialize type mismatch", cmp); } else { fi.SetValue(cmp, resolvedComponent); } } else { // TODO resolve gameobject references // this is probably not needed when there are component references } } cmp.AfterDeserialize(); } }
public static T ResolveComponentFromId <T>(int id) where T : SerializedComponent { if (serializedComponents.ContainsKey(id)) { SerializedComponent sc = serializedComponents[id]; if (sc.GetType() != typeof(T)) { Debug.LogWarning("resolvecomponent type mismatch: " + sc.GetType().ToString() + " " + typeof(T).ToString()); return(default(T)); } return((T)sc); } // if( idMap.ContainsKey( id ) && serializedComponents.ContainsKey( idMap[ id ] ) ) // return serializedComponents[ idMap[ id ] ]; Debug.LogWarning("failed to resolve component: " + id); return(null); }
public static GameObject Deserialize(JsonData data) { string resourceName = data["resource"].GetString(); Vector3 position = JsonUtil.ReadVector(data["position"]); Vector3 rotation = Vector3.zero; if (data.Keys.Contains("rotation")) { rotation = JsonUtil.ReadVector(data["rotation"]); } GameObject go; if (Application.isEditor && !Application.isPlaying) { go = GameObject.Instantiate(Resources.Load <GameObject>("serialized/" + resourceName), position, Quaternion.Euler(rotation), null); } else { go = Global.instance.Spawn(resourceName, position, Quaternion.Euler(rotation), null, false, false); } if (go != null) { SerializedObject so = go.GetComponent <SerializedObject>(); if (so == null) { // This can happen after name changes or removing the SerializedObject component from a prefab. Destroy(go); return(null); } serializedObjects.Remove(so.id); so.id = (int)data["id"].GetNatural(); serializedObjects.Add(so.id, so); if (data.Keys.Contains("components")) { JsonData cmps = data["components"]; foreach (JsonData cmpData in cmps) { string t = cmpData["type"].ToString(); System.Type stringType = System.Type.GetType(t); if (stringType == null) { continue; } Component component = go.GetComponentInChildren(stringType); if (component == null) { Debug.LogWarning("Cannot find component of type: " + stringType, go); continue; } System.Type compType = component.GetType(); if (!typeof(SerializedComponent).IsAssignableFrom(compType)) { // if component types change (different parent class, or field type changes) Debug.Log("component is not serializedcomponent: " + stringType, go); continue; } SerializedComponent comp = (SerializedComponent)component; if (comp == null) { continue; } // this is hacky, but prevents the waste of many ids. serializedComponents.Remove(comp.id); comp.id = (int)cmpData["id"].GetNatural(); serializedComponents.Add(comp.id, comp); foreach (var key in cmpData.Keys) { if (key == "type" || key == "id" || key == "position" || key == "rotation") { continue; } if (key.StartsWith("@")) { if (cmpData[key].IsArray) { Debug.LogWarning("Cannot deserialize an array of references. Not implemented."); } else { int refId = (int)cmpData[key].GetNatural(); if (so.refs.ContainsKey(key)) { Debug.LogWarning("Duplicate serialized field: " + key + " (Click for object)", go); } else { so.refs.Add(key, refId); } } } else { System.Reflection.FieldInfo fi = compType.GetField(key); if (fi == null) { continue; } if (cmpData[key] == null) { continue; } if (cmpData[key].IsNatural) { fi.SetValue(comp, (int)cmpData[key].GetNatural()); } if (cmpData[key].IsReal) { fi.SetValue(comp, (float)cmpData[key].GetReal()); } if (cmpData[key].IsBoolean) { fi.SetValue(comp, cmpData[key].GetBoolean()); } if (cmpData[key].IsString) { fi.SetValue(comp, cmpData[key].GetString()); } if (cmpData[key].IsArray && cmpData[key].Count > 0) { if (cmpData[key][0] == null) { continue; } object obj = fi.GetValue(comp); JsonType jsonType = cmpData[key][0].GetJsonType(); switch (jsonType) { case JsonType.String: foreach (JsonData element in cmpData[key]) { (obj as List <string>).Add(element.GetString()); } break; case JsonType.Natural: foreach (JsonData element in cmpData[key]) { (obj as List <int>).Add((int)element.GetNatural()); } break; } } } } } } return(go); } return(null); }
public void Serialize(JsonWriter writer) { writer.WritePropertyName("id"); writer.Write(id); writer.WritePropertyName("resource"); writer.Write(gameObject.name); writer.WritePropertyName("position"); JsonUtil.WriteVector(writer, transform.position); if (transform.rotation != Quaternion.identity) { writer.WritePropertyName("rotation"); JsonUtil.WriteVector(writer, transform.rotation.eulerAngles); } // NOTE only one SerializedComponent of a given type per GameObject is supported. // TODO check for multiple components of a given type and print warning GetComponentsInChildren <SerializedComponent>(components); if (components.Count > 0) { writer.WritePropertyName("components"); writer.WriteArrayStart(); foreach (var cmp in components) { System.Type cmpType = cmp.GetType(); writer.WriteObjectStart(); writer.WritePropertyName("type"); writer.Write(cmpType.Name); writer.WritePropertyName("id"); writer.Write(cmp.id); System.Reflection.FieldInfo[] fis = cmpType.GetFields(); foreach (var fi in fis) { if (fi.IsDefined(typeof(SerializeAttribute), true)) { object value = fi.GetValue(cmp); if (value == null) { continue; } if (fi.FieldType.IsSubclassOf(typeof(SerializedComponent))) { SerializedComponent sc = (SerializedComponent)value; if (sc == null) { continue; } SerializedObject so = sc.GetComponentInParent <SerializedObject>(); if (so != null) { writer.WritePropertyName("@" + fi.Name); writer.Write(sc.id); } } else if (value is IList) { IList list = value as IList; if (list.Count > 0) { bool isListOfReferences = false; string propName = fi.Name; System.Type type = value.GetType(); System.Type elementType = null; if (fi.FieldType.IsGenericType) { elementType = type.GetGenericArguments()[0]; if (elementType.IsSubclassOf(typeof(SerializedComponent))) { // collection of serialized components propName = "@" + propName; isListOfReferences = true; } } if (fi.FieldType.IsArray) { elementType = list.GetType().GetElementType(); } if (isListOfReferences) { Debug.LogError("Serializing an array of references is not implemented."); /*writer.WritePropertyName( propName ); * writer.WriteArrayStart(); * foreach( SerializedComponent obj in value as IEnumerable ) * writer.Write( obj.GetInstanceID() ); * writer.WriteArrayEnd();*/ } else { writer.WritePropertyName(propName); writer.WriteArrayStart(); foreach (var obj in list) { JsonUtil.SerializeValue(writer, elementType, obj); } writer.WriteArrayEnd(); } } } else { writer.WritePropertyName(fi.Name); JsonUtil.SerializeValue(writer, fi.FieldType, value); } } } writer.WriteObjectEnd(); } writer.WriteArrayEnd(); } }