public override fsResult TrySerialize(object instance, out fsData serialized, Type storageType) { var type = (Type)instance; serialized = new fsData(RuntimeCodebase.SerializeType(type)); return(fsResult.Success); }
public Type ResolveExpandedType() { if (RuntimeCodebase.TryDeserializeType(GetExpandedTypeName(), out var type)) { return(type); } return(null); }
public override fsResult TryDeserialize(fsData data, ref object instance, Type storageType) { if (data.IsString == false) { return(fsResult.Fail("Type converter requires a string")); } if (RuntimeCodebase.TryDeserializeType(data.AsString, out var type)) { instance = type; } else { return(fsResult.Fail($"Unable to find type: '{data.AsString ?? "(null)"}'.")); } return(fsResult.Success); }
private fsResult InternalDeserialize_3_Inheritance(Type overrideConverterType, fsData data, Type storageType, ref object result, out List <fsObjectProcessor> processors) { var deserializeResult = fsResult.Success; var objectType = storageType; // If the serialized state contains type information, then we need to // make sure to update our objectType and data to the proper values // so that when we construct an object instance later and run // deserialization we run it on the proper type. if (IsTypeSpecified(data)) { var typeNameData = data.AsDictionary[Key_InstanceType]; // we wrap everything in a do while false loop so we can break // out it do { if (typeNameData.IsString == false) { deserializeResult.AddMessage(Key_InstanceType + " value must be a string (in " + data + ")"); break; } var typeName = typeNameData.AsString; if (!RuntimeCodebase.TryDeserializeType(typeName, out var type)) { deserializeResult += fsResult.Fail("Unable to find type: '" + typeName + "'"); break; } if (storageType.IsAssignableFrom(type) == false) { deserializeResult.AddMessage("Ignoring type specifier; a field/property of type " + storageType + " cannot hold an instance of " + type); break; } objectType = type; }while (false); } RemapAbstractStorageTypeToDefaultType(ref objectType); // We wait until here to actually Invoke_OnBeforeDeserialize because // we do not have the correct set of processors to invoke until // *after* we have resolved the proper type to use for // deserialization. processors = GetProcessors(objectType); if (deserializeResult.Failed) { return(deserializeResult); } // LAZLO / LUDIQ FIX try { Invoke_OnBeforeDeserialize(processors, storageType, ref data); } catch (Exception ex) { return(deserializeResult += fsResult.Fail(ex.ToString())); } // Construct an object instance if we don't have one already. We also // need to construct an instance if the result type is of the wrong // type, which may be the case when we have a versioned import graph. if (ReferenceEquals(result, null) || result.GetType() != objectType) { result = GetConverter(objectType, overrideConverterType).CreateInstance(data, objectType); } // We call OnBeforeDeserializeAfterInstanceCreation here because we // still want to invoke the method even if the user passed in an // existing instance. try { Invoke_OnBeforeDeserializeAfterInstanceCreation(processors, storageType, result, ref data); } catch (Exception ex) { return(deserializeResult += fsResult.Fail(ex.ToString())); } // NOTE: It is critically important that we pass the actual // objectType down instead of using result.GetType() because it // is not guaranteed that result.GetType() will equal // objectType, especially because some converters are known to // return dummy values for CreateInstance() (for example, the // default behavior for structs is to just return the type of // the struct). return(deserializeResult += InternalDeserialize_4_Cycles(overrideConverterType, data, objectType, ref result)); }
private fsResult InternalSerialize_2_Inheritance(Type storageType, Type overrideConverterType, object instance, out fsData data) { // Serialize the actual object with the field type being the same as // the object type so that we won't go into an infinite loop. var serializeResult = InternalSerialize_3_ProcessVersioning(overrideConverterType, instance, out data); if (serializeResult.Failed) { return(serializeResult); } // Do we need to add type information? If the field type and the // instance type are different then we will not be able to recover // the correct instance type from the field type when we deserialize // the object. // // Note: We allow converters to request that we do *not* add type // information. if (storageType != instance.GetType() && GetConverter(storageType, overrideConverterType).RequestInheritanceSupport(storageType)) { var instanceType = instance.GetType(); // LAZLO / LUDIQ // We need to loosen the instance type hint of Unity objects when serializing // to counter a very specific issue that happens when: // - We serialize a reference to an object of an editor type // - That object type inherits a runtime type // - The field supports the runtime type, but will allow the editor type // - Therefore serializing as the editor type is valid, but will fail to deserialize in builds // The only current example of this bug is AudioMixers and AudioMixerGroups. // UnityEDITOR.Audio.AudioMixerController extends UnityENGINE.Audio.AudioMixer. // UnityEDITOR.Audio.AudioMixerGroupController extends UnityENGINE.Audio.AudioMixerGroup. // Therefore, if we serialize a type hint to the editor controller, e.g. AudioMixerGroupController, // builds will fail to deserialize the type hint, even though they don't actually need it // to properly fetch the Unity Object reference, because it's provided directly by the converter. // We must instead serialize a type hint to the runtime, non-controller type, e.g. AudioMixer. // However, when loosening our type, we must make sure not to go past the compatibility // with the defined storage type, because if we did, we would get the "Ignoring type specifier" // error defined below, as the instance type hint wouldn't be assignable to the storage type on deserialization. // Likewise, we must make sure not to go above UnityObject itself, because we need that much hinting // for FullSerializer to know that the proper converter to be used is our custom UnityObjectConverter. // See: https://support.ludiq.io/communities/5/topics/1032-audio-mixer-reference-gets-nulled-on-il2cpp-builds if (instance is UnityObject) { var looseType = instanceType; do { instanceType = looseType; looseType = looseType.BaseType; }while (looseType != null && instanceType != typeof(UnityObject) && storageType.IsAssignableFrom(looseType)); // Debug.Log($"Loosened instance type hint for {instance.GetType()} stored as {storageType} to {instanceType}"); } // Add the inheritance metadata EnsureDictionary(data); data.AsDictionary[Key_InstanceType] = new fsData(RuntimeCodebase.SerializeType(instanceType)); } return(serializeResult); }