Advertisement
Deukhoofd

Untitled

Dec 12th, 2018
126
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 20.25 KB | None | 0 0
  1. using System;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4. using System.Collections.Specialized;
  5. using System.ComponentModel;
  6. using System.Linq;
  7. using System.Reflection;
  8. using System.Xml;
  9. using System.Xml.Linq;
  10. using UnityEngine;
  11.  
  12. namespace EpsilonFramework.Utilities
  13. {
  14.     //
  15.     //If you're here to edit/bugfix this, sorry man. Reflection tends to turn into a mess
  16.     //~Deukhoofd
  17.     //
  18.     public class DontSaveAttribute : Attribute
  19.     {
  20.  
  21.     }
  22.  
  23.     [Serializable]
  24.     public abstract class Saveable
  25.     {
  26.         public virtual XmlElement GetSaveData(XmlDocument doc)
  27.         {
  28.             //Get all fields
  29.             var bindingFlags = BindingFlags.Instance |
  30.                                BindingFlags.NonPublic |
  31.                                BindingFlags.Public;
  32.             var fields = this.GetType().GetFields(bindingFlags);
  33.  
  34.             XmlElement root = doc.CreateElement(this.GetType().Name);
  35.             foreach (var field in fields)
  36.             {
  37.                 if (field.GetCustomAttributes(true).Any(x => x is DontSaveAttribute))
  38.                 {
  39.                     continue;
  40.                 }
  41.                 var fieldName = field.Name;
  42.                 if (fieldName.Contains("_BackingField"))
  43.                 {
  44.                     var temp = fieldName.Split('>')[0];
  45.                     fieldName = temp.Substring(1, temp.Length - 1);
  46.                     var prop = this.GetType().GetProperty(fieldName, bindingFlags);
  47.                     if (prop.GetCustomAttributes(true).Any(x => x is DontSaveAttribute))
  48.                     {
  49.                         continue;
  50.                     }
  51.                     if (!prop.CanWrite)
  52.                         continue;
  53.                 }
  54.  
  55.                 if (field.FieldType == typeof(string))
  56.                 {
  57.                     var data = field.GetValue(this);
  58.                     var s = "null";
  59.                     if (data != null)
  60.                         s = data.ToString();
  61.                     root.SetAttribute(fieldName, s);
  62.                 }
  63.                 //If this is an array
  64.                 else if (typeof(IEnumerable).IsAssignableFrom(field.FieldType))
  65.                 {
  66.                     var el = ConvertArray(doc, fieldName, field.GetValue(this));
  67.                     root.AppendChild(el);
  68.  
  69.                 }
  70.                 //If the field is a class (so not a primal value like int, string)
  71.                 else if (field.FieldType.IsClass)
  72.                 {
  73.  
  74.                     var ele = ConvertClassType(doc, fieldName, field.GetValue(this));
  75.                     root.AppendChild(ele);
  76.                 }
  77.                 else
  78.                 {
  79.                     root.SetAttribute(fieldName, field.GetValue(this).ToString());
  80.                 }
  81.             }
  82.             return root;
  83.         }
  84.  
  85.  
  86.         private XmlElement ConvertClassType(XmlDocument doc, string name, object o)
  87.         {
  88.             var ele = doc.CreateElement(name);
  89.             if (o == null)
  90.             {
  91.                 ele.SetAttribute("value", "null");
  92.                 return ele;
  93.             }
  94.             var saveable = o as Saveable;
  95.             if (saveable != null)
  96.             {
  97.                 var data = saveable.GetSaveData(doc);
  98.                 ele.AppendChild(data);
  99.             }
  100.             else if (o is string)
  101.             {
  102.                 ele.SetAttribute("value", o.ToString());
  103.             }
  104.             else if (o is int)
  105.             {
  106.                 ele.SetAttribute("value", o.ToString());
  107.             }
  108.             else if (o is bool)
  109.             {
  110.                 ele.SetAttribute("value", o.ToString());
  111.             }
  112.             else if (o.GetType().IsEnum)
  113.             {
  114.                 // if this is an enum, get the type it inherits
  115.                 var underlying = o.GetType().GetEnumUnderlyingType();
  116.                 // convert the value to that type
  117.                 var val = Convert.ChangeType(o, underlying);
  118.                 // and save it. If the cast is somehow invalid, set it to 0
  119.                 ele.SetAttribute("value", val?.ToString() ?? "0");
  120.             }
  121.             else if (o is Vector3)
  122.             {
  123.                 var vec = (Vector3)o;
  124.                 ele.SetAttribute("value", $"{vec.x},{vec.y},{vec.z}");
  125.             }
  126.             else
  127.             {
  128.                 throw new Exception($"An object could not be saved in class {this.GetType()}, Name: {name}, Type: {o.GetType()}");
  129.             }
  130.             return ele;
  131.         }
  132.  
  133.         private XmlElement ConvertArray(XmlDocument doc,string name,  object o)
  134.         {
  135.             var el = doc.CreateElement(name);
  136.  
  137.             var temp = o as IEnumerable;
  138.             if (temp == null)
  139.                 return el;
  140.  
  141.             var arr = temp.Cast<object>();
  142.             el.SetAttribute("Length", arr.Count().ToString());
  143.  
  144.             var enumerable = arr as object[] ?? arr.ToArray();
  145.             if (enumerable.Length == 0)
  146.             {
  147.                 return el;
  148.             }
  149.             if (enumerable.First() is byte)
  150.             {
  151.                 el.SetAttribute("value", Convert.ToBase64String(enumerable.Cast<byte>().ToArray()));
  152.             }
  153.             else if (enumerable.First() is string)
  154.             {
  155.                 var strarr = enumerable.Cast<string>();
  156.                 for (var index = 0; index < arr.Count(); index++)
  157.                 {
  158.                     string t = strarr.ElementAt(index);
  159.                     var child = doc.CreateElement("data");
  160.                     child.SetAttribute("value", t);
  161.                     child.SetAttribute("ArrayIndex", index.ToString());
  162.                     el.AppendChild(child);
  163.                 }
  164.             }
  165.             else if (enumerable.First() is bool)
  166.             {
  167.                 var barr = enumerable.Cast<bool>();
  168.                 var bools = barr as bool[] ?? barr.ToArray();
  169.                 for (var index = 0; index < bools.Count(); index++)
  170.                 {
  171.                     var b = bools.ElementAt(index);
  172.                     var child = doc.CreateElement("data");
  173.                     child.SetAttribute("value", b.ToString());
  174.                     child.SetAttribute("ArrayIndex", index.ToString());
  175.                     el.AppendChild(child);
  176.                 }
  177.             }
  178.             else if (enumerable.First() is DictionaryEntry)
  179.             {
  180.                 var dic = enumerable.Cast<DictionaryEntry>();
  181.                 foreach (var kp in dic)
  182.                 {
  183.                     var child = doc.CreateElement("data");
  184.                     child.SetAttribute("key", kp.Key.ToString());
  185.                     child.SetAttribute("value", kp.Value.ToString());
  186.                     el.AppendChild(child);
  187.                 }
  188.             }
  189.             // ReSharper disable once OperatorIsCanBeUsed
  190.             else if (temp is IDictionary)
  191.             {
  192.                 var first = enumerable.First();
  193.                 var t = first.GetType();
  194.                 var keyType = t.GenericTypeArguments[0];
  195.                 var valueType = t.GenericTypeArguments[1];
  196.                 foreach (var o1 in enumerable)
  197.                 {
  198.                     var keyProp = o1.GetType().GetProperty("Key");
  199.                     var valueProp = o1.GetType().GetProperty("Value");
  200.                     var key = keyProp.GetValue(o1);
  201.                     var value = valueProp.GetValue(o1);
  202.                     var child = doc.CreateElement("data");
  203.                     var keyEle = ConvertClassType(doc, "key", key);
  204.                     var valueEle = ConvertClassType(doc, "value", value);
  205.                     child.AppendChild(keyEle);
  206.                     child.AppendChild(valueEle);
  207.  
  208.                     el.AppendChild(child);
  209.                 }
  210.  
  211.             }
  212.             else
  213.             {
  214.  
  215.                 return ConvertClassArray(doc, el, enumerable);
  216.             }
  217.             return el;
  218.         }
  219.  
  220.         private XmlElement ConvertClassArray(XmlDocument doc, XmlElement el, IEnumerable basearr)
  221.         {
  222.             var arr = basearr.Cast<object>();
  223.             for (var i = 0; i < arr.Count(); i++)
  224.             {
  225.                 var ele = ConvertClassType(doc, "data", arr.ElementAt(i));
  226.                 ele.SetAttribute("ArrayIndex", i.ToString());
  227.                 el.AppendChild(ele);
  228.             }
  229.             return el;
  230.         }
  231.  
  232.         internal virtual void LoadData(XElement doc, bool topMost = false)
  233.         {
  234.             //Get all fields
  235.             var bindingFlags = BindingFlags.Instance |
  236.                                BindingFlags.NonPublic |
  237.                                BindingFlags.Public;
  238.             var fields = this.GetType().GetFields(bindingFlags);
  239.  
  240.             XElement root = null;
  241.             if (topMost)
  242.             {
  243.                 root = doc;
  244.             }
  245.             else
  246.             {
  247.                 root = doc.Element(this.GetType().Name);
  248.             }
  249.             foreach (var field in fields)
  250.             {
  251.                 MemberInfo info = field;
  252.                 if (field.GetCustomAttributes(true).Any(x => x is DontSaveAttribute))
  253.                 {
  254.                     continue;
  255.                 }
  256.                 var fieldName = field.Name;
  257.  
  258.                 if (fieldName.Contains("_BackingField"))
  259.                 {
  260.                     var temp  = fieldName.Split('>')[0];
  261.                     fieldName = temp.Substring(1, temp.Length - 1);
  262.                     var prop  = this.GetType().GetProperty(fieldName, bindingFlags);
  263.                     if (prop.GetCustomAttributes(true).Any(x => x is DontSaveAttribute))
  264.                     {
  265.                         continue;
  266.                     }
  267.                     if (!prop.CanWrite)
  268.                         continue;
  269.                 }
  270.                 if (fieldName.Contains("_BackingField"))
  271.                 {
  272.                     var temp = fieldName.Split('>')[0];
  273.                     fieldName = temp.Substring(1, temp.Length - 1);
  274.                     info = this.GetType().GetProperty(fieldName);
  275.                 }
  276.                 if (root == null)
  277.                     continue;
  278.                 var checkElement = root.Element(fieldName);
  279.                 if (checkElement != null)
  280.                 {
  281.                     if (checkElement.Attribute("value") != null)
  282.                     {
  283.                         if (checkElement.Attribute("value").Value == "null")
  284.                         {
  285.                             continue;
  286.                         }
  287.                     }
  288.                 }
  289.                 if (field.FieldType == typeof(string))
  290.                 {
  291.                     var name = root.Attribute(fieldName)?.Value;
  292.                     if (name != null && name != "null")
  293.                     {
  294.                         SetValue(info, root.Attribute(fieldName).Value);
  295.                        // field.SetValue(this, root.Attribute(fieldName).Value);
  296.                     }
  297.                 }
  298.                 else if (typeof(IEnumerable).IsAssignableFrom(field.FieldType))
  299.                 {
  300.                     LoadArray(field, root.Element(fieldName));
  301.                 }
  302.                 //If the field is a class (so not a primal value like int, string)
  303.                 else if (field.FieldType.IsClass)
  304.                 {
  305.                     SetValue(info, LoadObject(field.FieldType, root.Element(fieldName)));
  306.                     //field.SetValue(this, LoadObject(field.FieldType, root.Element(fieldName)));
  307.                 }
  308.                 else
  309.                 {
  310.                     XAttribute xAttribute = null;
  311.                     try
  312.                     {
  313.                         xAttribute = root.Attribute(fieldName);
  314.                     }
  315.                     catch
  316.                     {
  317.                         Debug.Log(fieldName);
  318.                     }
  319.                     if (xAttribute != null)
  320.                     {
  321.                         var stored = xAttribute.Value;
  322.                         if (stored != "null")
  323.                         {
  324.                             var converter = TypeDescriptor.GetConverter(field.FieldType);
  325.                             try
  326.                             {
  327.                                 var converted = converter.ConvertFrom(stored);
  328.                                 SetValue(info, converted);
  329.  
  330.                                 //field.SetValue(this, converted);
  331.                             }
  332.                             catch
  333.                             {
  334.                                 Debug.Log("Cant convert " + field.FieldType + " from " + stored);
  335.                             }
  336.                         }
  337.                     }
  338.                     else
  339.                     {
  340.                         //Debug.Log(fieldName);
  341.                     }
  342.                 }
  343.             }
  344.         }
  345.  
  346.         private void SetValue(MemberInfo info, object value)
  347.         {
  348.             var propertyInfo = info as PropertyInfo;
  349.             if (propertyInfo != null)
  350.             {
  351.                 propertyInfo.SetValue(this, value);
  352.             }
  353.             var fieldInfo = info as FieldInfo;
  354.             if (fieldInfo != null)
  355.             {
  356.                 fieldInfo.SetValue(this, value);
  357.             }
  358.         }
  359.  
  360.         private object LoadObject(Type type, XElement element)
  361.         {
  362.             if (typeof(Saveable).IsAssignableFrom(type))
  363.             {
  364.                 ConstructorInfo ci = type.GetConstructor(
  365.                     BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic,
  366.                     null, new Type[]{}, null);
  367.                 if (ci == null)
  368.                 {
  369.                     throw new NullReferenceException($"Class {type} does not have a parameterless constructor. " +
  370.                                                      "Please add a constructor to load it.");
  371.                 }
  372.                 var o = (Saveable) ci.Invoke(new object[] { });
  373.                 var savedata = (Saveable) o;
  374.                 savedata.LoadData(element);
  375.                 return savedata;
  376.             }
  377.             else if (type == typeof(string))
  378.             {
  379.                 return element.Attribute("value").Value;
  380.             }
  381.             else if (type == typeof(int))
  382.             {
  383.                 return int.Parse(element.Attribute("value").Value);
  384.             }
  385.             else if (type == typeof(bool))
  386.             {
  387.                 return bool.Parse(element.Attribute("value").Value);
  388.             }
  389.             else if (type.IsEnum)
  390.             {
  391.                 var underlying = type.GetEnumUnderlyingType();
  392.                 return Convert.ChangeType(element.Attribute("value").Value, underlying);
  393.             }
  394.             else if (type == typeof(Vector3))
  395.             {
  396.                 var val = element.Attribute("value").Value;
  397.                 var a = val.Split(',');
  398.                 var vec = new Vector3(float.Parse(a[0]),float.Parse(a[1]),float.Parse(a[2]));
  399.                 return vec;
  400.             }
  401.             Debug.Log($"{type} does not implement saveable, and doesn't appear to be a based on a base type that's saved");
  402.             return null;
  403.         }
  404.  
  405.         private IEnumerable LoadArray(FieldInfo field, XElement element)
  406.         {
  407.             if (element == null)
  408.             {
  409.                 throw new NullReferenceException(field + " is empty. " + this.GetType().Name);
  410.             }
  411.             if (!element.HasElements)
  412.             {
  413.                 if (element.Attribute("value") != null && field.FieldType == typeof(byte[]))
  414.                 {
  415.                     var bar = Convert.FromBase64String(element.Attribute("value").Value);
  416.                     field.SetValue(this, bar);
  417.                     return bar;
  418.                 }
  419.             }
  420.             else
  421.             {
  422.                 if (field.FieldType.IsArray)
  423.                 {
  424.                     var t = field.FieldType.GetElementType();
  425.                     var count = int.Parse(element.Attribute("Length").Value);
  426.  
  427.                     var arr = Array.CreateInstance(t, count);
  428.                     foreach (var xElement in element.Elements())
  429.                     {
  430.                         if (xElement.Attribute("value") != null && xElement.Attribute("value").Value == "null")
  431.                         {
  432.                             continue;
  433.                         }
  434.                         var index = int.Parse(xElement.Attribute("ArrayIndex").Value);
  435.                         if (typeof(Saveable).IsAssignableFrom(t))
  436.                         {
  437.                             ConstructorInfo ci = t.GetConstructor(
  438.                                 BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic,
  439.                                 null, new Type[]{}, null);
  440.                             if (ci == null)
  441.                             {
  442.                                 throw new Exception($"Can't find a parameteless constructor for type {t}");
  443.                             }
  444.                             var o = (Saveable) ci.Invoke(new object[] { });
  445.                             var save = (Saveable) o;
  446.                             save.LoadData(xElement);
  447.                             arr.SetValue(save, index);
  448.                         }
  449.                         else
  450.                         {
  451.                             var converter = TypeDescriptor.GetConverter(t);
  452.                             arr.SetValue(converter.ConvertFrom(xElement.Attribute("value").Value), index);
  453.                         }
  454.                     }
  455.                     field.SetValue(this, arr);
  456.                     return arr;
  457.                 }
  458.                 else if (field.FieldType == typeof(OrderedDictionary))
  459.                 {
  460.                     var od = new OrderedDictionary();
  461.  
  462.                     field.SetValue(this, od);
  463.                     return od;
  464.                 }
  465.                 else if (field.FieldType.IsGenericType &&
  466.                          field.FieldType.GetGenericTypeDefinition() == typeof(Dictionary<,>))
  467.                 {
  468.                     var args = field.FieldType.GetGenericArguments();
  469.                     var keyType = args.First();
  470.                     var valueType = args[1];
  471.  
  472.                     var dicType = typeof(Dictionary<,>).MakeGenericType(keyType, valueType);
  473.                     var dic = (IDictionary)Activator.CreateInstance(dicType);
  474.                     foreach (var xElement in element.Elements())
  475.                     {
  476.                         var keyElement = xElement.Element("key");
  477.                         var keyObject = LoadObject(keyType, keyElement);
  478.                         var valueElement = xElement.Element("value");
  479.                         var valueObject = LoadObject(valueType, valueElement);
  480.                         dic.Add(keyObject, valueObject);
  481.                     }
  482.                     field.SetValue(this, dic);
  483.                 }
  484.                 else
  485.                 {
  486.                     var t = field.FieldType.GetGenericArguments().First();
  487.  
  488.                     var l = typeof(List<>).MakeGenericType(t);
  489.                     var ls = (IList) Activator.CreateInstance(l);
  490.                     foreach (var xElement in element.Elements())
  491.                     {
  492.                         if (typeof(Saveable).IsAssignableFrom(t))
  493.                         {
  494.                             var xAttribute = xElement.Attribute("value");
  495.                             if (xAttribute != null && xAttribute.Value == "null")
  496.                                 continue;
  497.                             var save = (Saveable) Activator.CreateInstance(t);
  498.                             save.LoadData(xElement);
  499.                             ls.Add(save);
  500.                         }
  501.                         else if (typeof(IEnumerable).IsAssignableFrom(t))
  502.                         {
  503.                             var subArr = LoadArray(field, xElement);
  504.                             ls.Add(subArr);
  505.                         }
  506.                         else
  507.                         {
  508.                             throw new Exception(t.ToString());
  509.                         }
  510.                         //ls.Add(xElement);
  511.                     }
  512.                     field.SetValue(this, ls);
  513.                     return ls;
  514.                 }
  515.  
  516.                 //field.SetValue(this, l);
  517.  
  518.             }
  519.             return null;
  520.         }
  521.  
  522.     }
  523. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement