diff --git a/Editor.meta b/Editor.meta new file mode 100644 index 0000000..fb8960f --- /dev/null +++ b/Editor.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 2864f01274562f64a8b5baf512b13147 +folderAsset: yes +timeCreated: 1429820089 +licenseType: Pro +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Prefabs.meta b/Prefabs.meta new file mode 100644 index 0000000..aca5929 --- /dev/null +++ b/Prefabs.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 997e3bbddd101a04e823db6585b689f0 +folderAsset: yes +timeCreated: 1429820089 +licenseType: Pro +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/README.md.meta b/README.md.meta new file mode 100644 index 0000000..cedf215 --- /dev/null +++ b/README.md.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: e11fd8dc5ee36fe409b027877bd2dba3 +timeCreated: 1429820089 +licenseType: Pro +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Resources.meta b/Resources.meta new file mode 100644 index 0000000..5a1ca05 --- /dev/null +++ b/Resources.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: e400f648e7897744d9dfb9cf36273b65 +folderAsset: yes +timeCreated: 1429820089 +licenseType: Pro +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Source.meta b/Source.meta new file mode 100644 index 0000000..7ce52b2 --- /dev/null +++ b/Source.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 376a5756bcc7fdb4aa18c67756f87ee4 +folderAsset: yes +timeCreated: 1429820089 +licenseType: Pro +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Source/Game/GameEvent.cs b/Source/Game/GameEvent.cs index 310f959..5b6b243 100644 --- a/Source/Game/GameEvent.cs +++ b/Source/Game/GameEvent.cs @@ -1,8 +1,9 @@ using UnityEngine; using System.Collections.Generic; +using System.Linq; [System.Serializable] -public class GameEvent : ScriptableObject{ +public class GameEvent : ScriptableObject, JSONAble{ void Awake(){ if (args == null || args.Count != keys.Count) { @@ -33,11 +34,10 @@ public object getParameter(string param){ public void setParameter(string param, object content){ param = param.ToLower(); - object c = content; - if(c is System.ValueType || c is string){ - c = ScriptableObject.CreateInstance(); - ((IsoUnityBasicType)c).Value = content; - } + object c = IsoUnityTypeFactory.Instance.getIsoUnityType(content); + if (c == null) + c = content; + if(args.ContainsKey(param)) args[param] = (Object)c; else args.Add(param, (Object)c); @@ -47,8 +47,14 @@ public void setParameter(string param, object content){ public void removeParameter(string param){ param = param.ToLower(); - if(args.ContainsKey(param)) - args.Remove(param); + if (args.ContainsKey(param)) + { + UnityEngine.Object v = args[param]; + if (v is IsoUnityBasicType) + IsoUnityTypeFactory.Instance.Destroy(v as IsoUnityBasicType); + + args.Remove(param); + } this.keys = new List (args.Keys); this.values = new List (args.Values); @@ -106,5 +112,57 @@ public override int GetHashCode () { return !(ge1 == ge2); } + + + public JSONObject toJSONObject() + { + JSONObject json = new JSONObject(); + json.AddField("name", name); + JSONObject parameters = new JSONObject(); + foreach (KeyValuePair entry in args) + { + if (entry.Value is JSONAble) + { + var jsonAble = entry.Value as JSONAble; + parameters.AddField(entry.Key, JSONSerializer.Serialize(jsonAble)); + } + else + { + parameters.AddField(entry.Key, entry.Value.GetInstanceID()); + } + } + + + json.AddField("parameters", parameters); + return json; + } + + private static void destroyBasic(Dictionary args) + { + if (args == null || args.Count == 0) + return; + + foreach (KeyValuePair entry in args) + if (entry.Value is IsoUnityBasicType) + IsoUnityBasicType.DestroyImmediate(entry.Value); + } + + public void fromJSONObject(JSONObject json) + { + this.name = json["name"].ToString(); + + //Clean basic types + destroyBasic(this.args); + + this.args = new Dictionary(); + + JSONObject parameters = json["parameters"]; + foreach (string key in parameters.keys) + { + JSONObject param = parameters[key]; + JSONAble unserialized = JSONSerializer.UnSerialize(param); + this.setParameter(key, unserialized); + } + } } diff --git a/Source/Game/IsoUnityBasicType.cs b/Source/Game/IsoUnityBasicType.cs deleted file mode 100644 index 9e17204..0000000 --- a/Source/Game/IsoUnityBasicType.cs +++ /dev/null @@ -1,53 +0,0 @@ -using UnityEngine; -using System.Collections; - -[System.Serializable] -public class IsoUnityBasicType : ScriptableObject { - - public int i; - public float f; - public string s; - public Vector2 v2; - public Vector3 v3; - public Vector4 v4; - public Quaternion q; - public bool b; - public char c; - - public string whatIs; - public object Value { - get{ - object vt = null; - - if (whatIs == typeof(int).ToString()) {vt = i;} - else if(whatIs == typeof(float).ToString()) {vt = f;} - else if(whatIs == typeof(string).ToString()) {vt = s;} - else if(whatIs == typeof(Vector2).ToString()) {vt = v2;} - else if(whatIs == typeof(Vector3).ToString()) {vt = v3;} - else if(whatIs == typeof(Vector4).ToString()) {vt = v4;} - else if(whatIs == typeof(Quaternion).ToString()){vt = q;} - else if(whatIs == typeof(bool).ToString()) {vt = b;} - else if(whatIs == typeof(char).ToString()) {vt = c;} - - return vt; - } - set{ - object vt = value; - if(vt!=null){ - whatIs = vt.GetType().ToString(); - - if (vt.GetType() == typeof(int)) {i = (int)vt;} - else if(vt.GetType() == typeof(float)) {f = (float)vt;} - else if(vt.GetType() == typeof(string)) {s = (string)vt;} - else if(vt.GetType() == typeof(Vector2)) {v2 = (Vector2)vt;} - else if(vt.GetType() == typeof(Vector3)) {v3 = (Vector3)vt;} - else if(vt.GetType() == typeof(Vector4)) {v4 = (Vector4)vt;} - else if(vt.GetType() == typeof(Quaternion)) {q = (Quaternion)vt;} - else if(vt.GetType() == typeof(bool)) {b = (bool)vt;} - else if(vt.GetType() == typeof(char)) {c = (char)vt;} - else whatIs = null; - }else whatIs = null; - - } - } -} diff --git a/Source/Game/IsoUnityType.cs b/Source/Game/IsoUnityType.cs new file mode 100644 index 0000000..9cb4402 --- /dev/null +++ b/Source/Game/IsoUnityType.cs @@ -0,0 +1,16 @@ +using UnityEngine; +using System.Collections; + +public abstract class IsoUnityType : ScriptableObject, JSONAble +{ + public abstract bool canHandle(object o); + public abstract IsoUnityType clone(); + public abstract object Value + { + get; + set; + } + public abstract JSONObject toJSONObject(); + + public abstract void fromJSONObject(JSONObject json); +} diff --git a/Source/Game/IsoUnityType.cs.meta b/Source/Game/IsoUnityType.cs.meta new file mode 100644 index 0000000..4cd2778 --- /dev/null +++ b/Source/Game/IsoUnityType.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: be40efd5e8aa99b47afd89b0eca4dd33 +timeCreated: 1430061031 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Source/Game/IsoUnityTypeFactory.cs b/Source/Game/IsoUnityTypeFactory.cs new file mode 100644 index 0000000..e47d93b --- /dev/null +++ b/Source/Game/IsoUnityTypeFactory.cs @@ -0,0 +1,51 @@ +using UnityEngine; +using System.Collections.Generic; + +public abstract class IsoUnityTypeFactory +{ + private static IsoUnityTypeFactory instance; + public static IsoUnityTypeFactory Instance + { + get + { + if (instance == null) + instance = new IsoUnityTypeFactoryImp(); + return instance; + } + } + public abstract void Destroy(IsoUnityType i); + public abstract IsoUnityType getIsoUnityType(object c); + + private class IsoUnityTypeFactoryImp : IsoUnityTypeFactory + { + private List types; + + public IsoUnityTypeFactoryImp() + { + types = new List(); + types.Add(ScriptableObject.CreateInstance()); + types.Add(ScriptableObject.CreateInstance()); + } + + public override void Destroy(IsoUnityType i) + { + IsoUnityType.DestroyImmediate(i); + } + + public override IsoUnityType getIsoUnityType(object c) + { + IsoUnityType r = null; + foreach (IsoUnityType t in types) + { + if (t.canHandle(c)) + { + r = t.clone(); + r.Value = c; + break; + } + } + return r; + } + } + +} diff --git a/Source/Game/IsoUnityTypeFactory.cs.meta b/Source/Game/IsoUnityTypeFactory.cs.meta new file mode 100644 index 0000000..04f313e --- /dev/null +++ b/Source/Game/IsoUnityTypeFactory.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 564b3874aa6eff24b98e3d7af8382cbe +timeCreated: 1430062312 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Source/Game/IsoUnityTypes.meta b/Source/Game/IsoUnityTypes.meta new file mode 100644 index 0000000..e1fbdfa --- /dev/null +++ b/Source/Game/IsoUnityTypes.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 04f218d7e2e19d44bbf608d4f0fc93f1 +folderAsset: yes +timeCreated: 1430064348 +licenseType: Pro +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Source/Game/IsoUnityTypes/IsoUnityBasicType.cs b/Source/Game/IsoUnityTypes/IsoUnityBasicType.cs new file mode 100644 index 0000000..0318e5a --- /dev/null +++ b/Source/Game/IsoUnityTypes/IsoUnityBasicType.cs @@ -0,0 +1,120 @@ +using UnityEngine; +using System.Collections; + +[System.Serializable] +public class IsoUnityBasicType : IsoUnityType { + + public int i; + public float f; + public string s; + public Vector2 v2; + public Vector3 v3; + public Vector4 v4; + public Quaternion q; + public bool b; + public char c; + + public string whatIs; + + public override IsoUnityType clone() + { + return IsoUnityBasicType.CreateInstance(); + } + + public override bool canHandle(object o) + { + string[] types = new string[]{ + typeof(string).ToString(), + typeof(Vector2).ToString(), + typeof(Vector3).ToString(), + typeof(Vector4).ToString(), + typeof(Quaternion).ToString(), + typeof(int).ToString(), + typeof(float).ToString(), + typeof(bool).ToString(), + typeof(char).ToString() + }; + + var myType = o.GetType().ToString(); + + foreach (var type in types) + if (type == myType) + return true; + + return false; + } + + public override object Value { + get{ + object vt = null; + + if (whatIs == typeof(int).ToString()) {vt = i;} + else if(whatIs == typeof(float).ToString()) {vt = f;} + else if(whatIs == typeof(string).ToString()) {vt = s;} + else if(whatIs == typeof(Vector2).ToString()) {vt = v2;} + else if(whatIs == typeof(Vector3).ToString()) {vt = v3;} + else if(whatIs == typeof(Vector4).ToString()) {vt = v4;} + else if(whatIs == typeof(Quaternion).ToString()){vt = q;} + else if(whatIs == typeof(bool).ToString()) {vt = b;} + else if(whatIs == typeof(char).ToString()) {vt = c;} + + return vt; + } + set{ + object vt = value; + if(vt!=null){ + whatIs = vt.GetType().ToString(); + + if (vt.GetType() == typeof(int)) {i = (int)vt;} + else if(vt.GetType() == typeof(float)) {f = (float)vt;} + else if(vt.GetType() == typeof(string)) {s = (string)vt;} + else if(vt.GetType() == typeof(Vector2)) {v2 = (Vector2)vt;} + else if(vt.GetType() == typeof(Vector3)) {v3 = (Vector3)vt;} + else if(vt.GetType() == typeof(Vector4)) {v4 = (Vector4)vt;} + else if(vt.GetType() == typeof(Quaternion)) {q = (Quaternion)vt;} + else if(vt.GetType() == typeof(bool)) {b = (bool)vt;} + else if(vt.GetType() == typeof(char)) {c = (char)vt;} + else whatIs = null; + }else whatIs = null; + + } + } + + public override JSONObject toJSONObject() + { + + JSONObject o = null; + if (whatIs == typeof(int).ToString()) { o = new JSONObject(i); } + else if (whatIs == typeof(float).ToString()) { o = new JSONObject(f); } + else if (whatIs == typeof(string).ToString()) { o = JSONObject.CreateStringObject(s); } + else if (whatIs == typeof(Vector2).ToString()) { o = JSONObject.CreateStringObject(v2.ToString()); } + else if (whatIs == typeof(Vector3).ToString()) { o = JSONObject.CreateStringObject(v3.ToString()); } + else if (whatIs == typeof(Vector4).ToString()) { o = JSONObject.CreateStringObject(v4.ToString()); } + else if (whatIs == typeof(Quaternion).ToString()) { o = JSONObject.CreateStringObject(q.ToString()); } + else if (whatIs == typeof(bool).ToString()) { o = new JSONObject(b); } + else if (whatIs == typeof(char).ToString()) { o = new JSONObject(c); } + return o; + } + + public override void fromJSONObject(JSONObject json) + { + if (json.IsString) + { + object vq = null;// VectorUtil.getVQ(param.str); + if (vq == null) + Value = json.str; + else Value = vq; + } + else if (json.IsBool) + { + Value = json.b; + } + else if (json.IsNumber) + { + int i = Mathf.RoundToInt(json.n); + if (json.n == i) Value = i; + else Value = json.n; + } + } + +} diff --git a/Source/Game/IsoUnityTypes/IsoUnityBasicType.cs.meta b/Source/Game/IsoUnityTypes/IsoUnityBasicType.cs.meta new file mode 100644 index 0000000..e1f8b64 --- /dev/null +++ b/Source/Game/IsoUnityTypes/IsoUnityBasicType.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 8daaa0a8c5652f247939f4ab49339994 +timeCreated: 1430062617 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Source/Game/IsoUnityTypes/IsoUnityCollectionType.cs b/Source/Game/IsoUnityTypes/IsoUnityCollectionType.cs new file mode 100644 index 0000000..6ff38f1 --- /dev/null +++ b/Source/Game/IsoUnityTypes/IsoUnityCollectionType.cs @@ -0,0 +1,76 @@ +using UnityEngine; +using System.Collections; +using System.Collections.Generic; + +public class IsoUnityCollectionType : IsoUnityType +{ + [SerializeField] + private IsoUnityList l; + [SerializeField] + private string whatIs = ""; + + public override IsoUnityType clone() + { + return IsoUnityCollectionType.CreateInstance(); + } + + public override bool canHandle(object o) + { + return o is IList; + } + + public override object Value + { + get + { + if (whatIs == l.GetType().ToString()) return l; + + return null; + } + set + { + if (value is IList) { + var lo = value as IList; + if (lo is IsoUnityList) + { + l = lo as IsoUnityList; + } + else + { + var myList = IsoUnityList.CreateInstance(); + foreach (var o in lo) + myList.Add(o); + l = myList; + } + whatIs = l.GetType().ToString(); + } + } + } + + public override void fromJSONObject(JSONObject json) + { + List ljo = json.list; + if (this.l == null) + this.l = ScriptableObject.CreateInstance(); + else + this.l.Clear(); + foreach (var jo in ljo) + { + JSONAble unserialized = JSONSerializer.UnSerialize(jo); + this.l.Add(unserialized); + } + } + + public override JSONObject toJSONObject() + { + JSONObject[] array = new JSONObject[l.Count]; + int i = 0; + foreach (var o in this.l.getSerializable()) + { + array[i] = JSONSerializer.Serialize(o); + i++; + } + return new JSONObject(array); + } + +} diff --git a/Source/Game/IsoUnityTypes/IsoUnityCollectionType.cs.meta b/Source/Game/IsoUnityTypes/IsoUnityCollectionType.cs.meta new file mode 100644 index 0000000..63b60f3 --- /dev/null +++ b/Source/Game/IsoUnityTypes/IsoUnityCollectionType.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: a534316d35d1fd8498c57ae1a14c90e4 +timeCreated: 1430062617 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Source/Game/IsoUnityTypes/IsoUnityList.cs b/Source/Game/IsoUnityTypes/IsoUnityList.cs new file mode 100644 index 0000000..b9eb947 --- /dev/null +++ b/Source/Game/IsoUnityTypes/IsoUnityList.cs @@ -0,0 +1,203 @@ +using UnityEngine; +using System.Collections.Generic; + +public class IsoUnityList : ScriptableObject, IList { + + [SerializeField] + private List listaIsometrica; + + void OnEnable() + { + Debug.Log("Lista creada"); + this.listaIsometrica = new List(); + } + + void OnDestroy() + { + Debug.Log("Lista Destruida"); + this.Clear(); + } + + public List getSerializable() + { + return listaIsometrica; + } + + private static Object getObjectIn(object o, List listaIsometrica) + { + foreach(var i in listaIsometrica) + if (i is IsoUnityBasicType) + { + var b = i as IsoUnityBasicType; + if (o == b.Value) + return i; + } + else + { + if (o == i) + return i; + } + + return null; + } + + private static Object getObjectFor(object o) + { + if (o == null) + return null; + + Object uo = null; + + if (o is Object) + { + uo = o as Object; + } + else + { + uo = IsoUnityTypeFactory.Instance.getIsoUnityType(o); + } + return uo; + } + + private static object getSystemObjectFor(Object o) + { + object so = null; + if (o is IsoUnityType) + { + so = (o as IsoUnityType).Value; + } + else + { + so = o; + } + + return so; + } + + public int IndexOf(object item) + { + return listaIsometrica.IndexOf(getObjectIn(item, listaIsometrica)); + } + + public void Insert(int index, object item) + { + if (listaIsometrica[index] is IsoUnityType) + { + IsoUnityTypeFactory.Instance.Destroy(listaIsometrica[index] as IsoUnityType); + } + + listaIsometrica.Insert(index, getObjectFor(item)); + } + + public void RemoveAt(int index) + { + if (listaIsometrica[index] is IsoUnityType) + { + IsoUnityTypeFactory.Instance.Destroy(listaIsometrica[index] as IsoUnityType); + } + + listaIsometrica.RemoveAt(index); + } + + public object this[int index] + { + get + { + return getSystemObjectFor(listaIsometrica[index]); + } + set + { + this.Insert(index, value); + } + } + + public System.Collections.IEnumerator GetEnumerator() + { + return myEnumerator(); + } + + public void Add(object item) + { + this.listaIsometrica.Add(getObjectFor(item)); + } + + public void Clear() + { + for (int i = listaIsometrica.Count - 1; i >= 0; i--) + { + this.RemoveAt(i); + } + } + + public bool Contains(object item) + { + return this.listaIsometrica.Contains(getObjectIn(item, listaIsometrica)); + } + + public void CopyTo(object[] array, int arrayIndex) + { + if (arrayIndex != this.Count) + return; + + int i = 0; + foreach (var o in this) + { + array[i] = o; i++; + } + } + + public int Count + { + get { return listaIsometrica.Count; } + } + + public bool IsReadOnly + { + get { return false; } + } + + public bool Remove(object item) + { + return this.listaIsometrica.Remove(getObjectIn(item, listaIsometrica)); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return myEnumerator(); + } + + private IEnumerator myEnumerator() + { + return new MyEnumerator(listaIsometrica); + } + + private class MyEnumerator : IEnumerator + { + private IEnumerator OEnumerator; + public MyEnumerator(List lista) + { + OEnumerator = lista.GetEnumerator(); + } + + public object Current + { + get { return IsoUnityList.getSystemObjectFor(OEnumerator.Current); } + } + + + public bool MoveNext() + { + return OEnumerator.MoveNext(); + } + + public void Reset() + { + OEnumerator.Reset(); + } + + public void Dispose() + { + OEnumerator.Dispose(); + } + } +} diff --git a/Source/Game/IsoUnityTypes/IsoUnityList.cs.meta b/Source/Game/IsoUnityTypes/IsoUnityList.cs.meta new file mode 100644 index 0000000..d527fab --- /dev/null +++ b/Source/Game/IsoUnityTypes/IsoUnityList.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: fb99f2d02fb28d748a7dd7928514add9 +timeCreated: 1430152906 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Source/Map/Cell.cs b/Source/Map/Cell.cs index 9db6819..958694d 100644 --- a/Source/Map/Cell.cs +++ b/Source/Map/Cell.cs @@ -224,6 +224,7 @@ private void regenerateMesh(){ myMat.SetTexture("_MainTex", MeshFactory.Instance.getTexture2D()); this.GetComponent().sharedMaterial = myMat; this.GetComponent().sharedMesh = MeshFactory.Instance.getMesh(); + UnityEditor.EditorUtility.SetDirty(this); } diff --git a/Source/Util.meta b/Source/Util.meta new file mode 100644 index 0000000..dab425a --- /dev/null +++ b/Source/Util.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 7a147c7b764a23c4e8d021ccdd92a18c +folderAsset: yes +timeCreated: 1430064700 +licenseType: Pro +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Source/Util/JSONObject.meta b/Source/Util/JSONObject.meta new file mode 100644 index 0000000..e48871d --- /dev/null +++ b/Source/Util/JSONObject.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: c1f2170fd83a97340876c0d67de95372 +folderAsset: yes +timeCreated: 1430064700 +licenseType: Pro +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Source/Util/JSONObject/Editor.meta b/Source/Util/JSONObject/Editor.meta new file mode 100644 index 0000000..e7ab5f5 --- /dev/null +++ b/Source/Util/JSONObject/Editor.meta @@ -0,0 +1,5 @@ +fileFormatVersion: 2 +guid: 6b700d54458b2824c934e039a95c468c +folderAsset: yes +DefaultImporter: + userData: diff --git a/Source/Util/JSONObject/Editor/JSONChecker.cs b/Source/Util/JSONObject/Editor/JSONChecker.cs new file mode 100644 index 0000000..dd4098c --- /dev/null +++ b/Source/Util/JSONObject/Editor/JSONChecker.cs @@ -0,0 +1,49 @@ +//#define PERFTEST //For testing performance of parse/stringify. Turn on editor profiling to see how we're doing + +using UnityEngine; +using UnityEditor; + +public class JSONChecker : EditorWindow { + string JSON = @"{ + ""TestObject"": { + ""SomeText"": ""Blah"", + ""SomeObject"": { + ""SomeNumber"": 42, + ""SomeBool"": true, + ""SomeNull"": null + }, + ""SomeEmptyObject"": { }, + ""SomeEmptyArray"": [ ] + } +}"; + JSONObject j; + [MenuItem("Window/JSONChecker")] + static void Init() { + GetWindow(typeof(JSONChecker)); + } + void OnGUI() { + JSON = EditorGUILayout.TextArea(JSON); + GUI.enabled = !string.IsNullOrEmpty(JSON); + if(GUILayout.Button("Check JSON")) { +#if PERFTEST + Profiler.BeginSample("JSONParse"); + j = JSONObject.Create(JSON); + Profiler.EndSample(); + Profiler.BeginSample("JSONStringify"); + j.ToString(true); + Profiler.EndSample(); +#else + j = JSONObject.Create(JSON); +#endif + Debug.Log(j.ToString(true)); + } + if(j) { + //Debug.Log(System.GC.GetTotalMemory(false) + ""); + if(j.type == JSONObject.Type.NULL) + GUILayout.Label("JSON fail:\n" + j.ToString(true)); + else + GUILayout.Label("JSON success:\n" + j.ToString(true)); + + } + } +} diff --git a/Source/Game/IsoUnityBasicType.cs.meta b/Source/Util/JSONObject/Editor/JSONChecker.cs.meta similarity index 78% rename from Source/Game/IsoUnityBasicType.cs.meta rename to Source/Util/JSONObject/Editor/JSONChecker.cs.meta index daa50ce..e8cfa10 100644 --- a/Source/Game/IsoUnityBasicType.cs.meta +++ b/Source/Util/JSONObject/Editor/JSONChecker.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 06022059f6cbf9146a17ef0eada6d616 +guid: 6c5a625d29393ed4da8d9150a629fb35 MonoImporter: serializedVersion: 2 defaultReferences: [] diff --git a/Source/Util/JSONObject/JSONAble.cs b/Source/Util/JSONObject/JSONAble.cs new file mode 100644 index 0000000..2644aca --- /dev/null +++ b/Source/Util/JSONObject/JSONAble.cs @@ -0,0 +1,8 @@ +using UnityEngine; +using System.Collections; + +public interface JSONAble +{ + JSONObject toJSONObject(); + void fromJSONObject(JSONObject json); +} diff --git a/Source/Util/JSONObject/JSONAble.cs.meta b/Source/Util/JSONObject/JSONAble.cs.meta new file mode 100644 index 0000000..6706545 --- /dev/null +++ b/Source/Util/JSONObject/JSONAble.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 63388742a7784ef4ea357b91dccfd0c9 +timeCreated: 1430065834 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Source/Util/JSONObject/JSONObject.cs b/Source/Util/JSONObject/JSONObject.cs new file mode 100644 index 0000000..4dc07ab --- /dev/null +++ b/Source/Util/JSONObject/JSONObject.cs @@ -0,0 +1,966 @@ +#define PRETTY //Comment out when you no longer need to read JSON to disable pretty Print system-wide +//Using doubles will cause errors in VectorTemplates.cs; Unity speaks floats +#define USEFLOAT //Use floats for numbers instead of doubles (enable if you're getting too many significant digits in string output) +//#define POOLING //Currently using a build setting for this one (also it's experimental) + +using System.Diagnostics; +using UnityEngine; +using System.Collections; +using System.Collections.Generic; +using System.Text; +using Debug = UnityEngine.Debug; + +/* + * http://www.opensource.org/licenses/lgpl-2.1.php + * JSONObject class + * for use with Unity + * Copyright Matt Schoen 2010 - 2013 + */ + +public class JSONObject { +#if POOLING + const int MAX_POOL_SIZE = 10000; + public static Queue releaseQueue = new Queue(); +#endif + + const int MAX_DEPTH = 100; + const string INFINITY = "\"INFINITY\""; + const string NEGINFINITY = "\"NEGINFINITY\""; + const string NaN = "\"NaN\""; + static readonly char[] WHITESPACE = new[] { ' ', '\r', '\n', '\t' }; + public enum Type { NULL, STRING, NUMBER, OBJECT, ARRAY, BOOL, BAKED } + public bool isContainer { get { return (type == Type.ARRAY || type == Type.OBJECT); } } + public Type type = Type.NULL; + public int Count { + get { + if(list == null) + return -1; + return list.Count; + } + } + public List list; + public List keys; + public string str; +#if USEFLOAT + public float n; + public float f { + get { + return n; + } + } +#else + public double n; + public float f { + get { + return (float)n; + } + } +#endif + public bool b; + public delegate void AddJSONConents(JSONObject self); + + public static JSONObject nullJO { get { return Create(Type.NULL); } } //an empty, null object + public static JSONObject obj { get { return Create(Type.OBJECT); } } //an empty object + public static JSONObject arr { get { return Create(Type.ARRAY); } } //an empty array + + public JSONObject(Type t) { + type = t; + switch(t) { + case Type.ARRAY: + list = new List(); + break; + case Type.OBJECT: + list = new List(); + keys = new List(); + break; + } + } + public JSONObject(bool b) { + type = Type.BOOL; + this.b = b; + } +#if USEFLOAT + public JSONObject(float f) { + type = Type.NUMBER; + n = f; + } +#else + public JSONObject(double d) { + type = Type.NUMBER; + n = d; + } +#endif + public JSONObject(Dictionary dic) { + type = Type.OBJECT; + keys = new List(); + list = new List(); + //Not sure if it's worth removing the foreach here + foreach(KeyValuePair kvp in dic) { + keys.Add(kvp.Key); + list.Add(CreateStringObject(kvp.Value)); + } + } + public JSONObject(Dictionary dic) { + type = Type.OBJECT; + keys = new List(); + list = new List(); + //Not sure if it's worth removing the foreach here + foreach(KeyValuePair kvp in dic) { + keys.Add(kvp.Key); + list.Add(kvp.Value); + } + } + public JSONObject(AddJSONConents content) { + content.Invoke(this); + } + public JSONObject(JSONObject[] objs) { + type = Type.ARRAY; + list = new List(objs); + } + //Convenience function for creating a JSONObject containing a string. This is not part of the constructor so that malformed JSON data doesn't just turn into a string object + public static JSONObject StringObject(string val) { return CreateStringObject(val); } + public void Absorb(JSONObject obj) { + list.AddRange(obj.list); + keys.AddRange(obj.keys); + str = obj.str; + n = obj.n; + b = obj.b; + type = obj.type; + } + public static JSONObject Create() { +#if POOLING + JSONObject result = null; + while(result == null && releaseQueue.Count > 0) { + result = releaseQueue.Dequeue(); +#if DEV + //The following cases should NEVER HAPPEN (but they do...) + if(result == null) + Debug.Log("wtf " + releaseQueue.Count); + else if(result.list != null) + Debug.Log("wtflist " + result.list.Count); +#endif + } + if(result != null) + return result; +#endif + return new JSONObject(); + } + public static JSONObject Create(Type t) { + JSONObject obj = Create(); + obj.type = t; + switch(t) { + case Type.ARRAY: + obj.list = new List(); + break; + case Type.OBJECT: + obj.list = new List(); + obj.keys = new List(); + break; + } + return obj; + } + public static JSONObject Create(bool val) { + JSONObject obj = Create(); + obj.type = Type.BOOL; + obj.b = val; + return obj; + } + public static JSONObject Create(float val) { + JSONObject obj = Create(); + obj.type = Type.NUMBER; + obj.n = val; + return obj; + } + public static JSONObject Create(int val) { + JSONObject obj = Create(); + obj.type = Type.NUMBER; + obj.n = val; + return obj; + } + public static JSONObject CreateStringObject(string val) { + JSONObject obj = Create(); + obj.type = Type.STRING; + obj.str = val; + return obj; + } + public static JSONObject CreateBakedObject(string val) { + JSONObject bakedObject = Create(); + bakedObject.type = Type.BAKED; + bakedObject.str = val; + return bakedObject; + } + /// + /// Create a JSONObject by parsing string data + /// + /// The string to be parsed + /// The maximum depth for the parser to search. Set this to to 1 for the first level, + /// 2 for the first 2 levels, etc. It defaults to -2 because -1 is the depth value that is parsed (see below) + /// Whether to store levels beyond maxDepth in baked JSONObjects + /// Whether to be strict in the parsing. For example, non-strict parsing will successfully + /// parse "a string" into a string-type + /// + public static JSONObject Create(string val, int maxDepth = -2, bool storeExcessLevels = false, bool strict = false) { + JSONObject obj = Create(); + obj.Parse(val, maxDepth, storeExcessLevels, strict); + return obj; + } + public static JSONObject Create(AddJSONConents content) { + JSONObject obj = Create(); + content.Invoke(obj); + return obj; + } + public static JSONObject Create(Dictionary dic) { + JSONObject obj = Create(); + obj.type = Type.OBJECT; + obj.keys = new List(); + obj.list = new List(); + //Not sure if it's worth removing the foreach here + foreach(KeyValuePair kvp in dic) { + obj.keys.Add(kvp.Key); + obj.list.Add(CreateStringObject(kvp.Value)); + } + return obj; + } + public JSONObject() { } + #region PARSE + public JSONObject(string str, int maxDepth = -2, bool storeExcessLevels = false, bool strict = false) { //create a new JSONObject from a string (this will also create any children, and parse the whole string) + Parse(str, maxDepth, storeExcessLevels, strict); + } + void Parse(string str, int maxDepth = -2, bool storeExcessLevels = false, bool strict = false) { + if(!string.IsNullOrEmpty(str)) { + str = str.Trim(WHITESPACE); + if(strict) { + if(str[0] != '[' && str[0] != '{') { + type = Type.NULL; + Debug.LogWarning("Improper (strict) JSON formatting. First character must be [ or {"); + return; + } + } + if(str.Length > 0) { + if(string.Compare(str, "true", true) == 0) { + type = Type.BOOL; + b = true; + } else if(string.Compare(str, "false", true) == 0) { + type = Type.BOOL; + b = false; + } else if(string.Compare(str, "null", true) == 0) { + type = Type.NULL; +#if USEFLOAT + } else if(str == INFINITY) { + type = Type.NUMBER; + n = float.PositiveInfinity; + } else if(str == NEGINFINITY) { + type = Type.NUMBER; + n = float.NegativeInfinity; + } else if(str == NaN) { + type = Type.NUMBER; + n = float.NaN; +#else + } else if(str == INFINITY) { + type = Type.NUMBER; + n = double.PositiveInfinity; + } else if(str == NEGINFINITY) { + type = Type.NUMBER; + n = double.NegativeInfinity; + } else if(str == NaN) { + type = Type.NUMBER; + n = double.NaN; +#endif + } else if(str[0] == '"') { + type = Type.STRING; + this.str = str.Substring(1, str.Length - 2); + } else { + int tokenTmp = 1; + /* + * Checking for the following formatting (www.json.org) + * object - {"field1":value,"field2":value} + * array - [value,value,value] + * value - string - "string" + * - number - 0.0 + * - bool - true -or- false + * - null - null + */ + int offset = 0; + switch(str[offset]) { + case '{': + type = Type.OBJECT; + keys = new List(); + list = new List(); + break; + case '[': + type = Type.ARRAY; + list = new List(); + break; + default: + try { +#if USEFLOAT + n = System.Convert.ToSingle(str); +#else + n = System.Convert.ToDouble(str); +#endif + type = Type.NUMBER; + } catch(System.FormatException) { + type = Type.NULL; + Debug.LogWarning("improper JSON formatting:" + str); + } + return; + } + string propName = ""; + bool openQuote = false; + bool inProp = false; + int depth = 0; + while(++offset < str.Length) { + if(System.Array.IndexOf(WHITESPACE, str[offset]) > -1) + continue; + if(str[offset] == '\\') + offset += 2; + if(str[offset] == '"') { + if(openQuote) { + if(!inProp && depth == 0 && type == Type.OBJECT) + propName = str.Substring(tokenTmp + 1, offset - tokenTmp - 1); + openQuote = false; + } else { + if(depth == 0 && type == Type.OBJECT) + tokenTmp = offset; + openQuote = true; + } + } + if(openQuote) + continue; + if(type == Type.OBJECT && depth == 0) { + if(str[offset] == ':') { + tokenTmp = offset + 1; + inProp = true; + } + } + + if(str[offset] == '[' || str[offset] == '{') { + depth++; + } else if(str[offset] == ']' || str[offset] == '}') { + depth--; + } + //if (encounter a ',' at top level) || a closing ]/} + if((str[offset] == ',' && depth == 0) || depth < 0) { + inProp = false; + string inner = str.Substring(tokenTmp, offset - tokenTmp).Trim(WHITESPACE); + if(inner.Length > 0) { + if(type == Type.OBJECT) + keys.Add(propName); + if(maxDepth != -1) //maxDepth of -1 is the end of the line + list.Add(Create(inner, (maxDepth < -1) ? -2 : maxDepth - 1)); + else if(storeExcessLevels) + list.Add(CreateBakedObject(inner)); + + } + tokenTmp = offset + 1; + } + } + } + } else type = Type.NULL; + } else type = Type.NULL; //If the string is missing, this is a null + //Profiler.EndSample(); + } + #endregion + public bool IsNumber { get { return type == Type.NUMBER; } } + public bool IsNull { get { return type == Type.NULL; } } + public bool IsString { get { return type == Type.STRING; } } + public bool IsBool { get { return type == Type.BOOL; } } + public bool IsArray { get { return type == Type.ARRAY; } } + public bool IsObject { get { return type == Type.OBJECT; } } + public void Add(bool val) { + Add(Create(val)); + } + public void Add(float val) { + Add(Create(val)); + } + public void Add(int val) { + Add(Create(val)); + } + public void Add(string str) { + Add(CreateStringObject(str)); + } + public void Add(AddJSONConents content) { + Add(Create(content)); + } + public void Add(JSONObject obj) { + if(obj) { //Don't do anything if the object is null + if(type != Type.ARRAY) { + type = Type.ARRAY; //Congratulations, son, you're an ARRAY now + if(list == null) + list = new List(); + } + list.Add(obj); + } + } + public void AddField(string name, bool val) { + AddField(name, Create(val)); + } + public void AddField(string name, float val) { + AddField(name, Create(val)); + } + public void AddField(string name, int val) { + AddField(name, Create(val)); + } + public void AddField(string name, AddJSONConents content) { + AddField(name, Create(content)); + } + public void AddField(string name, string val) { + AddField(name, CreateStringObject(val)); + } + public void AddField(string name, JSONObject obj) { + if(obj) { //Don't do anything if the object is null + if(type != Type.OBJECT) { + if(keys == null) + keys = new List(); + if(type == Type.ARRAY) { + for(int i = 0; i < list.Count; i++) + keys.Add(i + ""); + } else + if(list == null) + list = new List(); + type = Type.OBJECT; //Congratulations, son, you're an OBJECT now + } + keys.Add(name); + list.Add(obj); + } + } + public void SetField(string name, bool val) { SetField(name, Create(val)); } + public void SetField(string name, float val) { SetField(name, Create(val)); } + public void SetField(string name, int val) { SetField(name, Create(val)); } + public void SetField(string name, JSONObject obj) { + if(HasField(name)) { + list.Remove(this[name]); + keys.Remove(name); + } + AddField(name, obj); + } + public void RemoveField(string name) { + if(keys.IndexOf(name) > -1) { + list.RemoveAt(keys.IndexOf(name)); + keys.Remove(name); + } + } + public delegate void FieldNotFound(string name); + public delegate void GetFieldResponse(JSONObject obj); + public void GetField(ref bool field, string name, FieldNotFound fail = null) { + if(type == Type.OBJECT) { + int index = keys.IndexOf(name); + if(index >= 0) { + field = list[index].b; + return; + } + } + if(fail != null) fail.Invoke(name); + } +#if USEFLOAT + public void GetField(ref float field, string name, FieldNotFound fail = null) { +#else + public void GetField(ref double field, string name, FieldNotFound fail = null) { +#endif + if(type == Type.OBJECT) { + int index = keys.IndexOf(name); + if(index >= 0) { + field = list[index].n; + return; + } + } + if(fail != null) fail.Invoke(name); + } + public void GetField(ref int field, string name, FieldNotFound fail = null) { + if(type == Type.OBJECT) { + int index = keys.IndexOf(name); + if(index >= 0) { + field = (int)list[index].n; + return; + } + } + if(fail != null) fail.Invoke(name); + } + public void GetField(ref uint field, string name, FieldNotFound fail = null) { + if(type == Type.OBJECT) { + int index = keys.IndexOf(name); + if(index >= 0) { + field = (uint)list[index].n; + return; + } + } + if(fail != null) fail.Invoke(name); + } + public void GetField(ref string field, string name, FieldNotFound fail = null) { + if(type == Type.OBJECT) { + int index = keys.IndexOf(name); + if(index >= 0) { + field = list[index].str; + return; + } + } + if(fail != null) fail.Invoke(name); + } + public void GetField(string name, GetFieldResponse response, FieldNotFound fail = null) { + if(response != null && type == Type.OBJECT) { + int index = keys.IndexOf(name); + if(index >= 0) { + response.Invoke(list[index]); + return; + } + } + if(fail != null) fail.Invoke(name); + } + public JSONObject GetField(string name) { + if(type == Type.OBJECT) + for(int i = 0; i < keys.Count; i++) + if(keys[i] == name) + return list[i]; + return null; + } + public bool HasFields(string[] names) { + for(int i = 0; i < names.Length; i++) + if(!keys.Contains(names[i])) + return false; + return true; + } + public bool HasField(string name) { + if(type == Type.OBJECT) + for(int i = 0; i < keys.Count; i++) + if(keys[i] == name) + return true; + return false; + } + public void Clear() { + type = Type.NULL; + if(list != null) + list.Clear(); + if(keys != null) + keys.Clear(); + str = ""; + n = 0; + b = false; + } + /// + /// Copy a JSONObject. This could probably work better + /// + /// + public JSONObject Copy() { + return Create(Print()); + } + /* + * The Merge function is experimental. Use at your own risk. + */ + public void Merge(JSONObject obj) { + MergeRecur(this, obj); + } + /// + /// Merge object right into left recursively + /// + /// The left (base) object + /// The right (new) object + static void MergeRecur(JSONObject left, JSONObject right) { + if(left.type == Type.NULL) + left.Absorb(right); + else if(left.type == Type.OBJECT && right.type == Type.OBJECT) { + for(int i = 0; i < right.list.Count; i++) { + string key = right.keys[i]; + if(right[i].isContainer) { + if(left.HasField(key)) + MergeRecur(left[key], right[i]); + else + left.AddField(key, right[i]); + } else { + if(left.HasField(key)) + left.SetField(key, right[i]); + else + left.AddField(key, right[i]); + } + } + } else if(left.type == Type.ARRAY && right.type == Type.ARRAY) { + if(right.Count > left.Count) { + Debug.LogError("Cannot merge arrays when right object has more elements"); + return; + } + for(int i = 0; i < right.list.Count; i++) { + if(left[i].type == right[i].type) { //Only overwrite with the same type + if(left[i].isContainer) + MergeRecur(left[i], right[i]); + else { + left[i] = right[i]; + } + } + } + } + } + public void Bake() { + if(type != Type.BAKED) { + str = Print(); + type = Type.BAKED; + } + } + public IEnumerable BakeAsync() { + if(type != Type.BAKED) { + foreach(string s in PrintAsync()) { + if(s == null) + yield return s; + else { + str = s; + } + } + type = Type.BAKED; + } + } +#pragma warning disable 219 + public string Print(bool pretty = false) { + StringBuilder builder = new StringBuilder(); + Stringify(0, builder, pretty); + return builder.ToString(); + } + public IEnumerable PrintAsync(bool pretty = false) { + StringBuilder builder = new StringBuilder(); + printWatch.Reset(); + printWatch.Start(); + foreach(IEnumerable e in StringifyAsync(0, builder, pretty)) { + yield return null; + } + yield return builder.ToString(); + } +#pragma warning restore 219 + #region STRINGIFY + const float maxFrameTime = 0.008f; + static readonly Stopwatch printWatch = new Stopwatch(); + IEnumerable StringifyAsync(int depth, StringBuilder builder, bool pretty = false) { //Convert the JSONObject into a string + //Profiler.BeginSample("JSONprint"); + if(depth++ > MAX_DEPTH) { + Debug.Log("reached max depth!"); + yield break; + } + if(printWatch.Elapsed.TotalSeconds > maxFrameTime) { + printWatch.Reset(); + yield return null; + printWatch.Start(); + } + switch(type) { + case Type.BAKED: + builder.Append(str); + break; + case Type.STRING: + builder.AppendFormat("\"{0}\"", str); + break; + case Type.NUMBER: +#if USEFLOAT + if(float.IsInfinity(n)) + builder.Append(INFINITY); + else if(float.IsNegativeInfinity(n)) + builder.Append(NEGINFINITY); + else if(float.IsNaN(n)) + builder.Append(NaN); +#else + if(double.IsInfinity(n)) + builder.Append(INFINITY); + else if(double.IsNegativeInfinity(n)) + builder.Append(NEGINFINITY); + else if(double.IsNaN(n)) + builder.Append(NaN); +#endif + else + builder.Append(n.ToString()); + break; + case Type.OBJECT: + builder.Append("{"); + if(list.Count > 0) { +#if(PRETTY) //for a bit more readability, comment the define above to disable system-wide + if(pretty) + builder.Append("\n"); +#endif + for(int i = 0; i < list.Count; i++) { + string key = keys[i]; + JSONObject obj = list[i]; + if(obj) { +#if(PRETTY) + if(pretty) + for(int j = 0; j < depth; j++) + builder.Append("\t"); //for a bit more readability +#endif + builder.AppendFormat("\"{0}\":", key); + foreach(IEnumerable e in obj.StringifyAsync(depth, builder, pretty)) + yield return e; + builder.Append(","); +#if(PRETTY) + if(pretty) + builder.Append("\n"); +#endif + } + } +#if(PRETTY) + if(pretty) + builder.Length -= 2; + else +#endif + builder.Length--; + } +#if(PRETTY) + if(pretty && list.Count > 0) { + builder.Append("\n"); + for(int j = 0; j < depth - 1; j++) + builder.Append("\t"); //for a bit more readability + } +#endif + builder.Append("}"); + break; + case Type.ARRAY: + builder.Append("["); + if(list.Count > 0) { +#if(PRETTY) + if(pretty) + builder.Append("\n"); //for a bit more readability +#endif + for(int i = 0; i < list.Count; i++) { + if(list[i]) { +#if(PRETTY) + if(pretty) + for(int j = 0; j < depth; j++) + builder.Append("\t"); //for a bit more readability +#endif + foreach(IEnumerable e in list[i].StringifyAsync(depth, builder, pretty)) + yield return e; + builder.Append(","); +#if(PRETTY) + if(pretty) + builder.Append("\n"); //for a bit more readability +#endif + } + } +#if(PRETTY) + if(pretty) + builder.Length -= 2; + else +#endif + builder.Length--; + } +#if(PRETTY) + if(pretty && list.Count > 0) { + builder.Append("\n"); + for(int j = 0; j < depth - 1; j++) + builder.Append("\t"); //for a bit more readability + } +#endif + builder.Append("]"); + break; + case Type.BOOL: + if(b) + builder.Append("true"); + else + builder.Append("false"); + break; + case Type.NULL: + builder.Append("null"); + break; + } + //Profiler.EndSample(); + } + //TODO: Refactor Stringify functions to share core logic + /* + * I know, I know, this is really bad form. It turns out that there is a + * significant amount of garbage created when calling as a coroutine, so this + * method is duplicated. Hopefully there won't be too many future changes, but + * I would still like a more elegant way to optionaly yield + */ + void Stringify(int depth, StringBuilder builder, bool pretty = false) { //Convert the JSONObject into a string + //Profiler.BeginSample("JSONprint"); + if(depth++ > MAX_DEPTH) { + Debug.Log("reached max depth!"); + return; + } + switch(type) { + case Type.BAKED: + builder.Append(str); + break; + case Type.STRING: + builder.AppendFormat("\"{0}\"", str); + break; + case Type.NUMBER: +#if USEFLOAT + if(float.IsInfinity(n)) + builder.Append(INFINITY); + else if(float.IsNegativeInfinity(n)) + builder.Append(NEGINFINITY); + else if(float.IsNaN(n)) + builder.Append(NaN); +#else + if(double.IsInfinity(n)) + builder.Append(INFINITY); + else if(double.IsNegativeInfinity(n)) + builder.Append(NEGINFINITY); + else if(double.IsNaN(n)) + builder.Append(NaN); +#endif + else + builder.Append(n.ToString()); + break; + case Type.OBJECT: + builder.Append("{"); + if(list.Count > 0) { +#if(PRETTY) //for a bit more readability, comment the define above to disable system-wide + if(pretty) + builder.Append("\n"); +#endif + for(int i = 0; i < list.Count; i++) { + string key = keys[i]; + JSONObject obj = list[i]; + if(obj) { +#if(PRETTY) + if(pretty) + for(int j = 0; j < depth; j++) + builder.Append("\t"); //for a bit more readability +#endif + builder.AppendFormat("\"{0}\":", key); + obj.Stringify(depth, builder, pretty); + builder.Append(","); +#if(PRETTY) + if(pretty) + builder.Append("\n"); +#endif + } + } +#if(PRETTY) + if(pretty) + builder.Length -= 2; + else +#endif + builder.Length--; + } +#if(PRETTY) + if(pretty && list.Count > 0) { + builder.Append("\n"); + for(int j = 0; j < depth - 1; j++) + builder.Append("\t"); //for a bit more readability + } +#endif + builder.Append("}"); + break; + case Type.ARRAY: + builder.Append("["); + if(list.Count > 0) { +#if(PRETTY) + if(pretty) + builder.Append("\n"); //for a bit more readability +#endif + for(int i = 0; i < list.Count; i++) { + if(list[i]) { +#if(PRETTY) + if(pretty) + for(int j = 0; j < depth; j++) + builder.Append("\t"); //for a bit more readability +#endif + list[i].Stringify(depth, builder, pretty); + builder.Append(","); +#if(PRETTY) + if(pretty) + builder.Append("\n"); //for a bit more readability +#endif + } + } +#if(PRETTY) + if(pretty) + builder.Length -= 2; + else +#endif + builder.Length--; + } +#if(PRETTY) + if(pretty && list.Count > 0) { + builder.Append("\n"); + for(int j = 0; j < depth - 1; j++) + builder.Append("\t"); //for a bit more readability + } +#endif + builder.Append("]"); + break; + case Type.BOOL: + if(b) + builder.Append("true"); + else + builder.Append("false"); + break; + case Type.NULL: + builder.Append("null"); + break; + } + //Profiler.EndSample(); + } + #endregion + public static implicit operator WWWForm(JSONObject obj) { + WWWForm form = new WWWForm(); + for(int i = 0; i < obj.list.Count; i++) { + string key = i + ""; + if(obj.type == Type.OBJECT) + key = obj.keys[i]; + string val = obj.list[i].ToString(); + if(obj.list[i].type == Type.STRING) + val = val.Replace("\"", ""); + form.AddField(key, val); + } + return form; + } + public JSONObject this[int index] { + get { + if(list.Count > index) return list[index]; + return null; + } + set { + if(list.Count > index) + list[index] = value; + } + } + public JSONObject this[string index] { + get { + return GetField(index); + } + set { + SetField(index, value); + } + } + public override string ToString() { + return Print(); + } + public string ToString(bool pretty) { + return Print(pretty); + } + public Dictionary ToDictionary() { + if(type == Type.OBJECT) { + Dictionary result = new Dictionary(); + for(int i = 0; i < list.Count; i++) { + JSONObject val = list[i]; + switch(val.type) { + case Type.STRING: result.Add(keys[i], val.str); break; + case Type.NUMBER: result.Add(keys[i], val.n + ""); break; + case Type.BOOL: result.Add(keys[i], val.b + ""); break; + default: Debug.LogWarning("Omitting object: " + keys[i] + " in dictionary conversion"); break; + } + } + return result; + } + Debug.LogWarning("Tried to turn non-Object JSONObject into a dictionary"); + return null; + } + public static implicit operator bool(JSONObject o) { + return o != null; + } +#if POOLING + static bool pool = true; + public static void ClearPool() { + pool = false; + releaseQueue.Clear(); + pool = true; + } + + ~JSONObject() { + if(pool && releaseQueue.Count < MAX_POOL_SIZE) { + type = Type.NULL; + list = null; + keys = null; + str = ""; + n = 0; + b = false; + releaseQueue.Enqueue(this); + } + } +#endif +} \ No newline at end of file diff --git a/Source/Util/JSONObject/JSONObject.cs.meta b/Source/Util/JSONObject/JSONObject.cs.meta new file mode 100644 index 0000000..691a4aa --- /dev/null +++ b/Source/Util/JSONObject/JSONObject.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: f71819923b555d14ab64ae2044718de9 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Source/Util/JSONObject/JSONSerializer.cs b/Source/Util/JSONObject/JSONSerializer.cs new file mode 100644 index 0000000..107b5c2 --- /dev/null +++ b/Source/Util/JSONObject/JSONSerializer.cs @@ -0,0 +1,58 @@ +using UnityEngine; +using System; +using System.Collections; + +public class JSONSerializer { + + public static JSONObject Serialize(object jsonAble) + { + JSONObject json = new JSONObject(); + + if (jsonAble is IsoUnityType) + { + json = ((JSONAble)jsonAble).toJSONObject(); + } + else if(jsonAble is JSONAble) + { + json.AddField("_class", jsonAble.GetType().ToString()); + json.AddField("_data", ((JSONAble)jsonAble).toJSONObject()); + } + else if (jsonAble is UnityEngine.Object) + { + json = new JSONObject(((UnityEngine.Object)jsonAble).GetInstanceID()); + } + + return json; + } + + public static JSONAble UnSerialize(JSONObject jsonObject){ + JSONAble r = null; + + if (jsonObject.HasField("_class") && jsonObject.HasField("_data")) + { + string c = jsonObject.GetField("_class").str; + Type t = Type.GetType(c); + if (t.IsSubclassOf(typeof(JSONAble))) + { + if (t.IsSubclassOf(typeof(ScriptableObject))) + { + r = ScriptableObject.CreateInstance(t) as JSONAble; + r.fromJSONObject(jsonObject.GetField("_data")); + } + } + } + else if (jsonObject.IsArray) + { + r = ScriptableObject.CreateInstance(); + r.fromJSONObject(jsonObject); + } + else if (jsonObject.IsString || jsonObject.IsNumber || jsonObject.IsBool) + { + r = ScriptableObject.CreateInstance(); + r.fromJSONObject(jsonObject); + } + + return r; + } + +} diff --git a/Source/Util/JSONObject/JSONSerializer.cs.meta b/Source/Util/JSONObject/JSONSerializer.cs.meta new file mode 100644 index 0000000..c6184b2 --- /dev/null +++ b/Source/Util/JSONObject/JSONSerializer.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: ae39a32b7fc01574ea82dcb4ca0a8cd3 +timeCreated: 1430161708 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Source/Util/JSONObject/JSONTemplates.cs b/Source/Util/JSONObject/JSONTemplates.cs new file mode 100644 index 0000000..749107d --- /dev/null +++ b/Source/Util/JSONObject/JSONTemplates.cs @@ -0,0 +1,88 @@ +using UnityEngine; +using System.Collections.Generic; +using System.Reflection; + +/* + * http://www.opensource.org/licenses/lgpl-2.1.php + * JSONTemplates class + * for use with Unity + * Copyright Matt Schoen 2010 + */ + +public static partial class JSONTemplates { + static readonly HashSet touched = new HashSet(); + + public static JSONObject TOJSON(object obj) { //For a generic guess + if(touched.Add(obj)) { + JSONObject result = JSONObject.obj; + //Fields + FieldInfo[] fieldinfo = obj.GetType().GetFields(); + foreach(FieldInfo fi in fieldinfo) { + JSONObject val = JSONObject.nullJO; + if(!fi.GetValue(obj).Equals(null)) { + MethodInfo info = typeof(JSONTemplates).GetMethod("From" + fi.FieldType.Name); + if(info != null) { + object[] parms = new object[1]; + parms[0] = fi.GetValue(obj); + val = (JSONObject)info.Invoke(null, parms); + } else if(fi.FieldType == typeof(string)) + val = JSONObject.CreateStringObject(fi.GetValue(obj).ToString()); + else + val = JSONObject.Create(fi.GetValue(obj).ToString()); + } + if(val) { + if(val.type != JSONObject.Type.NULL) + result.AddField(fi.Name, val); + else Debug.LogWarning("Null for this non-null object, property " + fi.Name + " of class " + obj.GetType().Name + ". Object type is " + fi.FieldType.Name); + } + } + //Properties + PropertyInfo[] propertyInfo = obj.GetType().GetProperties(); + foreach(PropertyInfo pi in propertyInfo) { + //This section should mirror part of AssetFactory.AddScripts() + JSONObject val = JSONObject.nullJO; + if(!pi.GetValue(obj, null).Equals(null)) { + MethodInfo info = typeof(JSONTemplates).GetMethod("From" + pi.PropertyType.Name); + if(info != null) { + object[] parms = new object[1]; + parms[0] = pi.GetValue(obj, null); + val = (JSONObject)info.Invoke(null, parms); + } else if(pi.PropertyType == typeof(string)) + val = JSONObject.CreateStringObject(pi.GetValue(obj, null).ToString()); + else + val = JSONObject.Create(pi.GetValue(obj, null).ToString()); + } + if(val) { + if(val.type != JSONObject.Type.NULL) + result.AddField(pi.Name, val); + else Debug.LogWarning("Null for this non-null object, property " + pi.Name + " of class " + obj.GetType().Name + ". Object type is " + pi.PropertyType.Name); + } + } + return result; + } + Debug.LogWarning("trying to save the same data twice"); + return JSONObject.nullJO; + } +} + +/* + * Some helpful code templates for the JSON class + * + * LOOP THROUGH OBJECT +for(int i = 0; i < obj.Count; i++){ + if(obj.keys[i] != null){ + switch((string)obj.keys[i]){ + case "key1": + do stuff with (JSONObject)obj.list[i]; + break; + case "key2": + do stuff with (JSONObject)obj.list[i]; + break; + } + } +} + * + * LOOP THROUGH ARRAY +foreach(JSONObject ob in obj.list) + do stuff with ob; + */ diff --git a/Source/Util/JSONObject/JSONTemplates.cs.meta b/Source/Util/JSONObject/JSONTemplates.cs.meta new file mode 100644 index 0000000..7ed2549 --- /dev/null +++ b/Source/Util/JSONObject/JSONTemplates.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 3e45009f4fac2044ea997acbf31422ec +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Source/Util/JSONObject/VectorTemplates.cs b/Source/Util/JSONObject/VectorTemplates.cs new file mode 100644 index 0000000..f0c1328 --- /dev/null +++ b/Source/Util/JSONObject/VectorTemplates.cs @@ -0,0 +1,237 @@ +using UnityEngine; + +public static partial class JSONTemplates { + + /* + * Vector2 + */ + public static Vector2 ToVector2(JSONObject obj) { + float x = obj["x"] ? obj["x"].f : 0; + float y = obj["y"] ? obj["y"].f : 0; + return new Vector2(x, y); + } + public static JSONObject FromVector2(Vector2 v) { + JSONObject vdata = JSONObject.obj; + if(v.x != 0) vdata.AddField("x", v.x); + if(v.y != 0) vdata.AddField("y", v.y); + return vdata; + } + /* + * Vector3 + */ + public static JSONObject FromVector3(Vector3 v) { + JSONObject vdata = JSONObject.obj; + if(v.x != 0) vdata.AddField("x", v.x); + if(v.y != 0) vdata.AddField("y", v.y); + if(v.z != 0) vdata.AddField("z", v.z); + return vdata; + } + public static Vector3 ToVector3(JSONObject obj) { + float x = obj["x"] ? obj["x"].f : 0; + float y = obj["y"] ? obj["y"].f : 0; + float z = obj["z"] ? obj["z"].f : 0; + return new Vector3(x, y, z); + } + /* + * Vector4 + */ + public static JSONObject FromVector4(Vector4 v) { + JSONObject vdata = JSONObject.obj; + if(v.x != 0) vdata.AddField("x", v.x); + if(v.y != 0) vdata.AddField("y", v.y); + if(v.z != 0) vdata.AddField("z", v.z); + if(v.w != 0) vdata.AddField("w", v.w); + return vdata; + } + public static Vector4 ToVector4(JSONObject obj) { + float x = obj["x"] ? obj["x"].f : 0; + float y = obj["y"] ? obj["y"].f : 0; + float z = obj["z"] ? obj["z"].f : 0; + float w = obj["w"] ? obj["w"].f : 0; + return new Vector4(x, y, z, w); + } + /* + * Matrix4x4 + */ + public static JSONObject FromMatrix4x4(Matrix4x4 m) { + JSONObject mdata = JSONObject.obj; + if(m.m00 != 0) mdata.AddField("m00", m.m00); + if(m.m01 != 0) mdata.AddField("m01", m.m01); + if(m.m02 != 0) mdata.AddField("m02", m.m02); + if(m.m03 != 0) mdata.AddField("m03", m.m03); + if(m.m10 != 0) mdata.AddField("m10", m.m10); + if(m.m11 != 0) mdata.AddField("m11", m.m11); + if(m.m12 != 0) mdata.AddField("m12", m.m12); + if(m.m13 != 0) mdata.AddField("m13", m.m13); + if(m.m20 != 0) mdata.AddField("m20", m.m20); + if(m.m21 != 0) mdata.AddField("m21", m.m21); + if(m.m22 != 0) mdata.AddField("m22", m.m22); + if(m.m23 != 0) mdata.AddField("m23", m.m23); + if(m.m30 != 0) mdata.AddField("m30", m.m30); + if(m.m31 != 0) mdata.AddField("m31", m.m31); + if(m.m32 != 0) mdata.AddField("m32", m.m32); + if(m.m33 != 0) mdata.AddField("m33", m.m33); + return mdata; + } + public static Matrix4x4 ToMatrix4x4(JSONObject obj) { + Matrix4x4 result = new Matrix4x4(); + if(obj["m00"]) result.m00 = obj["m00"].f; + if(obj["m01"]) result.m01 = obj["m01"].f; + if(obj["m02"]) result.m02 = obj["m02"].f; + if(obj["m03"]) result.m03 = obj["m03"].f; + if(obj["m10"]) result.m10 = obj["m10"].f; + if(obj["m11"]) result.m11 = obj["m11"].f; + if(obj["m12"]) result.m12 = obj["m12"].f; + if(obj["m13"]) result.m13 = obj["m13"].f; + if(obj["m20"]) result.m20 = obj["m20"].f; + if(obj["m21"]) result.m21 = obj["m21"].f; + if(obj["m22"]) result.m22 = obj["m22"].f; + if(obj["m23"]) result.m23 = obj["m23"].f; + if(obj["m30"]) result.m30 = obj["m30"].f; + if(obj["m31"]) result.m31 = obj["m31"].f; + if(obj["m32"]) result.m32 = obj["m32"].f; + if(obj["m33"]) result.m33 = obj["m33"].f; + return result; + } + /* + * Quaternion + */ + public static JSONObject FromQuaternion(Quaternion q) { + JSONObject qdata = JSONObject.obj; + if(q.w != 0) qdata.AddField("w", q.w); + if(q.x != 0) qdata.AddField("x", q.x); + if(q.y != 0) qdata.AddField("y", q.y); + if(q.z != 0) qdata.AddField("z", q.z); + return qdata; + } + public static Quaternion ToQuaternion(JSONObject obj) { + float x = obj["x"] ? obj["x"].f : 0; + float y = obj["y"] ? obj["y"].f : 0; + float z = obj["z"] ? obj["z"].f : 0; + float w = obj["w"] ? obj["w"].f : 0; + return new Quaternion(x, y, z, w); + } + /* + * Color + */ + public static JSONObject FromColor(Color c) { + JSONObject cdata = JSONObject.obj; + if(c.r != 0) cdata.AddField("r", c.r); + if(c.g != 0) cdata.AddField("g", c.g); + if(c.b != 0) cdata.AddField("b", c.b); + if(c.a != 0) cdata.AddField("a", c.a); + return cdata; + } + public static Color ToColor(JSONObject obj) { + Color c = new Color(); + for(int i = 0; i < obj.Count; i++) { + switch(obj.keys[i]) { + case "r": c.r = obj[i].f; break; + case "g": c.g = obj[i].f; break; + case "b": c.b = obj[i].f; break; + case "a": c.a = obj[i].f; break; + } + } + return c; + } + /* + * Layer Mask + */ + public static JSONObject FromLayerMask(LayerMask l) { + JSONObject result = JSONObject.obj; + result.AddField("value", l.value); + return result; + } + public static LayerMask ToLayerMask(JSONObject obj) { + LayerMask l = new LayerMask {value = (int)obj["value"].n}; + return l; + } + public static JSONObject FromRect(Rect r) { + JSONObject result = JSONObject.obj; + if(r.x != 0) result.AddField("x", r.x); + if(r.y != 0) result.AddField("y", r.y); + if(r.height != 0) result.AddField("height", r.height); + if(r.width != 0) result.AddField("width", r.width); + return result; + } + public static Rect ToRect(JSONObject obj) { + Rect r = new Rect(); + for(int i = 0; i < obj.Count; i++) { + switch(obj.keys[i]) { + case "x": r.x = obj[i].f; break; + case "y": r.y = obj[i].f; break; + case "height": r.height = obj[i].f; break; + case "width": r.width = obj[i].f; break; + } + } + return r; + } + public static JSONObject FromRectOffset(RectOffset r) { + JSONObject result = JSONObject.obj; + if(r.bottom != 0) result.AddField("bottom", r.bottom); + if(r.left != 0) result.AddField("left", r.left); + if(r.right != 0) result.AddField("right", r.right); + if(r.top != 0) result.AddField("top", r.top); + return result; + } + public static RectOffset ToRectOffset(JSONObject obj) { + RectOffset r = new RectOffset(); + for(int i = 0; i < obj.Count; i++) { + switch(obj.keys[i]) { + case "bottom": r.bottom = (int)obj[i].n; break; + case "left": r.left = (int)obj[i].n; break; + case "right": r.right = (int)obj[i].n; break; + case "top": r.top = (int)obj[i].n; break; + } + } + return r; + } + + public static AnimationCurve ToAnimationCurve(JSONObject obj){ + AnimationCurve a = new AnimationCurve(); + if(obj.HasField("keys")){ + JSONObject keys = obj.GetField("keys"); + for(int i =0; i < keys.list.Count;i++){ + a.AddKey(ToKeyframe(keys[i])); + } + } + if(obj.HasField("preWrapMode")) + a.preWrapMode = (WrapMode)((int)obj.GetField("preWrapMode").n); + if(obj.HasField("postWrapMode")) + a.postWrapMode = (WrapMode)((int)obj.GetField("postWrapMode").n); + return a; + } + + public static JSONObject FromAnimationCurve(AnimationCurve a){ + JSONObject result = JSONObject.obj; + result.AddField("preWrapMode", a.preWrapMode.ToString()); + result.AddField("postWrapMode", a.postWrapMode.ToString()); + if(a.keys.Length > 0){ + JSONObject keysJSON = JSONObject.Create(); + for(int i =0; i < a.keys.Length;i++){ + keysJSON.Add(FromKeyframe(a.keys[i])); + } + result.AddField("keys", keysJSON); + } + return result; + } + + public static Keyframe ToKeyframe(JSONObject obj){ + Keyframe k = new Keyframe(obj.HasField("time")? obj.GetField("time").n : 0, obj.HasField("value")? obj.GetField("value").n : 0); + if(obj.HasField("inTangent")) k.inTangent = obj.GetField("inTangent").n; + if(obj.HasField("outTangent")) k.outTangent = obj.GetField("outTangent").n; + if(obj.HasField("tangentMode")) k.tangentMode = (int)obj.GetField("tangentMode").n; + + return k; + } + public static JSONObject FromKeyframe(Keyframe k){ + JSONObject result = JSONObject.obj; + if(k.inTangent != 0) result.AddField("inTangent", k.inTangent); + if(k.outTangent != 0) result.AddField("outTangent", k.outTangent); + if(k.tangentMode != 0) result.AddField("tangentMode", k.tangentMode); + if(k.time != 0) result.AddField("time", k.time); + if(k.value != 0) result.AddField("value", k.value); + return result; + } + +} diff --git a/Source/Util/JSONObject/VectorTemplates.cs.meta b/Source/Util/JSONObject/VectorTemplates.cs.meta new file mode 100644 index 0000000..ae84b17 --- /dev/null +++ b/Source/Util/JSONObject/VectorTemplates.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 886fb4d7a67d4ce4bb7f51bcc38e20c1 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Source/Util/JSONObject/readme.txt b/Source/Util/JSONObject/readme.txt new file mode 100644 index 0000000..a062c66 --- /dev/null +++ b/Source/Util/JSONObject/readme.txt @@ -0,0 +1,139 @@ +==Author== +[mailto:schoen@defectivestudios.com Matt Schoen] of [http://www.defectivestudios.com Defective Studios] + +==Download== +[[Media:JSONObject.zip|Download JSONObject.zip]] + += Intro = +I came across the need to send structured data to and from a server on one of my projects, and figured it would be worth my while to use JSON. When I looked into the issue, I tried a few of the C# implementations listed on [http://json.org json.org], but found them to be too complicated. So, I've written a very simple JSONObject class, which can be generically used to encode/decode data into a simple container. This page assumes that you know what JSON is, and how it works. It's rather simple, just go to json.org for a visual description of the encoding format. + +As an aside, this class is pretty central to the [[AssetCloud]] content management system, from Defective Studios. + +Update: The code has been updated to version 1.3 to incorporate user-submitted patches and bug reports. This fixes issues dealing with whitespace in the format, as well as empty arrays and objects. + += Usage = +Users should not have to modify the JSONObject class themselves, and must follow the very simple proceedures outlined below: + +Sample data (in JSON format): {"field1": 0.5,"field2": "sampletext","field3": [1,2,3]} + += Features = + +*Decode JSON-formatted strings into a usable data structure +*Encode structured data into a JSON-formatted string +*Interoperable with System.Collections.Generic.Dictionary +*Copy to new JSONObject +*Merge with another JSONObject (experimental) +*Random access (with [int] or [string]) +*ToString() returns JSON data with optional "pretty" flag to include newlines and tabs +*Switch between double and float for numeric storage depending on level of precision needed (and to ensure that numbers are parsed/stringified correctly) +*Supports Infinity and NaN values + +It should be pretty obvious what this parser can and cannot do. If anyone reading this is a JSON buff (is there such a thing?) please feel free to expand and modify the parser to be more compliant. Currently I am using the .NET System.Convert namespace functions for parsing the data itself. It parses strings and numbers, which was all that I needed of it, but unless the formatting is supported by System.Convert, it may not incorporate all proper JSON strings. Also, having never written a JSON parser before, I don't doubt that I could improve the efficiency or correctness of the parser. It serves my purpose, and hopefully will help you with your project! Let me know if you make any improvements :) + +== Encoding == + +Encoding is something of a hard-coded process. This is because I have no idea what your data is! It would be great if this were some sort of interface for taking an entire class and encoding it's number/string fields, but it's not. I've come up with a few clever ways of using loops and/or recursive methods to cut down of the amount of code I have to write when I use this tool, but they're pretty project-specific. + +Note: This section used to be WRONG! + + +//Note: your data can only be numbers and strings. This is not a solution for object serialization or anything like that. +JSONObject j = new JSONObject(JSONObject.Type.OBJECT); +//number +j.AddField("field1", 0.5); +//string +j.AddField("field2", "sampletext"); +//array +JSONObject arr = new JSONObject(JSONObject.Type.ARRAY); +j.AddField("field3", arr); + +arr.Add(1); +arr.Add(2); +arr.Add(3); + +string encodedString = j.print(); + + +NEW! The constructor, Add, and AddField functions now support a nested delegate structure. This is useful if you need to create a nested JSONObject in a single line. For example: + +DoRequest(URL, new JSONObject(delegate(JSONObject request) { + request.AddField("sort", delegate(JSONObject sort) { + sort.AddField("_timestamp", "desc"); + }); + request.AddField("query", new JSONObject(delegate(JSONObject query) { + query.AddField("match_all", JSONObject.obj); + })); + request.AddField("fields", delegate(JSONObject fields) { + fields.Add("_timestamp"); + }); +}).ToString()); + + +== Decoding == +Decoding is much simpler on the input end, and again, what you do with the JSONObject will vary on a per-project basis. One of the more complicated way to extract the data is with a recursive function, as drafted below. Calling the constructor with a properly formatted JSON string will return the root object (or array) containing all of its children, in one neat reference! The data is in a public ArrayList called list, with a matching key list (called keys!) if the root is an Object. If that's confusing, take a glance over the following code and the print() method in the JSONOBject class. If there is an error in the JSON formatting (or if there's an error with my code!) the debug console will read "improper JSON formatting". + + + +string encodedString = "{\"field1\": 0.5,\"field2\": \"sampletext\",\"field3\": [1,2,3]}"; +JSONObject j = new JSONObject(encodedString); +accessData(j); +//access data (and print it) +void accessData(JSONObject obj){ + switch(obj.type){ + case JSONObject.Type.OBJECT: + for(int i = 0; i < obj.list.Count; i++){ + string key = (string)obj.keys[i]; + JSONObject j = (JSONObject)obj.list[i]; + Debug.Log(key); + accessData(j); + } + break; + case JSONObject.Type.ARRAY: + foreach(JSONObject j in obj.list){ + accessData(j); + } + break; + case JSONObject.Type.STRING: + Debug.Log(obj.str); + break; + case JSONObject.Type.NUMBER: + Debug.Log(obj.n); + break; + case JSONObject.Type.BOOL: + Debug.Log(obj.b); + break; + case JSONObject.Type.NULL: + Debug.Log("NULL"); + break; + + } +} + + +NEW! Decoding now also supports a delegate format which will automatically check if a field exists before processing the data, providing an optional parameter for an OnFieldNotFound response. For example: + +new JSONObject(data); +list.GetField("hits", delegate(JSONObject hits) { + hits.GetField("hits", delegate(JSONObject hits2) { + foreach (JSONObject gameSession in hits2.list) { + Debug.Log(gameSession); + } + }); +}, delegate(string name) { //"name" will be equal to the name of the missing field. In this case, "hits" + Debug.LogWarning("no game sessions"); +}); + + +===New! (O(n)) Random access!=== +I've added a string and int [] index to the class, so you can now retrieve data as such (from above): + +JSONObject arr = obj["field3"]; +Debug.log(arr[2].n); //Should ouptut "3" + + +--Code omitted from readme-- + +[[Category:C Sharp]] +[[Category:Scripts]] +[[Category:Utility]] +[[Category:JSON]] diff --git a/Source/Util/JSONObject/readme.txt.meta b/Source/Util/JSONObject/readme.txt.meta new file mode 100644 index 0000000..86fe7ee --- /dev/null +++ b/Source/Util/JSONObject/readme.txt.meta @@ -0,0 +1,4 @@ +fileFormatVersion: 2 +guid: 80b692916bec1664098283aa4425e4d8 +TextScriptImporter: + userData: