dx
This commit is contained in:
@@ -0,0 +1,794 @@
|
||||
/* INFINITY CODE 2013-2019 */
|
||||
/* http://www.infinity-code.com */
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using InfinityCode.RealWorldTerrain.Utils;
|
||||
using UnityEngine;
|
||||
|
||||
namespace InfinityCode.RealWorldTerrain.JSON
|
||||
{
|
||||
/// <summary>
|
||||
/// Class for working with JSON. It is used for parsing of string, serialization and deserialization of object.
|
||||
/// </summary>
|
||||
public class RealWorldTerrainJson
|
||||
{
|
||||
private string json;
|
||||
private int index = 0;
|
||||
private Token lookAheadToken = Token.None;
|
||||
private StringBuilder s;
|
||||
private int length;
|
||||
|
||||
protected RealWorldTerrainJson(string json)
|
||||
{
|
||||
s = new StringBuilder();
|
||||
this.json = json;
|
||||
length = json.Length;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deserialize string into object.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Type</typeparam>
|
||||
/// <param name="json">JSON string</param>
|
||||
/// <returns>Deserialized object</returns>
|
||||
public static T Deserialize<T>(string json)
|
||||
{
|
||||
object obj = ParseDirect(json);
|
||||
if (obj is IDictionary) return (T) DeserializeObject(typeof(T), obj as Dictionary<string, object>);
|
||||
if (obj is IList) return (T) DeserializeArray(typeof(T), obj as List<object>);
|
||||
return (T) DeserializeValue(typeof(T), obj);
|
||||
}
|
||||
|
||||
private static object DeserializeValue(Type type, object obj)
|
||||
{
|
||||
if (obj == null) return null;
|
||||
try
|
||||
{
|
||||
return Convert.ChangeType(obj, type);
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
Debug.Log(exception.Message + "\n" + exception.StackTrace);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static object DeserializeArray(Type type, List<object> list)
|
||||
{
|
||||
if (list == null || list.Count == 0) return null;
|
||||
if (type.IsArray)
|
||||
{
|
||||
Type elementType = type.GetElementType();
|
||||
Array v = Array.CreateInstance(elementType, list.Count);
|
||||
for (int i = 0; i < list.Count; i++)
|
||||
{
|
||||
object child = list[i];
|
||||
object item;
|
||||
if (child is IDictionary) item = DeserializeObject(elementType, child as Dictionary<string, object>);
|
||||
else if (child is IList) item = DeserializeArray(elementType, child as List<object>);
|
||||
else item = DeserializeValue(elementType, child);
|
||||
v.SetValue(item, i);
|
||||
}
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
if (RealWorldTerrainReflectionHelper.IsGenericType(type))
|
||||
{
|
||||
Type listType = RealWorldTerrainReflectionHelper.GetGenericArguments(type)[0];
|
||||
object v = Activator.CreateInstance(type);
|
||||
|
||||
for (int i = 0; i < list.Count; i++)
|
||||
{
|
||||
object child = list[i];
|
||||
object item;
|
||||
if (child is IDictionary) item = DeserializeObject(listType, child as Dictionary<string, object>);
|
||||
else if (child is IList) item = DeserializeArray(listType, child as List<object>);
|
||||
else item = DeserializeValue(listType, child);
|
||||
try
|
||||
{
|
||||
MethodInfo methodInfo = RealWorldTerrainReflectionHelper.GetMethod(type, "Add");
|
||||
if (methodInfo != null) methodInfo.Invoke(v, new[] {item});
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static object DeserializeObject(Type type, Dictionary<string, object> table)
|
||||
{
|
||||
IEnumerable<MemberInfo> members = RealWorldTerrainReflectionHelper.GetMembers(type, BindingFlags.Instance | BindingFlags.Public);
|
||||
|
||||
object v = Activator.CreateInstance(type);
|
||||
|
||||
foreach (MemberInfo member in members)
|
||||
{
|
||||
#if !NETFX_CORE
|
||||
MemberTypes memberType = member.MemberType;
|
||||
if (memberType != MemberTypes.Field && memberType != MemberTypes.Property) continue;
|
||||
#else
|
||||
MemberTypes memberType;
|
||||
if (member is PropertyInfo) memberType = MemberTypes.Property;
|
||||
else if (member is FieldInfo) memberType = MemberTypes.Field;
|
||||
else continue;
|
||||
#endif
|
||||
|
||||
if (memberType == MemberTypes.Property && !((PropertyInfo) member).CanWrite) continue;
|
||||
object item;
|
||||
|
||||
#if !NETFX_CORE
|
||||
object[] attributes = member.GetCustomAttributes(typeof(AliasAttribute), true);
|
||||
AliasAttribute alias = attributes.Length > 0 ? attributes[0] as AliasAttribute : null;
|
||||
#else
|
||||
IEnumerable<Attribute> attributes = member.GetCustomAttributes(typeof(AliasAttribute), true);
|
||||
AliasAttribute alias = null;
|
||||
foreach (Attribute a in attributes)
|
||||
{
|
||||
alias = a as AliasAttribute;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
if (alias == null || !alias.ignoreFieldName)
|
||||
{
|
||||
if (table.TryGetValue(member.Name, out item))
|
||||
{
|
||||
DeserializeValue(memberType, member, item, v);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (alias != null)
|
||||
{
|
||||
for (int j = 0; j < alias.aliases.Length; j++)
|
||||
{
|
||||
if (table.TryGetValue(alias.aliases[j], out item))
|
||||
{
|
||||
DeserializeValue(memberType, member, item, v);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
private static void DeserializeValue(MemberTypes memberType, MemberInfo member, object item, object v)
|
||||
{
|
||||
object cv;
|
||||
Type t = memberType == MemberTypes.Field ? ((FieldInfo) member).FieldType : ((PropertyInfo) member).PropertyType;
|
||||
if (t == typeof(System.Object)) cv = item;
|
||||
else if (item is IDictionary) cv = DeserializeObject(t, item as Dictionary<string, object>);
|
||||
else if (item is IList) cv = DeserializeArray(t, item as List<object>);
|
||||
else cv = DeserializeValue(t, item);
|
||||
|
||||
if (memberType == MemberTypes.Field) ((FieldInfo) member).SetValue(v, cv);
|
||||
else ((PropertyInfo) member).SetValue(v, cv, null);
|
||||
}
|
||||
|
||||
private Token LookAhead()
|
||||
{
|
||||
if (lookAheadToken != Token.None) return lookAheadToken;
|
||||
return lookAheadToken = NextTokenCore();
|
||||
}
|
||||
|
||||
private Token NextToken()
|
||||
{
|
||||
Token result = lookAheadToken != Token.None ? lookAheadToken : NextTokenCore();
|
||||
lookAheadToken = Token.None;
|
||||
return result;
|
||||
}
|
||||
|
||||
private Token NextTokenCore()
|
||||
{
|
||||
char c;
|
||||
|
||||
do
|
||||
{
|
||||
c = json[index];
|
||||
|
||||
if (c == '/' && json[index + 1] == '/')
|
||||
{
|
||||
index += 2;
|
||||
do
|
||||
{
|
||||
c = json[index];
|
||||
if (c == '\r' || c == '\n') break;
|
||||
} while (++index < length);
|
||||
}
|
||||
|
||||
if (c > ' ') break;
|
||||
if (c != ' ' && c != '\t' && c != '\n' && c != '\r') break;
|
||||
|
||||
} while (++index < length);
|
||||
|
||||
if (index == length) throw new Exception("Reached end of string unexpectedly");
|
||||
|
||||
c = json[index];
|
||||
|
||||
index++;
|
||||
|
||||
switch (c)
|
||||
{
|
||||
case '{':
|
||||
return Token.Curly_Open;
|
||||
|
||||
case '}':
|
||||
return Token.Curly_Close;
|
||||
|
||||
case '[':
|
||||
return Token.Squared_Open;
|
||||
|
||||
case ']':
|
||||
return Token.Squared_Close;
|
||||
|
||||
case ',':
|
||||
return Token.Comma;
|
||||
|
||||
case '"':
|
||||
return Token.String;
|
||||
|
||||
case '0':
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
case '7':
|
||||
case '8':
|
||||
case '9':
|
||||
case '-':
|
||||
case '+':
|
||||
case '.':
|
||||
return Token.Number;
|
||||
|
||||
case ':':
|
||||
return Token.Colon;
|
||||
|
||||
case 'f':
|
||||
if (length - index >= 4 &&
|
||||
json[index + 0] == 'a' &&
|
||||
json[index + 1] == 'l' &&
|
||||
json[index + 2] == 's' &&
|
||||
json[index + 3] == 'e')
|
||||
{
|
||||
index += 4;
|
||||
return Token.False;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 't':
|
||||
if (length - index >= 3 &&
|
||||
json[index + 0] == 'r' &&
|
||||
json[index + 1] == 'u' &&
|
||||
json[index + 2] == 'e')
|
||||
{
|
||||
index += 3;
|
||||
return Token.True;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 'n':
|
||||
if (length - index >= 3 &&
|
||||
json[index + 0] == 'u' &&
|
||||
json[index + 1] == 'l' &&
|
||||
json[index + 2] == 'l')
|
||||
{
|
||||
index += 3;
|
||||
return Token.Null;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
throw new Exception("Could not find token at index " + --index);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parse JSON string into RealWorldTerrainJsonItem
|
||||
/// </summary>
|
||||
/// <param name="json">JSON string</param>
|
||||
/// <returns>Root object</returns>
|
||||
public static RealWorldTerrainJsonItem Parse(string json)
|
||||
{
|
||||
RealWorldTerrainJson instance = new RealWorldTerrainJson(json);
|
||||
return instance.ParseValue();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parse JSON string into Dictonary, List and Object
|
||||
/// </summary>
|
||||
/// <param name="json">JSON string</param>
|
||||
/// <returns>Root object</returns>
|
||||
public static object ParseDirect(string json)
|
||||
{
|
||||
RealWorldTerrainJson instance = new RealWorldTerrainJson(json);
|
||||
return instance.ParseValueDirect();
|
||||
}
|
||||
|
||||
private RealWorldTerrainJsonArray ParseArray()
|
||||
{
|
||||
RealWorldTerrainJsonArray array = new RealWorldTerrainJsonArray();
|
||||
lookAheadToken = Token.None;
|
||||
|
||||
while (true)
|
||||
{
|
||||
switch (LookAhead())
|
||||
{
|
||||
case Token.Comma:
|
||||
lookAheadToken = Token.None;
|
||||
break;
|
||||
|
||||
case Token.Squared_Close:
|
||||
lookAheadToken = Token.None;
|
||||
return array;
|
||||
|
||||
default:
|
||||
array.Add(ParseValue());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private List<object> ParseArrayDirect()
|
||||
{
|
||||
List<object> array = new List<object>();
|
||||
lookAheadToken = Token.None;
|
||||
|
||||
while (true)
|
||||
{
|
||||
switch (LookAhead())
|
||||
{
|
||||
case Token.Comma:
|
||||
lookAheadToken = Token.None;
|
||||
break;
|
||||
|
||||
case Token.Squared_Close:
|
||||
lookAheadToken = Token.None;
|
||||
return array;
|
||||
|
||||
default:
|
||||
array.Add(ParseValueDirect());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private object ParseNumber()
|
||||
{
|
||||
lookAheadToken = Token.None;
|
||||
|
||||
index--;
|
||||
|
||||
long n = 0;
|
||||
bool neg = false;
|
||||
long decimalV = 0;
|
||||
long exp = 0;
|
||||
bool negExp = false;
|
||||
|
||||
while (index < length)
|
||||
{
|
||||
char c = json[index];
|
||||
|
||||
if (c >= '0' && c <= '9')
|
||||
{
|
||||
n = n * 10 + (c - '0');
|
||||
decimalV *= 10;
|
||||
}
|
||||
else if (c == '.')
|
||||
{
|
||||
decimalV = 1;
|
||||
}
|
||||
else if (c == '-') neg = true;
|
||||
else if (c == '+') neg = false;
|
||||
else if (c == 'e' || c == 'E')
|
||||
{
|
||||
if (decimalV == 0) decimalV = 1;
|
||||
index++;
|
||||
exp = 0;
|
||||
while (index < length)
|
||||
{
|
||||
c = json[index];
|
||||
if (c >= '0' && c <= '9') exp = exp * 10 + (c - '0');
|
||||
else if (c == '-') negExp = true;
|
||||
else if (c == '+') negExp = false;
|
||||
else break;
|
||||
index++;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
else break;
|
||||
|
||||
index++;
|
||||
}
|
||||
|
||||
if (neg) n = -n;
|
||||
if (decimalV != 0)
|
||||
{
|
||||
double v = n / (double) decimalV;
|
||||
if (exp > 0)
|
||||
{
|
||||
if (negExp) v /= Math.Pow(10, exp);
|
||||
else v *= Math.Pow(10, exp);
|
||||
}
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
private RealWorldTerrainJsonObject ParseObject()
|
||||
{
|
||||
RealWorldTerrainJsonObject obj = new RealWorldTerrainJsonObject();
|
||||
|
||||
lookAheadToken = Token.None;
|
||||
|
||||
while (true)
|
||||
{
|
||||
switch (LookAhead())
|
||||
{
|
||||
|
||||
case Token.Comma:
|
||||
lookAheadToken = Token.None;
|
||||
break;
|
||||
|
||||
case Token.Curly_Close:
|
||||
lookAheadToken = Token.None;
|
||||
return obj;
|
||||
|
||||
default:
|
||||
{
|
||||
string name = ParseString();
|
||||
if (NextToken() != Token.Colon) throw new Exception("Expected colon at index " + index);
|
||||
obj.Add(name, ParseValue());
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Dictionary<string, object> ParseObjectDirect()
|
||||
{
|
||||
Dictionary<string, object> obj = new Dictionary<string, object>();
|
||||
|
||||
lookAheadToken = Token.None;
|
||||
|
||||
while (true)
|
||||
{
|
||||
switch (LookAhead())
|
||||
{
|
||||
|
||||
case Token.Comma:
|
||||
lookAheadToken = Token.None;
|
||||
break;
|
||||
|
||||
case Token.Curly_Close:
|
||||
lookAheadToken = Token.None;
|
||||
return obj;
|
||||
|
||||
default:
|
||||
{
|
||||
string name = ParseString();
|
||||
if (NextToken() != Token.Colon) throw new Exception("Expected colon at index " + index);
|
||||
obj.Add(name, ParseValueDirect());
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private uint ParseSingleChar(char c1, uint multipliyer)
|
||||
{
|
||||
uint p1 = 0;
|
||||
if (c1 >= '0' && c1 <= '9') p1 = (uint) (c1 - '0') * multipliyer;
|
||||
else if (c1 >= 'A' && c1 <= 'F') p1 = (uint) (c1 - 'A' + 10) * multipliyer;
|
||||
else if (c1 >= 'a' && c1 <= 'f') p1 = (uint) (c1 - 'a' + 10) * multipliyer;
|
||||
return p1;
|
||||
}
|
||||
|
||||
private string ParseString()
|
||||
{
|
||||
lookAheadToken = Token.None;
|
||||
|
||||
s.Length = 0;
|
||||
|
||||
int runIndex = -1;
|
||||
int l = length;
|
||||
string p = json;
|
||||
{
|
||||
while (index < l)
|
||||
{
|
||||
char c = p[index++];
|
||||
|
||||
if (c == '"')
|
||||
{
|
||||
if (runIndex != -1)
|
||||
{
|
||||
if (s.Length == 0) return p.Substring(runIndex, index - runIndex - 1);
|
||||
s.Append(p, runIndex, index - runIndex - 1);
|
||||
}
|
||||
|
||||
return s.ToString();
|
||||
}
|
||||
|
||||
if (c != '\\')
|
||||
{
|
||||
if (runIndex == -1) runIndex = index - 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (index == l) break;
|
||||
|
||||
if (runIndex != -1)
|
||||
{
|
||||
s.Append(p, runIndex, index - runIndex - 1);
|
||||
runIndex = -1;
|
||||
}
|
||||
|
||||
switch (p[index++])
|
||||
{
|
||||
case '"':
|
||||
s.Append('"');
|
||||
break;
|
||||
|
||||
case '\\':
|
||||
s.Append('\\');
|
||||
break;
|
||||
|
||||
case '/':
|
||||
s.Append('/');
|
||||
break;
|
||||
|
||||
case 'b':
|
||||
s.Append('\b');
|
||||
break;
|
||||
|
||||
case 'f':
|
||||
s.Append('\f');
|
||||
break;
|
||||
|
||||
case 'n':
|
||||
s.Append('\n');
|
||||
break;
|
||||
|
||||
case 'r':
|
||||
s.Append('\r');
|
||||
break;
|
||||
|
||||
case 't':
|
||||
s.Append('\t');
|
||||
break;
|
||||
|
||||
case 'u':
|
||||
{
|
||||
int remainingLength = l - index;
|
||||
if (remainingLength < 4) break;
|
||||
|
||||
uint codePoint = ParseUnicode(p[index], p[index + 1], p[index + 2], p[index + 3]);
|
||||
s.Append((char) codePoint);
|
||||
|
||||
index += 4;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
throw new Exception("Unexpectedly reached end of string");
|
||||
}
|
||||
|
||||
private uint ParseUnicode(char c1, char c2, char c3, char c4)
|
||||
{
|
||||
uint p1 = ParseSingleChar(c1, 0x1000);
|
||||
uint p2 = ParseSingleChar(c2, 0x100);
|
||||
uint p3 = ParseSingleChar(c3, 0x10);
|
||||
uint p4 = ParseSingleChar(c4, 1);
|
||||
|
||||
return p1 + p2 + p3 + p4;
|
||||
}
|
||||
|
||||
private RealWorldTerrainJsonItem ParseValue()
|
||||
{
|
||||
switch (LookAhead())
|
||||
{
|
||||
case Token.Number:
|
||||
object number = ParseNumber();
|
||||
return new RealWorldTerrainJsonValue(number, number is double ? RealWorldTerrainJsonValue.ValueType.DOUBLE : RealWorldTerrainJsonValue.ValueType.LONG);
|
||||
|
||||
case Token.String:
|
||||
return new RealWorldTerrainJsonValue(ParseString(), RealWorldTerrainJsonValue.ValueType.STRING);
|
||||
|
||||
case Token.Curly_Open:
|
||||
return ParseObject();
|
||||
|
||||
case Token.Squared_Open:
|
||||
return ParseArray();
|
||||
|
||||
case Token.True:
|
||||
lookAheadToken = Token.None;
|
||||
return new RealWorldTerrainJsonValue(true, RealWorldTerrainJsonValue.ValueType.BOOLEAN);
|
||||
|
||||
case Token.False:
|
||||
lookAheadToken = Token.None;
|
||||
return new RealWorldTerrainJsonValue(false, RealWorldTerrainJsonValue.ValueType.BOOLEAN);
|
||||
|
||||
case Token.Null:
|
||||
lookAheadToken = Token.None;
|
||||
return new RealWorldTerrainJsonValue(null, RealWorldTerrainJsonValue.ValueType.NULL);
|
||||
}
|
||||
|
||||
throw new Exception("Unrecognized token at index" + index);
|
||||
}
|
||||
|
||||
private object ParseValueDirect()
|
||||
{
|
||||
switch (LookAhead())
|
||||
{
|
||||
case Token.Number:
|
||||
return ParseNumber();
|
||||
|
||||
case Token.String:
|
||||
return ParseString();
|
||||
|
||||
case Token.Curly_Open:
|
||||
return ParseObjectDirect();
|
||||
|
||||
case Token.Squared_Open:
|
||||
return ParseArrayDirect();
|
||||
|
||||
case Token.True:
|
||||
lookAheadToken = Token.None;
|
||||
return true;
|
||||
|
||||
case Token.False:
|
||||
lookAheadToken = Token.None;
|
||||
return false;
|
||||
|
||||
case Token.Null:
|
||||
lookAheadToken = Token.None;
|
||||
return null;
|
||||
}
|
||||
|
||||
throw new Exception("Unrecognized token at index" + index);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Serializes an object to JSON.
|
||||
/// </summary>
|
||||
/// <param name="obj">Object</param>
|
||||
/// <param name="bindingFlags">A bitmask comprised of one or more BindingFlags that specify how the search is conducted.</param>
|
||||
/// <returns>JSON</returns>
|
||||
public static RealWorldTerrainJsonItem Serialize(object obj, BindingFlags bindingFlags = BindingFlags.Instance | BindingFlags.Public)
|
||||
{
|
||||
#if !UNITY_WP_8_1 || UNITY_EDITOR
|
||||
if (obj == null || obj is DBNull) return new RealWorldTerrainJsonValue(obj, RealWorldTerrainJsonValue.ValueType.NULL);
|
||||
#else
|
||||
if (obj == null) return new RealWorldTerrainJsonValue(obj, RealWorldTerrainJsonValue.ValueType.NULL);
|
||||
#endif
|
||||
if (obj is string || obj is bool || obj is int || obj is long || obj is short || obj is float || obj is double) return new RealWorldTerrainJsonValue(obj);
|
||||
if (obj is UnityEngine.Object)
|
||||
{
|
||||
if (!(obj is Component || obj is ScriptableObject)) return new RealWorldTerrainJsonValue((obj as UnityEngine.Object).GetInstanceID());
|
||||
}
|
||||
|
||||
if (obj is IDictionary)
|
||||
{
|
||||
IDictionary d = obj as IDictionary;
|
||||
RealWorldTerrainJsonObject dv = new RealWorldTerrainJsonObject();
|
||||
ICollection keys = d.Keys;
|
||||
ICollection values = d.Values;
|
||||
IEnumerator keysEnum = keys.GetEnumerator();
|
||||
IEnumerator valuesEnum = values.GetEnumerator();
|
||||
while (keysEnum.MoveNext() && valuesEnum.MoveNext())
|
||||
{
|
||||
object k = keysEnum.Current;
|
||||
object v = valuesEnum.Current;
|
||||
|
||||
dv.Add(k as string, Serialize(v, bindingFlags));
|
||||
}
|
||||
|
||||
return dv;
|
||||
}
|
||||
|
||||
if (obj is IEnumerable)
|
||||
{
|
||||
IEnumerable v = (IEnumerable) obj;
|
||||
RealWorldTerrainJsonArray array = new RealWorldTerrainJsonArray();
|
||||
foreach (var item in v) array.Add(Serialize(item, bindingFlags));
|
||||
return array;
|
||||
}
|
||||
|
||||
RealWorldTerrainJsonObject o = new RealWorldTerrainJsonObject();
|
||||
Type type = obj.GetType();
|
||||
|
||||
if (RealWorldTerrainReflectionHelper.CheckIfAnonymousType(type)) bindingFlags |= BindingFlags.NonPublic;
|
||||
IEnumerable<FieldInfo> fields = RealWorldTerrainReflectionHelper.GetFields(type, bindingFlags);
|
||||
foreach (FieldInfo field in fields)
|
||||
{
|
||||
string fieldName = field.Name;
|
||||
if (field.Attributes == (FieldAttributes.Private | FieldAttributes.InitOnly))
|
||||
{
|
||||
int startIndex = fieldName.IndexOf('<') + 1;
|
||||
int endIndex = fieldName.IndexOf('>', startIndex);
|
||||
if (endIndex != -1 && startIndex != -1) fieldName = fieldName.Substring(startIndex, endIndex - startIndex);
|
||||
else fieldName = fieldName.Trim('<', '>');
|
||||
}
|
||||
|
||||
o.Add(fieldName, Serialize(field.GetValue(obj)));
|
||||
}
|
||||
|
||||
return o;
|
||||
}
|
||||
|
||||
private enum Token
|
||||
{
|
||||
None = -1,
|
||||
Curly_Open,
|
||||
Curly_Close,
|
||||
Squared_Open,
|
||||
Squared_Close,
|
||||
Colon,
|
||||
Comma,
|
||||
String,
|
||||
Number,
|
||||
True,
|
||||
False,
|
||||
Null
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Alias of field used during deserialization.
|
||||
/// </summary>
|
||||
public class AliasAttribute : Attribute
|
||||
{
|
||||
/// <summary>
|
||||
/// Aliases
|
||||
/// </summary>
|
||||
public readonly string[] aliases;
|
||||
|
||||
/// <summary>
|
||||
/// If true, the original field name will be ignored.
|
||||
/// </summary>
|
||||
public readonly bool ignoreFieldName;
|
||||
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
/// <param name="ignoreFieldName">If true, the original field name will be ignored.</param>
|
||||
/// <param name="aliases">Aliases</param>
|
||||
public AliasAttribute(bool ignoreFieldName, params string[] aliases)
|
||||
{
|
||||
if (aliases == null || aliases.Length == 0) throw new Exception("You must use at least one alias.");
|
||||
|
||||
this.ignoreFieldName = ignoreFieldName;
|
||||
this.aliases = aliases;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
/// <param name="aliases">Aliases</param>
|
||||
public AliasAttribute(params string[] aliases) : this(false, aliases)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: caeec121996ee584c9fa1e236d7947b4
|
||||
timeCreated: 1564669254
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,274 @@
|
||||
/* INFINITY CODE 2013-2019 */
|
||||
/* http://www.infinity-code.com */
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using InfinityCode.RealWorldTerrain.Utils;
|
||||
|
||||
namespace InfinityCode.RealWorldTerrain.JSON
|
||||
{
|
||||
/// <summary>
|
||||
/// The wrapper for an array of JSON elements.
|
||||
/// </summary>
|
||||
public class RealWorldTerrainJsonArray : RealWorldTerrainJsonItem
|
||||
{
|
||||
private List<RealWorldTerrainJsonItem> _items;
|
||||
private int _count;
|
||||
|
||||
public List<RealWorldTerrainJsonItem> items
|
||||
{
|
||||
get { return _items; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Count elements
|
||||
/// </summary>
|
||||
public int count
|
||||
{
|
||||
get { return _count; }
|
||||
}
|
||||
|
||||
public override RealWorldTerrainJsonItem this[int index]
|
||||
{
|
||||
get
|
||||
{
|
||||
if (index < 0 || index >= _count) return null;
|
||||
return _items[index];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public override RealWorldTerrainJsonItem this[string key]
|
||||
{
|
||||
get { return Get(key); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
public RealWorldTerrainJsonArray()
|
||||
{
|
||||
_items = new List<RealWorldTerrainJsonItem>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds an element to the array.
|
||||
/// </summary>
|
||||
/// <param name="item">Element</param>
|
||||
public void Add(RealWorldTerrainJsonItem item)
|
||||
{
|
||||
_items.Add(item);
|
||||
_count++;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds an elements to the array.
|
||||
/// </summary>
|
||||
/// <param name="collection">Array of elements</param>
|
||||
public void AddRange(RealWorldTerrainJsonArray collection)
|
||||
{
|
||||
if (collection == null) return;
|
||||
_items.AddRange(collection._items);
|
||||
_count += collection._count;
|
||||
}
|
||||
|
||||
public void AddRange(RealWorldTerrainJsonItem collection)
|
||||
{
|
||||
AddRange(collection as RealWorldTerrainJsonArray);
|
||||
}
|
||||
|
||||
public RealWorldTerrainJsonObject CreateObject()
|
||||
{
|
||||
RealWorldTerrainJsonObject obj = new RealWorldTerrainJsonObject();
|
||||
Add(obj);
|
||||
return obj;
|
||||
}
|
||||
|
||||
public override object Deserialize(Type type, BindingFlags bindingFlags = BindingFlags.Instance | BindingFlags.Public)
|
||||
{
|
||||
if (_count == 0) return null;
|
||||
|
||||
if (type.IsArray)
|
||||
{
|
||||
Type elementType = type.GetElementType();
|
||||
Array v = Array.CreateInstance(elementType, _count);
|
||||
if (_items[0] is RealWorldTerrainJsonObject)
|
||||
{
|
||||
IEnumerable<MemberInfo> members = RealWorldTerrainReflectionHelper.GetMembers(elementType, bindingFlags);
|
||||
for (int i = 0; i < _count; i++)
|
||||
{
|
||||
RealWorldTerrainJsonItem child = _items[i];
|
||||
object item = (child as RealWorldTerrainJsonObject).Deserialize(elementType, members, bindingFlags);
|
||||
v.SetValue(item, i);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < _count; i++)
|
||||
{
|
||||
RealWorldTerrainJsonItem child = _items[i];
|
||||
object item = child.Deserialize(elementType, bindingFlags);
|
||||
v.SetValue(item, i);
|
||||
}
|
||||
}
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
if (RealWorldTerrainReflectionHelper.IsGenericType(type))
|
||||
{
|
||||
Type listType = RealWorldTerrainReflectionHelper.GetGenericArguments(type)[0];
|
||||
object v = Activator.CreateInstance(type);
|
||||
|
||||
if (_items[0] is RealWorldTerrainJsonObject)
|
||||
{
|
||||
IEnumerable<MemberInfo> members = RealWorldTerrainReflectionHelper.GetMembers(listType, BindingFlags.Instance | BindingFlags.Public);
|
||||
for (int i = 0; i < _count; i++)
|
||||
{
|
||||
RealWorldTerrainJsonItem child = _items[i];
|
||||
object item = (child as RealWorldTerrainJsonObject).Deserialize(listType, members);
|
||||
try
|
||||
{
|
||||
MethodInfo methodInfo = RealWorldTerrainReflectionHelper.GetMethod(type, "Add");
|
||||
if (methodInfo != null) methodInfo.Invoke(v, new[] { item });
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < _count; i++)
|
||||
{
|
||||
RealWorldTerrainJsonItem child = _items[i];
|
||||
object item = child.Deserialize(listType);
|
||||
try
|
||||
{
|
||||
MethodInfo methodInfo = RealWorldTerrainReflectionHelper.GetMethod(type, "Add");
|
||||
if (methodInfo != null) methodInfo.Invoke(v, new[] { item });
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private RealWorldTerrainJsonItem Get(string key)
|
||||
{
|
||||
if (string.IsNullOrEmpty(key)) return null;
|
||||
|
||||
if (key.StartsWith("//"))
|
||||
{
|
||||
string k = key.Substring(2);
|
||||
if (string.IsNullOrEmpty(k) || k.StartsWith("//")) return null;
|
||||
return GetAll(k);
|
||||
}
|
||||
|
||||
return GetThis(key);
|
||||
}
|
||||
|
||||
private RealWorldTerrainJsonItem GetThis(string key)
|
||||
{
|
||||
int kindex;
|
||||
|
||||
if (key.Contains("/"))
|
||||
{
|
||||
int index = key.IndexOf("/");
|
||||
string k = key.Substring(0, index);
|
||||
string nextPart = key.Substring(index + 1);
|
||||
|
||||
if (k == "*")
|
||||
{
|
||||
RealWorldTerrainJsonArray arr = new RealWorldTerrainJsonArray();
|
||||
for (int i = 0; i < _count; i++)
|
||||
{
|
||||
RealWorldTerrainJsonItem item = _items[i][nextPart];
|
||||
if (item != null) arr.Add(item);
|
||||
}
|
||||
|
||||
return arr;
|
||||
}
|
||||
|
||||
if (int.TryParse(k, out kindex))
|
||||
{
|
||||
if (kindex < 0 || kindex >= _count) return null;
|
||||
RealWorldTerrainJsonItem item = _items[kindex];
|
||||
return item[nextPart];
|
||||
}
|
||||
}
|
||||
|
||||
if (key == "*") return this;
|
||||
if (int.TryParse(key, out kindex)) return this[kindex];
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public override RealWorldTerrainJsonItem GetAll(string k)
|
||||
{
|
||||
RealWorldTerrainJsonItem item = GetThis(k);
|
||||
RealWorldTerrainJsonArray arr = null;
|
||||
if (item != null)
|
||||
{
|
||||
arr = new RealWorldTerrainJsonArray();
|
||||
arr.Add(item);
|
||||
}
|
||||
|
||||
for (int i = 0; i < _count; i++)
|
||||
{
|
||||
item = _items[i];
|
||||
RealWorldTerrainJsonArray subArr = item.GetAll(k) as RealWorldTerrainJsonArray;
|
||||
if (subArr != null)
|
||||
{
|
||||
if (arr == null) arr = new RealWorldTerrainJsonArray();
|
||||
arr.AddRange(subArr);
|
||||
}
|
||||
}
|
||||
|
||||
return arr;
|
||||
}
|
||||
|
||||
public override IEnumerator<RealWorldTerrainJsonItem> GetEnumerator()
|
||||
{
|
||||
return _items.GetEnumerator();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parse a string that contains an array
|
||||
/// </summary>
|
||||
/// <param name="json">JSON string</param>
|
||||
/// <returns>Instance</returns>
|
||||
public static RealWorldTerrainJsonArray ParseArray(string json)
|
||||
{
|
||||
return RealWorldTerrainJson.Parse(json) as RealWorldTerrainJsonArray;
|
||||
}
|
||||
|
||||
public override void ToJSON(StringBuilder b)
|
||||
{
|
||||
b.Append("[");
|
||||
for (int i = 0; i < _count; i++)
|
||||
{
|
||||
if (i != 0) b.Append(",");
|
||||
_items[i].ToJSON(b);
|
||||
}
|
||||
|
||||
b.Append("]");
|
||||
}
|
||||
|
||||
public override object Value(Type type)
|
||||
{
|
||||
if (RealWorldTerrainReflectionHelper.IsValueType(type)) return Activator.CreateInstance(type);
|
||||
return null;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4051daf2706fd35499b6795639764db5
|
||||
timeCreated: 1564669254
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,145 @@
|
||||
/* INFINITY CODE 2013-2019 */
|
||||
/* http://www.infinity-code.com */
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
|
||||
namespace InfinityCode.RealWorldTerrain.JSON
|
||||
{
|
||||
/// <summary>
|
||||
/// The base class of JSON elements.
|
||||
/// </summary>
|
||||
public abstract class RealWorldTerrainJsonItem : IEnumerable<RealWorldTerrainJsonItem>
|
||||
{
|
||||
/// <summary>
|
||||
/// Get the element by index
|
||||
/// </summary>
|
||||
/// <param name="index">Index of element</param>
|
||||
/// <returns>Element</returns>
|
||||
public abstract RealWorldTerrainJsonItem this[int index] { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Get the element by key.\n
|
||||
/// Supports XPath like selectors:\n
|
||||
/// ["key"] - get element by key.\n
|
||||
/// ["key1/key2"] - get element key2, which is a child of the element key1.\n
|
||||
/// ["key/N"] - where N is number. Get array element by index N, which is a child of the element key1.\n
|
||||
/// ["key/*"] - get all array elements, which is a child of the element key1.\n
|
||||
/// ["//key"] - get all elements with the key on the first or the deeper levels of the current element. \n
|
||||
/// </summary>
|
||||
/// <param name="key">Element key</param>
|
||||
/// <returns>Element</returns>
|
||||
public abstract RealWorldTerrainJsonItem this[string key] { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Serializes the object and adds to the current json node.
|
||||
/// </summary>
|
||||
/// <param name="obj">Object</param>
|
||||
/// <returns>Current json node</returns>
|
||||
public virtual RealWorldTerrainJsonItem AppendObject(object obj)
|
||||
{
|
||||
throw new Exception("AppendObject is only allowed for RealWorldTerrainJsonObject.");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the value of the child element, converted to the specified type.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Type of variable</typeparam>
|
||||
/// <param name="childName">Child element key</param>
|
||||
/// <returns>Value</returns>
|
||||
public T ChildValue<T>(string childName)
|
||||
{
|
||||
RealWorldTerrainJsonItem el = this[childName];
|
||||
if (el == null) return default(T);
|
||||
return el.Value<T>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deserializes current element
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Type</typeparam>
|
||||
/// <returns>Object</returns>
|
||||
public T Deserialize<T>(BindingFlags bindingFlags = BindingFlags.Instance | BindingFlags.Public)
|
||||
{
|
||||
return (T) Deserialize(typeof(T), bindingFlags);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deserializes current element
|
||||
/// </summary>
|
||||
/// <param name="type">Type</param>
|
||||
/// <returns>Object</returns>
|
||||
public abstract object Deserialize(Type type, BindingFlags bindingFlags = BindingFlags.Instance | BindingFlags.Public);
|
||||
|
||||
/// <summary>
|
||||
/// Get all elements with the key on the first or the deeper levels of the current element.
|
||||
/// </summary>
|
||||
/// <param name="key">Key</param>
|
||||
/// <returns>Elements</returns>
|
||||
public abstract RealWorldTerrainJsonItem GetAll(string key);
|
||||
|
||||
/// <summary>
|
||||
/// Converts the current and the child elements to JSON string.
|
||||
/// </summary>
|
||||
/// <param name="b">StringBuilder instance</param>
|
||||
public abstract void ToJSON(StringBuilder b);
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return GetEnumerator();
|
||||
}
|
||||
|
||||
public virtual IEnumerator<RealWorldTerrainJsonItem> GetEnumerator()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
StringBuilder b = new StringBuilder();
|
||||
ToJSON(b);
|
||||
return b.ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the value of the element, converted to the specified type.
|
||||
/// </summary>
|
||||
/// <param name="type">Type of variable</param>
|
||||
/// <returns>Value</returns>
|
||||
public abstract object Value(Type type);
|
||||
|
||||
/// <summary>
|
||||
/// Returns the value of the element, converted to the specified type.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Type of variable</typeparam>
|
||||
/// <returns>Value</returns>
|
||||
public virtual T Value<T>()
|
||||
{
|
||||
return (T) Value(typeof(T));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the value of the element, converted to the specified type.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Type of variable</typeparam>
|
||||
/// <returns>Value</returns>
|
||||
public T V<T>()
|
||||
{
|
||||
return Value<T>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the value of the child element, converted to the specified type.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Type of variable</typeparam>
|
||||
/// <param name="childName">Child element key</param>
|
||||
/// <returns>Value</returns>
|
||||
public T V<T>(string childName)
|
||||
{
|
||||
return ChildValue<T>(childName);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f76b4b0f8b1c1b54d8656a77ca5d340c
|
||||
timeCreated: 1564669254
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,325 @@
|
||||
/* INFINITY CODE 2013-2019 */
|
||||
/* http://www.infinity-code.com */
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using InfinityCode.RealWorldTerrain.Utils;
|
||||
using UnityEngine;
|
||||
|
||||
namespace InfinityCode.RealWorldTerrain.JSON
|
||||
{
|
||||
/// <summary>
|
||||
/// The wrapper for JSON dictonary.
|
||||
/// </summary>
|
||||
public class RealWorldTerrainJsonObject : RealWorldTerrainJsonItem
|
||||
{
|
||||
private Dictionary<string, RealWorldTerrainJsonItem> _table;
|
||||
|
||||
/// <summary>
|
||||
/// Dictionary of items
|
||||
/// </summary>
|
||||
public Dictionary<string, RealWorldTerrainJsonItem> table
|
||||
{
|
||||
get { return _table; }
|
||||
}
|
||||
|
||||
public override RealWorldTerrainJsonItem this[string key]
|
||||
{
|
||||
get { return Get(key); }
|
||||
}
|
||||
|
||||
public override RealWorldTerrainJsonItem this[int index]
|
||||
{
|
||||
get
|
||||
{
|
||||
if (index < 0) return null;
|
||||
|
||||
int i = 0;
|
||||
foreach (KeyValuePair<string, RealWorldTerrainJsonItem> pair in _table)
|
||||
{
|
||||
if (i == index) return pair.Value;
|
||||
i++;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
public RealWorldTerrainJsonObject()
|
||||
{
|
||||
_table = new Dictionary<string, RealWorldTerrainJsonItem>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds element to the dictionary
|
||||
/// </summary>
|
||||
/// <param name="name">Key</param>
|
||||
/// <param name="value">Value</param>
|
||||
public void Add(string name, RealWorldTerrainJsonItem value)
|
||||
{
|
||||
_table[name] = value;
|
||||
}
|
||||
|
||||
public void Add(string name, object value)
|
||||
{
|
||||
if (value is string || value is bool || value is int || value is long || value is short || value is float || value is double) _table[name] = new RealWorldTerrainJsonValue(value);
|
||||
else if (value is UnityEngine.Object)
|
||||
{
|
||||
_table[name] = new RealWorldTerrainJsonValue((value as UnityEngine.Object).GetInstanceID());
|
||||
}
|
||||
else _table[name] = RealWorldTerrainJson.Serialize(value, BindingFlags.Instance | BindingFlags.Public);
|
||||
}
|
||||
|
||||
public void Add(string name, object value, RealWorldTerrainJsonValue.ValueType valueType)
|
||||
{
|
||||
_table[name] = new RealWorldTerrainJsonValue(value, valueType);
|
||||
}
|
||||
|
||||
public override RealWorldTerrainJsonItem AppendObject(object obj)
|
||||
{
|
||||
Combine(RealWorldTerrainJson.Serialize(obj));
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Combines two JSON Object.
|
||||
/// </summary>
|
||||
/// <param name="other">Other JSON Object</param>
|
||||
/// <param name="overwriteExistingValues">Overwrite the existing values?</param>
|
||||
public void Combine(RealWorldTerrainJsonItem other, bool overwriteExistingValues = false)
|
||||
{
|
||||
RealWorldTerrainJsonObject otherObj = other as RealWorldTerrainJsonObject;
|
||||
if (otherObj == null) throw new Exception("Only RealWorldTerrainJsonObject is allowed to be combined.");
|
||||
Dictionary<string, RealWorldTerrainJsonItem> otherDict = otherObj.table;
|
||||
foreach (KeyValuePair<string, RealWorldTerrainJsonItem> pair in otherDict)
|
||||
{
|
||||
if (overwriteExistingValues || !_table.ContainsKey(pair.Key)) _table[pair.Key] = pair.Value;
|
||||
}
|
||||
}
|
||||
|
||||
public bool Contains(string key)
|
||||
{
|
||||
return _table.ContainsKey(key);
|
||||
}
|
||||
|
||||
public RealWorldTerrainJsonArray CreateArray(string name)
|
||||
{
|
||||
RealWorldTerrainJsonArray array = new RealWorldTerrainJsonArray();
|
||||
Add(name, array);
|
||||
return array;
|
||||
}
|
||||
|
||||
public RealWorldTerrainJsonObject CreateObject(string name)
|
||||
{
|
||||
RealWorldTerrainJsonObject obj = new RealWorldTerrainJsonObject();
|
||||
Add(name, obj);
|
||||
return obj;
|
||||
}
|
||||
|
||||
public override object Deserialize(Type type, BindingFlags bindingFlags = BindingFlags.Instance | BindingFlags.Public)
|
||||
{
|
||||
IEnumerable<MemberInfo> members = RealWorldTerrainReflectionHelper.GetMembers(type, bindingFlags);
|
||||
return Deserialize(type, members, bindingFlags);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deserializes current element
|
||||
/// </summary>
|
||||
/// <param name="type">Type</param>
|
||||
/// <param name="members">Members of variable</param>
|
||||
/// <returns>Object</returns>
|
||||
public object Deserialize(Type type, IEnumerable<MemberInfo> members, BindingFlags bindingFlags = BindingFlags.Instance | BindingFlags.Public)
|
||||
{
|
||||
object v = Activator.CreateInstance(type);
|
||||
DeserializeObject(v, members, bindingFlags);
|
||||
return v;
|
||||
}
|
||||
|
||||
public void DeserializeObject(object obj, BindingFlags bindingFlags = BindingFlags.Instance | BindingFlags.Public)
|
||||
{
|
||||
IEnumerable<MemberInfo> members = RealWorldTerrainReflectionHelper.GetMembers(obj.GetType(), bindingFlags);
|
||||
DeserializeObject(obj, members);
|
||||
}
|
||||
|
||||
public void DeserializeObject(object obj, IEnumerable<MemberInfo> members, BindingFlags bindingFlags = BindingFlags.Instance | BindingFlags.Public)
|
||||
{
|
||||
foreach (MemberInfo member in members)
|
||||
{
|
||||
#if !NETFX_CORE
|
||||
MemberTypes memberType = member.MemberType;
|
||||
if (memberType != MemberTypes.Field && memberType != MemberTypes.Property) continue;
|
||||
#else
|
||||
MemberTypes memberType;
|
||||
if (member is PropertyInfo) memberType = MemberTypes.Property;
|
||||
else if (member is FieldInfo) memberType = MemberTypes.Field;
|
||||
else continue;
|
||||
#endif
|
||||
|
||||
if (memberType == MemberTypes.Property && !((PropertyInfo) member).CanWrite) continue;
|
||||
RealWorldTerrainJsonItem item;
|
||||
|
||||
#if !NETFX_CORE
|
||||
object[] attributes = member.GetCustomAttributes(typeof(RealWorldTerrainJson.AliasAttribute), true);
|
||||
RealWorldTerrainJson.AliasAttribute alias = attributes.Length > 0 ? attributes[0] as RealWorldTerrainJson.AliasAttribute : null;
|
||||
#else
|
||||
IEnumerable<Attribute> attributes = member.GetCustomAttributes(typeof(RealWorldTerrainJson.AliasAttribute), true);
|
||||
RealWorldTerrainJson.AliasAttribute alias = null;
|
||||
foreach (Attribute a in attributes)
|
||||
{
|
||||
alias = a as RealWorldTerrainJson.AliasAttribute;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
if (alias == null || !alias.ignoreFieldName)
|
||||
{
|
||||
if (_table.TryGetValue(member.Name, out item))
|
||||
{
|
||||
Type t = memberType == MemberTypes.Field ? ((FieldInfo) member).FieldType : ((PropertyInfo) member).PropertyType;
|
||||
if (memberType == MemberTypes.Field) ((FieldInfo) member).SetValue(obj, item.Deserialize(t, bindingFlags));
|
||||
else ((PropertyInfo) member).SetValue(obj, item.Deserialize(t, bindingFlags), null);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (alias != null)
|
||||
{
|
||||
for (int j = 0; j < alias.aliases.Length; j++)
|
||||
{
|
||||
if (_table.TryGetValue(alias.aliases[j], out item))
|
||||
{
|
||||
Type t = memberType == MemberTypes.Field ? ((FieldInfo) member).FieldType : ((PropertyInfo) member).PropertyType;
|
||||
if (memberType == MemberTypes.Field) ((FieldInfo) member).SetValue(obj, item.Deserialize(t, bindingFlags));
|
||||
else ((PropertyInfo) member).SetValue(obj, item.Deserialize(t, bindingFlags), null);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private RealWorldTerrainJsonItem Get(string key)
|
||||
{
|
||||
if (string.IsNullOrEmpty(key)) return null;
|
||||
|
||||
if (key.Length > 2 && key[0] == '/' && key[1] == '/')
|
||||
{
|
||||
string k = key.Substring(2);
|
||||
if (string.IsNullOrEmpty(k) || k.StartsWith("//")) return null;
|
||||
return GetAll(k);
|
||||
}
|
||||
|
||||
return GetThis(key);
|
||||
}
|
||||
|
||||
private RealWorldTerrainJsonItem GetThis(string key)
|
||||
{
|
||||
RealWorldTerrainJsonItem item;
|
||||
int index = -1;
|
||||
for (int i = 0; i < key.Length; i++)
|
||||
{
|
||||
if (key[i] == '/')
|
||||
{
|
||||
index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (index != -1)
|
||||
{
|
||||
string k = key.Substring(0, index);
|
||||
if (!string.IsNullOrEmpty(k))
|
||||
{
|
||||
if (_table.TryGetValue(k, out item))
|
||||
{
|
||||
string nextPart = key.Substring(index + 1);
|
||||
return item[nextPart];
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
if (_table.TryGetValue(key, out item)) return item;
|
||||
return null;
|
||||
}
|
||||
|
||||
public override RealWorldTerrainJsonItem GetAll(string k)
|
||||
{
|
||||
RealWorldTerrainJsonItem item = GetThis(k);
|
||||
RealWorldTerrainJsonArray arr = null;
|
||||
if (item != null)
|
||||
{
|
||||
arr = new RealWorldTerrainJsonArray();
|
||||
arr.Add(item);
|
||||
}
|
||||
|
||||
var enumerator = _table.GetEnumerator();
|
||||
while (enumerator.MoveNext())
|
||||
{
|
||||
item = enumerator.Current.Value;
|
||||
RealWorldTerrainJsonArray subArr = item.GetAll(k) as RealWorldTerrainJsonArray;
|
||||
if (subArr != null)
|
||||
{
|
||||
if (arr == null) arr = new RealWorldTerrainJsonArray();
|
||||
arr.AddRange(subArr);
|
||||
}
|
||||
}
|
||||
|
||||
return arr;
|
||||
}
|
||||
|
||||
public override IEnumerator<RealWorldTerrainJsonItem> GetEnumerator()
|
||||
{
|
||||
return _table.Values.GetEnumerator();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parse a string that contains JSON dictonary
|
||||
/// </summary>
|
||||
/// <param name="json">String that contains JSON dictonary</param>
|
||||
/// <returns>Instance</returns>
|
||||
public static RealWorldTerrainJsonObject ParseObject(string json)
|
||||
{
|
||||
return RealWorldTerrainJson.Parse(json) as RealWorldTerrainJsonObject;
|
||||
}
|
||||
|
||||
public RealWorldTerrainJsonItem Remove(string key)
|
||||
{
|
||||
RealWorldTerrainJsonItem item;
|
||||
if (_table.TryGetValue(key, out item))
|
||||
{
|
||||
_table.Remove(key);
|
||||
return item;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public override void ToJSON(StringBuilder b)
|
||||
{
|
||||
b.Append("{");
|
||||
bool hasChilds = false;
|
||||
foreach (KeyValuePair<string, RealWorldTerrainJsonItem> pair in _table)
|
||||
{
|
||||
b.Append("\"").Append(pair.Key).Append("\"").Append(":");
|
||||
pair.Value.ToJSON(b);
|
||||
b.Append(",");
|
||||
hasChilds = true;
|
||||
}
|
||||
|
||||
if (hasChilds) b.Remove(b.Length - 1, 1);
|
||||
b.Append("}");
|
||||
}
|
||||
|
||||
public override object Value(Type type)
|
||||
{
|
||||
if (RealWorldTerrainReflectionHelper.IsValueType(type)) return Activator.CreateInstance(type);
|
||||
return Deserialize(type);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e795b994aaf01f2478404364e8b3b62a
|
||||
timeCreated: 1564669254
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,263 @@
|
||||
/* INFINITY CODE 2013-2019 */
|
||||
/* http://www.infinity-code.com */
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using InfinityCode.RealWorldTerrain.Utils;
|
||||
using UnityEngine;
|
||||
|
||||
namespace InfinityCode.RealWorldTerrain.JSON
|
||||
{
|
||||
/// <summary>
|
||||
/// The wrapper for JSON value.
|
||||
/// </summary>
|
||||
public class RealWorldTerrainJsonValue : RealWorldTerrainJsonItem
|
||||
{
|
||||
private ValueType _type;
|
||||
private object _value;
|
||||
|
||||
public override RealWorldTerrainJsonItem this[string key]
|
||||
{
|
||||
get { return null; }
|
||||
}
|
||||
|
||||
public override RealWorldTerrainJsonItem this[int index]
|
||||
{
|
||||
get { return null; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets / sets the current value
|
||||
/// </summary>
|
||||
public object value
|
||||
{
|
||||
get { return _value; }
|
||||
set
|
||||
{
|
||||
#if !UNITY_WP_8_1 || UNITY_EDITOR
|
||||
if (value == null || value is DBNull)
|
||||
#else
|
||||
if (value == null)
|
||||
#endif
|
||||
{
|
||||
_type = ValueType.NULL;
|
||||
_value = value;
|
||||
}
|
||||
else if (value is string)
|
||||
{
|
||||
_type = ValueType.STRING;
|
||||
_value = value;
|
||||
}
|
||||
else if (value is double)
|
||||
{
|
||||
_type = ValueType.DOUBLE;
|
||||
_value = (double) value;
|
||||
}
|
||||
else if (value is float)
|
||||
{
|
||||
_type = ValueType.DOUBLE;
|
||||
_value = (double) (float) value;
|
||||
}
|
||||
else if (value is bool)
|
||||
{
|
||||
_type = ValueType.BOOLEAN;
|
||||
_value = value;
|
||||
}
|
||||
else if (value is long)
|
||||
{
|
||||
_type = ValueType.LONG;
|
||||
_value = value;
|
||||
}
|
||||
else if (value is int || value is short || value is byte)
|
||||
{
|
||||
_type = ValueType.LONG;
|
||||
_value = Convert.ChangeType(value, typeof(long));
|
||||
}
|
||||
else throw new Exception("Unknown type of value.");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the type of value
|
||||
/// </summary>
|
||||
public ValueType type
|
||||
{
|
||||
get { return _type; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
/// <param name="value">Value</param>
|
||||
public RealWorldTerrainJsonValue(object value)
|
||||
{
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
/// <param name="value">Value</param>
|
||||
/// <param name="type">Type of value</param>
|
||||
public RealWorldTerrainJsonValue(object value, ValueType type)
|
||||
{
|
||||
_value = value;
|
||||
_type = type;
|
||||
}
|
||||
|
||||
public override object Deserialize(Type type, BindingFlags bindingFlags = BindingFlags.Instance | BindingFlags.Public)
|
||||
{
|
||||
return Value(type);
|
||||
}
|
||||
|
||||
public override RealWorldTerrainJsonItem GetAll(string key)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public override void ToJSON(StringBuilder b)
|
||||
{
|
||||
if (_type == ValueType.STRING) WriteString(b);
|
||||
else if (_type == ValueType.NULL) b.Append("null");
|
||||
else if (_type == ValueType.BOOLEAN) b.Append((bool) _value ? "true" : "false");
|
||||
else if (_type == ValueType.DOUBLE) b.Append(((double) value).ToString(RealWorldTerrainCultureInfo.cultureInfo));
|
||||
else b.Append(value);
|
||||
}
|
||||
|
||||
public override IEnumerator<RealWorldTerrainJsonItem> GetEnumerator()
|
||||
{
|
||||
yield return this;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
if (type == ValueType.DOUBLE) return ((double) value).ToString(RealWorldTerrainCultureInfo.cultureInfo);
|
||||
return value.ToString();
|
||||
}
|
||||
|
||||
public override object Value(Type t)
|
||||
{
|
||||
if (_type == ValueType.NULL || _value == null)
|
||||
{
|
||||
if (RealWorldTerrainReflectionHelper.IsValueType(t)) return Activator.CreateInstance(t);
|
||||
return null;
|
||||
}
|
||||
|
||||
if (t == typeof(string)) return Convert.ChangeType(_value, t);
|
||||
|
||||
if (_type == ValueType.BOOLEAN)
|
||||
{
|
||||
if (t == typeof(bool)) return Convert.ChangeType(_value, t);
|
||||
}
|
||||
else if (_type == ValueType.DOUBLE)
|
||||
{
|
||||
if (t == typeof(double)) return Convert.ChangeType(_value, t, RealWorldTerrainCultureInfo.numberFormat);
|
||||
if (t == typeof(float)) return Convert.ChangeType((double) _value, t, RealWorldTerrainCultureInfo.numberFormat);
|
||||
}
|
||||
else if (_type == ValueType.LONG)
|
||||
{
|
||||
if (t == typeof(long)) return Convert.ChangeType(_value, t);
|
||||
#if UNITY_EDITOR
|
||||
if (t.IsSubclassOf(typeof(UnityEngine.Object)))
|
||||
{
|
||||
return UnityEditor.EditorUtility.InstanceIDToObject((int) (long) _value);
|
||||
}
|
||||
#endif
|
||||
|
||||
try
|
||||
{
|
||||
return Convert.ChangeType((long) _value, t);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.Log(e.Message + "\n" + e.StackTrace);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
else if (_type == ValueType.STRING)
|
||||
{
|
||||
MethodInfo method = RealWorldTerrainReflectionHelper.GetMethod(t, "Parse", new[] {typeof(string), typeof(IFormatProvider)});
|
||||
if (method != null) return method.Invoke(null, new object[] {value, RealWorldTerrainCultureInfo.numberFormat});
|
||||
|
||||
method = RealWorldTerrainReflectionHelper.GetMethod(t, "Parse", new[] {typeof(string)});
|
||||
return method.Invoke(null, new[] {value});
|
||||
}
|
||||
|
||||
StringBuilder builder = new StringBuilder();
|
||||
ToJSON(builder);
|
||||
throw new InvalidCastException(t.FullName + "\n" + builder);
|
||||
}
|
||||
|
||||
private void WriteString(StringBuilder b)
|
||||
{
|
||||
b.Append('\"');
|
||||
|
||||
string s = value as string;
|
||||
|
||||
int runIndex = -1;
|
||||
int l = s.Length;
|
||||
for (var index = 0; index < l; ++index)
|
||||
{
|
||||
var c = s[index];
|
||||
|
||||
if (c >= ' ' && c < 128 && c != '\"' && c != '\\')
|
||||
{
|
||||
if (runIndex == -1) runIndex = index;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (runIndex != -1)
|
||||
{
|
||||
b.Append(s, runIndex, index - runIndex);
|
||||
runIndex = -1;
|
||||
}
|
||||
|
||||
switch (c)
|
||||
{
|
||||
case '\t':
|
||||
b.Append("\\t");
|
||||
break;
|
||||
case '\r':
|
||||
b.Append("\\r");
|
||||
break;
|
||||
case '\n':
|
||||
b.Append("\\n");
|
||||
break;
|
||||
case '"':
|
||||
case '\\':
|
||||
b.Append('\\');
|
||||
b.Append(c);
|
||||
break;
|
||||
default:
|
||||
b.Append("\\u");
|
||||
b.Append(((int) c).ToString("X4", NumberFormatInfo.InvariantInfo));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (runIndex != -1) b.Append(s, runIndex, s.Length - runIndex);
|
||||
b.Append('\"');
|
||||
}
|
||||
|
||||
public static implicit operator string(RealWorldTerrainJsonValue val)
|
||||
{
|
||||
return val.ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Type of value
|
||||
/// </summary>
|
||||
public enum ValueType
|
||||
{
|
||||
DOUBLE,
|
||||
LONG,
|
||||
STRING,
|
||||
BOOLEAN,
|
||||
NULL
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 978ceaf2c164ae545bfd24fb23c24135
|
||||
timeCreated: 1564669254
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user