Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- using UnityEngine;
- using System;
- using System.Reflection;
- using System.Linq;
- using System.Collections.Generic;
- using UnityObject = UnityEngine.Object;
- using System.Runtime.Serialization.Formatters.Binary;
- using System.IO;
- using System.Runtime.Serialization;
- namespace Assets.Vexe.ShowEmAll
- {
- public abstract class SerializedBehaviour : MonoBehaviour, ISerializationCallbackReceiver
- {
- [SerializeField]
- private StrObjDict serializedObjects = new StrObjDict(); // a serializable Dictionary<string, UnityObject>
- [SerializeField]
- private StrStrDict serializedStrings = new StrStrDict(); // a serializable Dictionary<string, string>
- private BinaryFormatter mSerializer;
- private BinaryFormatter serializer
- {
- get
- {
- if (mSerializer == null)
- {
- mSerializer = new BinaryFormatter();
- var selector = new SurrogateSelector();
- Action<Type, ISerializationSurrogate> addSurrogate = (type, surrogate) =>
- selector.AddSurrogate(type, new StreamingContext(), surrogate);
- addSurrogate(typeof(Vector3), new Vector3Surrogate());
- // add more custom surrogates here
- // create our unity surrogate
- var unitySurrogate = new AnotherUnityObjectSurrogate(serializedObjects);
- // get all unity object types
- var unityTypes = typeof(UnityObject).Assembly.GetTypes()
- .Where(t => typeof(UnityObject).IsAssignableFrom(t))
- .ToArray();
- // add our surrogate to let the serializer use it to handle unity objects serialization
- foreach (var t in unityTypes)
- addSurrogate(t, unitySurrogate);
- serializer.SurrogateSelector = selector;
- }
- return mSerializer;
- }
- }
- public void OnAfterDeserialize()
- {
- Deserialize();
- }
- public void OnBeforeSerialize()
- {
- Serialize();
- }
- private void Serialize()
- {
- foreach (var field in GetInterfaces())
- {
- var value = field.GetValue(this);
- if (value == null)
- continue;
- string name = field.Name;
- var obj = value as UnityObject;
- if (obj != null) // the implementor is a UnityEngine.Object
- {
- serializedObjects[name] = obj; // using the field's name as a key because you can't have two fields with the same name
- }
- else
- {
- // try to serialize the interface and store the result in our other dictionary
- using (var stream = new MemoryStream())
- {
- serializer.Serialize(stream, value);
- stream.Flush();
- serializedObjects.Remove(name); // it could happen that the field might end up in both the dictionaries, ex when you change the implementation of the interface to use a System.Object instead of a UnityObject
- serializedStrings[name] = Convert.ToBase64String(stream.ToArray());
- }
- }
- }
- }
- private void Deserialize()
- {
- foreach (var field in GetInterfaces())
- {
- object result = null;
- string name = field.Name;
- // Try fetch member serialized value
- UnityObject obj;
- if (serializedObjects.TryGetValue(name, out obj)) // if the implementor is a UnityObject, then we just fetch the value from our dictionary as the result
- {
- result = obj;
- }
- else // otherwise, get it from our other dictionary
- {
- string serializedString;
- if (serializedStrings.TryGetValue(name, out serializedString))
- {
- // deserialize the string back to the original object
- byte[] bytes = Convert.FromBase64String(serializedString);
- using (var stream = new MemoryStream(bytes))
- result = serializer.Deserialize(stream);
- }
- }
- field.SetValue(this, result);
- }
- }
- private IEnumerable<FieldInfo> GetInterfaces()
- {
- return GetType().GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
- .Where(f => !f.IsDefined(typeof(HideInInspector)) && (f.IsPublic || f.IsDefined(typeof(SerializeField))))
- .Where(f => f.FieldType.IsInterface);
- }
- }
- public interface ITestInterface
- {
- string StringValue { get; set; }
- float FloatValue { get; set; }
- Vector3 Vector3Value { get; set; }
- Transform Target { get; set; }
- }
- [Serializable]
- public class SystemImplementer : ITestInterface
- {
- public string StringValue { get; set; }
- public float FloatValue { get; set; }
- public Vector3 Vector3Value { get; set; }
- public Transform Target { get; set; }
- }
- // This should have its own file
- public class UnityImplementer : MonoBehaviour, ITestInterface
- {
- public string StringValue { get; set; }
- public float FloatValue { get; set; }
- public Vector3 Vector3Value { get; set; }
- public Transform Target { get; set; }
- }
- // Put this in a file on its own inside an "Editor" folder
- [CustomEditor(typeof(SerializationTest))]
- public class SerializationTestEditor : Editor
- {
- public override void OnInspectorGUI()
- {
- base.OnInspectorGUI();
- var typedTarget = target as SerializationTest;
- if (GUILayout.Button("Set to system implementor"))
- typedTarget.test = new SystemImplementer();
- if (GUILayout.Button("Set to unity implementor"))
- typedTarget.test = UnityEngine.Object.FindObjectOfType<UnityImplementer>() ?? new GameObject().AddComponent<UnityImplementer>();
- if (GUILayout.Button("Print value"))
- Debug.Log(typedTarget.test);
- }
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment