Guest User

Untitled

a guest
Jun 11th, 2017
105
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 12.66 KB | None | 0 0
  1. using UnityEngine;
  2. using System.Collections.Generic;
  3. using Pathfinding.WindowsStore;
  4. using System;
  5. #if NETFX_CORE
  6. using System.Linq;
  7. using WinRTLegacy;
  8. #endif
  9.  
  10. namespace Pathfinding.Serialization {
  11.     public class JsonMemberAttribute : System.Attribute {
  12.     }
  13.     public class JsonOptInAttribute : System.Attribute {
  14.     }
  15.  
  16.     /** A very tiny json serializer.
  17.      * It is not supposed to have lots of features, it is only intended to be able to serialize graph settings
  18.      * well enough.
  19.      */
  20.     public class TinyJsonSerializer {
  21.         System.Text.StringBuilder output = new System.Text.StringBuilder();
  22.  
  23.         Dictionary<Type, Action<System.Object> > serializers = new Dictionary<Type, Action<object> >();
  24.  
  25.         static readonly System.Globalization.CultureInfo invariantCulture = System.Globalization.CultureInfo.InvariantCulture;
  26.  
  27.         public static void Serialize (System.Object obj, System.Text.StringBuilder output) {
  28.             new TinyJsonSerializer() {
  29.                 output = output
  30.             }.Serialize(obj);
  31.         }
  32.  
  33.         TinyJsonSerializer () {
  34.             serializers[typeof(float)] = v => output.Append(((float)v).ToString("R", invariantCulture));
  35.             serializers[typeof(bool)] = v => output.Append((bool)v ? "true" : "false");
  36.             serializers[typeof(Version)] = serializers[typeof(uint)] = serializers[typeof(int)] = v => output.Append(v.ToString());
  37.             serializers[typeof(string)] = v => output.AppendFormat("\"{0}\"", v.ToString().Replace("\"", "\\\""));
  38.             serializers[typeof(Vector2)] = v => output.AppendFormat("{{ \"x\": {0}, \"y\": {1} }}", ((Vector2)v).x.ToString("R", invariantCulture), ((Vector2)v).y.ToString("R", invariantCulture));
  39.             serializers[typeof(Vector3)] = v => output.AppendFormat("{{ \"x\": {0}, \"y\": {1}, \"z\": {2} }}", ((Vector3)v).x.ToString("R", invariantCulture), ((Vector3)v).y.ToString("R", invariantCulture), ((Vector3)v).z.ToString("R", invariantCulture));
  40.             serializers[typeof(Pathfinding.Util.Guid)] = v => output.AppendFormat("{{ \"value\": \"{0}\" }}", v.ToString());
  41.             serializers[typeof(LayerMask)] = v => output.AppendFormat("{{ \"value\": {0} }}", ((int)(LayerMask)v).ToString());
  42.         }
  43.  
  44.         void Serialize (System.Object obj) {
  45.             if (obj == null) {
  46.                 output.Append("null");
  47.                 return;
  48.             }
  49.  
  50.             var type = obj.GetType();
  51.             var typeInfo = WindowsStoreCompatibility.GetTypeInfo(type);
  52.             if (serializers.ContainsKey(type)) {
  53.                 serializers[type] (obj);
  54.             } else if (typeInfo.IsEnum) {
  55.                 output.Append('"' + obj.ToString() + '"');
  56.             } else if (obj is System.Collections.IList) {
  57.                 output.Append("[");
  58.                 var arr = obj as System.Collections.IList;
  59.                 for (int i = 0; i < arr.Count; i++) {
  60.                     if (i != 0)
  61.                         output.Append(", ");
  62.                     Serialize(arr[i]);
  63.                 }
  64.                 output.Append("]");
  65.             } else if (obj is UnityEngine.Object) {
  66.                 SerializeUnityObject(obj as UnityEngine.Object);
  67.             } else {
  68. #if NETFX_CORE
  69.                 var optIn = typeInfo.CustomAttributes.Any(attr => attr.GetType() == typeof(JsonOptInAttribute));
  70. #else
  71.                 var optIn = typeInfo.GetCustomAttributes(typeof(JsonOptInAttribute), true).Length > 0;
  72. #endif
  73.                 output.Append("{");
  74.  
  75. #if NETFX_CORE
  76.                 var fields = typeInfo.DeclaredFields.Where(f => !f.IsStatic).ToArray();
  77. #else
  78.                 var fields = type.GetFields(System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.NonPublic);
  79. #endif
  80.                 bool earlier = false;
  81.                 foreach (var field in fields) {
  82.                     if ((!optIn && field.IsPublic) ||
  83. #if NETFX_CORE
  84.                         field.CustomAttributes.Any(attr => attr.GetType() == typeof(JsonMemberAttribute))
  85. #else
  86.                         field.GetCustomAttributes(typeof(JsonMemberAttribute), true).Length > 0
  87. #endif
  88.                         ) {
  89.                         if (earlier) {
  90.                             output.Append(", ");
  91.                         }
  92.  
  93.                         earlier = true;
  94.                         output.AppendFormat("\"{0}\": ", field.Name);
  95.                         Serialize(field.GetValue(obj));
  96.                     }
  97.                 }
  98.                 output.Append("}");
  99.             }
  100.         }
  101.  
  102.         void QuotedField (string name, string contents) {
  103.             output.AppendFormat("\"{0}\": \"{1}\"", name, contents);
  104.         }
  105.  
  106.         void SerializeUnityObject (UnityEngine.Object obj) {
  107.             // Note that a unityengine can be destroyed as well
  108.             if (obj == null) {
  109.                 Serialize(null);
  110.                 return;
  111.             }
  112.  
  113.             output.Append("{");
  114.             QuotedField("Name", obj.name);
  115.             output.Append(", ");
  116.             QuotedField("Type", obj.GetType().FullName);
  117.  
  118.             //Write scene path if the object is a Component or GameObject
  119.             var component = obj as Component;
  120.             var go = obj as GameObject;
  121.  
  122.             if (component != null || go != null) {
  123.                 if (component != null && go == null) {
  124.                     go = component.gameObject;
  125.                 }
  126.  
  127.                 var helper = go.GetComponent<UnityReferenceHelper>();
  128.  
  129.                 if (helper == null) {
  130.                     Debug.Log("Adding UnityReferenceHelper to Unity Reference '"+obj.name+"'");
  131.                     helper = go.AddComponent<UnityReferenceHelper>();
  132.                 }
  133.  
  134.                 //Make sure it has a unique GUID
  135.                 helper.Reset();
  136.                 output.Append(", ");
  137.                 QuotedField("GUID", helper.GetGUID().ToString());
  138.             }
  139.             output.Append("}");
  140.         }
  141.     }
  142.  
  143.     /** A very tiny json deserializer.
  144.      * It is not supposed to have lots of features, it is only intended to be able to deserialize graph settings
  145.      * well enough. Not much validation of the input is done.
  146.      */
  147.     public class TinyJsonDeserializer {
  148.         System.IO.TextReader reader;
  149.  
  150.         static readonly System.Globalization.NumberFormatInfo numberFormat = System.Globalization.NumberFormatInfo.InvariantInfo;
  151.  
  152.         /** Deserializes an object of the specified type.
  153.          * Will load all fields into the \a populate object if it is set (only works for classes).
  154.          */
  155.         public static System.Object Deserialize (string text, Type type, System.Object populate = null) {
  156.             return new TinyJsonDeserializer() {
  157.                        reader = new System.IO.StringReader(text)
  158.             }.Deserialize(type, populate);
  159.         }
  160.  
  161.         /** Deserializes an object of type tp.
  162.          * Will load all fields into the \a populate object if it is set (only works for classes).
  163.          */
  164.         System.Object Deserialize (Type tp, System.Object populate = null) {
  165.             var tpInfo = WindowsStoreCompatibility.GetTypeInfo(tp);
  166.  
  167.             if (tpInfo.IsEnum) {
  168.                 return Enum.Parse(tp, EatField());
  169.             } else if (TryEat('n')) {
  170.                 Eat("ull");
  171.                 TryEat(',');
  172.                 return null;
  173.             } else if (Type.Equals(tp, typeof(float))) {
  174.                 return float.Parse(EatField(), numberFormat);
  175.             } else if (Type.Equals(tp, typeof(int))) {
  176.                 return int.Parse(EatField(), numberFormat);
  177.             } else if (Type.Equals(tp, typeof(uint))) {
  178.                 return uint.Parse(EatField(), numberFormat);
  179.             } else if (Type.Equals(tp, typeof(bool))) {
  180.                 return bool.Parse(EatField());
  181.             } else if (Type.Equals(tp, typeof(string))) {
  182.                 return EatField();
  183.             } else if (Type.Equals(tp, typeof(Version))) {
  184.                 return new Version(EatField());
  185.             } else if (Type.Equals(tp, typeof(Vector2))) {
  186.                 Eat("{");
  187.                 var result = new Vector2();
  188.                 EatField();
  189.                 result.x = float.Parse(EatField(), numberFormat);
  190.                 EatField();
  191.                 result.y = float.Parse(EatField(), numberFormat);
  192.                 Eat("}");
  193.                 return result;
  194.             } else if (Type.Equals(tp, typeof(Vector3))) {
  195.                 Eat("{");
  196.                 var result = new Vector3();
  197.                 EatField();
  198.                 result.x = float.Parse(EatField(), numberFormat);
  199.                 EatField();
  200.                 result.y = float.Parse(EatField(), numberFormat);
  201.                 EatField();
  202.                 result.z = float.Parse(EatField(), numberFormat);
  203.                 Eat("}");
  204.                 return result;
  205.             } else if (Type.Equals(tp, typeof(Pathfinding.Util.Guid))) {
  206.                 Eat("{");
  207.                 EatField();
  208.                 var result = Pathfinding.Util.Guid.Parse(EatField());
  209.                 Eat("}");
  210.                 return result;
  211.             } else if (Type.Equals(tp, typeof(LayerMask))) {
  212.                 Eat("{");
  213.                 EatField();
  214.                 var result = (LayerMask)int.Parse(EatField());
  215.                 Eat("}");
  216.                 return result;
  217.             } else if (Type.Equals(tp, typeof(List<string>))) {
  218.                 System.Collections.IList result = new List<string>();
  219.  
  220.                 Eat("[");
  221.                 while (!TryEat(']')) {
  222.                     result.Add(Deserialize(typeof(string)));
  223.                     TryEat(',');
  224.                 }
  225.                 return result;
  226.             } else if (tpInfo.IsArray) {
  227.                 List<System.Object> ls = new List<System.Object>();
  228.                 Eat("[");
  229.                 while (!TryEat(']')) {
  230.                     ls.Add(Deserialize(tp.GetElementType()));
  231.                     TryEat(',');
  232.                 }
  233.                 var arr = Array.CreateInstance(tp.GetElementType(), ls.Count);
  234.                 ls.ToArray().CopyTo(arr, 0);
  235.                 return arr;
  236.             } else if (Type.Equals(tp, typeof(Mesh)) || Type.Equals(tp, typeof(Texture2D)) || Type.Equals(tp, typeof(Transform)) || Type.Equals(tp, typeof(GameObject))) {
  237.                 return DeserializeUnityObject();
  238.             } else {
  239.                 var obj = populate ?? Activator.CreateInstance(tp);
  240.                 Eat("{");
  241.                 while (!TryEat('}')) {
  242.                     var name = EatField();
  243.                     var field = tp.GetField(name, System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.NonPublic);
  244.                     if (field == null) {
  245.                         SkipFieldData();
  246.                     } else {
  247.                         field.SetValue(obj, Deserialize(field.FieldType));
  248.                     }
  249.                     TryEat(',');
  250.                 }
  251.                 return obj;
  252.             }
  253.         }
  254.  
  255.         UnityEngine.Object DeserializeUnityObject () {
  256.             Eat("{");
  257.             var result = DeserializeUnityObjectInner();
  258.             Eat("}");
  259.             return result;
  260.         }
  261.  
  262.         UnityEngine.Object DeserializeUnityObjectInner () {
  263.             // Ignore InstanceID field (compatibility only)
  264.             var fieldName = EatField();
  265.  
  266.             if (fieldName == "InstanceID") {
  267.                 EatField();
  268.                 fieldName = EatField();
  269.             }
  270.  
  271.             if (fieldName != "Name") throw new Exception("Expected 'Name' field");
  272.             string name = EatField();
  273.  
  274.             if (name == null) return null;
  275.  
  276.             if (EatField() != "Type") throw new Exception("Expected 'Type' field");
  277.             string typename = EatField();
  278.  
  279.             // Remove assembly information
  280.             if (typename.IndexOf(',') != -1) {
  281.                 typename = typename.Substring(0, typename.IndexOf(','));
  282.             }
  283.  
  284.             // Note calling through assembly is more stable on e.g WebGL
  285.             var type = WindowsStoreCompatibility.GetTypeInfo(typeof(AstarPath)).Assembly.GetType(typename);
  286.             type = type ?? WindowsStoreCompatibility.GetTypeInfo(typeof(Transform)).Assembly.GetType(typename);
  287.  
  288.             if (Type.Equals(type, null)) {
  289.                 Debug.LogError("Could not find type '"+typename+"'. Cannot deserialize Unity reference");
  290.                 return null;
  291.             }
  292.  
  293.             // Check if there is another field there
  294.             EatWhitespace();
  295.             if ((char)reader.Peek() == '"') {
  296.                 if (EatField() != "GUID") throw new Exception("Expected 'GUID' field");
  297.                 string guid = EatField();
  298.  
  299.                 foreach (var helper in UnityEngine.Object.FindObjectsOfType<UnityReferenceHelper>()) {
  300.                     if (helper.GetGUID() == guid) {
  301.                         if (Type.Equals(type, typeof(GameObject))) {
  302.                             return helper.gameObject;
  303.                         } else {
  304.                             return helper.GetComponent(type);
  305.                         }
  306.                     }
  307.                 }
  308.             }
  309.  
  310.             // Try to load from resources
  311.             UnityEngine.Object[] objs = Resources.LoadAll(name, type);
  312.  
  313.             for (int i = 0; i < objs.Length; i++) {
  314.                 if (objs[i].name == name || objs.Length == 1) {
  315.                     return objs[i];
  316.                 }
  317.             }
  318.  
  319.             return null;
  320.         }
  321.  
  322.         void EatWhitespace () {
  323.             while (char.IsWhiteSpace((char)reader.Peek()))
  324.                 reader.Read();
  325.         }
  326.  
  327.         void Eat (string s) {
  328.             EatWhitespace();
  329.             for (int i = 0; i < s.Length; i++) {
  330.                 var c = (char)reader.Read();
  331.                 if (c != s[i]) {
  332.                     throw new Exception("Expected '" + s[i] + "' found '" + c + "'\n\n..." + reader.ReadLine());
  333.                 }
  334.             }
  335.         }
  336.  
  337.         System.Text.StringBuilder builder = new System.Text.StringBuilder();
  338.         string EatUntil (string c, bool inString) {
  339.             builder.Length = 0;
  340.             bool escape = false;
  341.             while (true) {
  342.                 var readInt = reader.Peek();
  343.                 if (!escape && (char)readInt == '"') {
  344.                     inString = !inString;
  345.                 }
  346.  
  347.                 var readChar = (char)readInt;
  348.                 if (readInt == -1) {
  349.                     throw new Exception("Unexpected EOF");
  350.                 } else if (!escape && readChar == '\\') {
  351.                     escape = true;
  352.                     reader.Read();
  353.                 } else if (!inString && c.IndexOf(readChar) != -1) {
  354.                     break;
  355.                 } else {
  356.                     builder.Append(readChar);
  357.                     reader.Read();
  358.                     escape = false;
  359.                 }
  360.             }
  361.  
  362.             return builder.ToString();
  363.         }
  364.  
  365.         bool TryEat (char c) {
  366.             EatWhitespace();
  367.             if ((char)reader.Peek() == c) {
  368.                 reader.Read();
  369.                 return true;
  370.             }
  371.             return false;
  372.         }
  373.  
  374.         string EatField () {
  375.             var result = EatUntil("\",}]", TryEat('"'));
  376.  
  377.             TryEat('\"');
  378.             TryEat(':');
  379.             TryEat(',');
  380.             return result;
  381.         }
  382.  
  383.         void SkipFieldData () {
  384.             var indent = 0;
  385.  
  386.             while (true) {
  387.                 EatUntil(",{}[]", false);
  388.                 var last = (char)reader.Peek();
  389.  
  390.                 switch (last) {
  391.                 case '{':
  392.                 case '[':
  393.                     indent++;
  394.                     break;
  395.                 case '}':
  396.                 case ']':
  397.                     indent--;
  398.                     if (indent < 0) return;
  399.                     break;
  400.                 case ',':
  401.                     if (indent == 0) {
  402.                         reader.Read();
  403.                         return;
  404.                     }
  405.                     break;
  406.                 default:
  407.                     throw new System.Exception("Should not reach this part");
  408.                 }
  409.  
  410.                 reader.Read();
  411.             }
  412.         }
  413.     }
  414. }
Add Comment
Please, Sign In to add comment