vexe

UA Serializtion Test

Sep 2nd, 2014
2,157
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 5.27 KB | None | 0 0
  1. using UnityEngine;
  2. using System;
  3. using System.Reflection;
  4. using System.Linq;
  5. using System.Collections.Generic;
  6. using UnityObject = UnityEngine.Object;
  7. using System.Runtime.Serialization.Formatters.Binary;
  8. using System.IO;
  9. using System.Runtime.Serialization;
  10.  
  11. namespace Assets.Vexe.ShowEmAll
  12. {
  13.     public abstract class SerializedBehaviour : MonoBehaviour, ISerializationCallbackReceiver
  14.     {
  15.         [SerializeField]
  16.         private StrObjDict serializedObjects = new StrObjDict(); // a serializable Dictionary<string, UnityObject>
  17.         [SerializeField]
  18.         private StrStrDict serializedStrings = new StrStrDict(); // a serializable Dictionary<string, string>
  19.  
  20.         private BinaryFormatter mSerializer;
  21.  
  22.         private BinaryFormatter serializer
  23.         {
  24.             get
  25.             {
  26.                 if (mSerializer == null)
  27.                 {
  28.                     mSerializer = new BinaryFormatter();
  29.                     var selector = new SurrogateSelector();
  30.  
  31.                     Action<Type, ISerializationSurrogate> addSurrogate = (type, surrogate) =>
  32.                         selector.AddSurrogate(type, new StreamingContext(), surrogate);
  33.  
  34.                     addSurrogate(typeof(Vector3), new Vector3Surrogate());
  35.                     // add more custom surrogates here
  36.  
  37.                     // create our unity surrogate
  38.                     var unitySurrogate = new AnotherUnityObjectSurrogate(serializedObjects);
  39.  
  40.                     // get all unity object types
  41.                     var unityTypes = typeof(UnityObject).Assembly.GetTypes()
  42.                                                         .Where(t => typeof(UnityObject).IsAssignableFrom(t))
  43.                                                         .ToArray();
  44.  
  45.                     // add our surrogate to let the serializer use it to handle unity objects serialization
  46.                     foreach (var t in unityTypes)
  47.                         addSurrogate(t, unitySurrogate);
  48.  
  49.                     serializer.SurrogateSelector = selector;
  50.                 }
  51.                 return mSerializer;
  52.             }
  53.         }
  54.  
  55.         public void OnAfterDeserialize()
  56.         {
  57.             Deserialize();
  58.         }
  59.  
  60.         public void OnBeforeSerialize()
  61.         {
  62.             Serialize();
  63.         }
  64.  
  65.         private void Serialize()
  66.         {
  67.             foreach (var field in GetInterfaces())
  68.             {
  69.                 var value = field.GetValue(this);
  70.                 if (value == null)
  71.                     continue;
  72.  
  73.                 string name = field.Name;
  74.                 var obj = value as UnityObject;
  75.                 if (obj != null) // the implementor is a UnityEngine.Object
  76.                 {
  77.                     serializedObjects[name] = obj; // using the field's name as a key because you can't have two fields with the same name
  78.                 }
  79.                 else
  80.                 {
  81.                     // try to serialize the interface and store the result in our other dictionary
  82.                     using (var stream = new MemoryStream())
  83.                     {
  84.                         serializer.Serialize(stream, value);
  85.                         stream.Flush();
  86.                         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
  87.                         serializedStrings[name] = Convert.ToBase64String(stream.ToArray());
  88.                     }
  89.                 }
  90.             }
  91.         }
  92.  
  93.         private void Deserialize()
  94.         {
  95.             foreach (var field in GetInterfaces())
  96.             {
  97.                 object result = null;
  98.                 string name = field.Name;
  99.  
  100.                 // Try fetch member serialized value
  101.                 UnityObject obj;
  102.                 if (serializedObjects.TryGetValue(name, out obj)) // if the implementor is a UnityObject, then we just fetch the value from our dictionary as the result
  103.                 {
  104.                     result = obj;
  105.                 }
  106.                 else // otherwise, get it from our other dictionary
  107.                 {
  108.                     string serializedString;
  109.                     if (serializedStrings.TryGetValue(name, out serializedString))
  110.                     {
  111.                         // deserialize the string back to the original object
  112.                         byte[] bytes = Convert.FromBase64String(serializedString);
  113.                         using (var stream = new MemoryStream(bytes))
  114.                             result = serializer.Deserialize(stream);
  115.                     }
  116.                 }
  117.  
  118.                 field.SetValue(this, result);
  119.             }
  120.         }
  121.  
  122.         private IEnumerable<FieldInfo> GetInterfaces()
  123.         {
  124.             return GetType().GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
  125.                             .Where(f => !f.IsDefined(typeof(HideInInspector)) && (f.IsPublic || f.IsDefined(typeof(SerializeField))))
  126.                             .Where(f => f.FieldType.IsInterface);
  127.         }
  128.     }
  129.  
  130.     public interface ITestInterface
  131.     {
  132.         string StringValue { get; set; }
  133.         float FloatValue { get; set; }
  134.         Vector3 Vector3Value { get; set; }
  135.         Transform Target { get; set; }
  136.     }
  137.  
  138.     [Serializable]
  139.     public class SystemImplementer : ITestInterface
  140.     {
  141.         public string StringValue { get; set; }
  142.         public float FloatValue { get; set; }
  143.         public Vector3 Vector3Value { get; set; }
  144.         public Transform Target { get; set; }
  145.     }
  146.  
  147.     // This should have its own file
  148.     public class UnityImplementer : MonoBehaviour, ITestInterface
  149.     {
  150.         public string StringValue { get; set; }
  151.         public float FloatValue { get; set; }
  152.         public Vector3 Vector3Value { get; set; }
  153.         public Transform Target { get; set; }
  154.     }
  155.  
  156.     // Put this in a file on its own inside an "Editor" folder
  157.     [CustomEditor(typeof(SerializationTest))]
  158.     public class SerializationTestEditor : Editor
  159.     {
  160.         public override void OnInspectorGUI()
  161.         {
  162.             base.OnInspectorGUI();
  163.  
  164.             var typedTarget = target as SerializationTest;
  165.             if (GUILayout.Button("Set to system implementor"))
  166.                 typedTarget.test = new SystemImplementer();
  167.             if (GUILayout.Button("Set to unity implementor"))
  168.                 typedTarget.test = UnityEngine.Object.FindObjectOfType<UnityImplementer>() ?? new GameObject().AddComponent<UnityImplementer>();
  169.             if (GUILayout.Button("Print value"))
  170.                 Debug.Log(typedTarget.test);
  171.         }
  172.     }
  173. }
Advertisement
Add Comment
Please, Sign In to add comment