using System; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using SUISS.Core; using SUISS.Storage; namespace SUISSEngine { public abstract class AbstractState : SingletonMonobehaviour where T : AbstractState { public static FieldInfo GetFieldFromHandle(RuntimeFieldHandle handle) { return FieldInfo.GetFieldFromHandle(handle); } //[DebuggerBrowsable(DebuggerBrowsableState.Never)] public event AbstractState.ValueChangedHandler ValueChangedEvent; //[DebuggerBrowsable(DebuggerBrowsableState.Never)] public event AbstractState.AnyValueChangedHandler AnyValueChangedEvent; public void FireValueChangedHandler(string key, object oldValue, object newValue) { if (this.ValueChangedEvent != null) { this.ValueChangedEvent(key, oldValue, newValue); } if (this.AnyValueChangedEvent != null) { this.AnyValueChangedEvent(); } } public void FireAnyValueChangedEvent() { if (this.AnyValueChangedEvent != null) { this.AnyValueChangedEvent(); } } protected Dictionary Persistent { get { if (this.persistentDictionary == null) { if (!this.persistent.ContainsKey("dictionary")) { this.persistent.Add("dictionary", new Dictionary()); } this.persistentDictionary = (Dictionary)this.persistent["dictionary"]; } return this.persistentDictionary; } } protected override void Awake() { base.Awake(); this.storage = Storage.Get(this.GetLifecycle()); this.loadState(); } protected virtual void Start() { } protected override void OnDestroy() { base.OnDestroy(); this.ValueChangedEvent = null; if (this.storage != null) { this.storage.OnSync -= this.syncToStorage; } } public virtual V GetValue(string key, V defaultvalue) { V result = defaultvalue; object obj; if (this.Persistent.TryGetValue(key, out obj) && obj is V) { result = (V)((object)obj); } return result; } public virtual object GetValue(string key, object defaultValue) { object result; if (!this.Persistent.TryGetValue(key, out result)) { result = defaultValue; } return result; } public virtual void SetValue(string key, object value) { if (this.isNewState) { this.Persistent[key] = value; } else { object obj; if (!this.Persistent.TryGetValue(key, out obj)) { obj = null; } if (!object.Equals(obj, value)) { this.Persistent[key] = value; this.OnValueChanged(key, obj, value); } } } protected virtual void OnValueChanged(string key, object oldValue, object newValue) { this.FireValueChangedHandler(key, oldValue, newValue); } private void loadState() { if (this.storage.Root.ContainsKey(this.GetStorageKey())) { this.persistent = (Dictionary)this.storage.Root[this.GetStorageKey()]; if (!this.persistent.ContainsKey("dictionary")) { this.persistent["dictionary"] = new Dictionary(); } this.persistentDictionary = (Dictionary)this.persistent["dictionary"]; if (!this.persistent.ContainsKey("fields")) { this.persistent["fields"] = new Dictionary(); } this.persistentFields = (Dictionary)this.persistent["fields"]; this.syncToFields(); this.storage.OnSync += this.syncToStorage; } else { this.persistent = new Dictionary(); this.persistentFields = new Dictionary(); this.persistent["fields"] = this.persistentFields; this.persistentDictionary = new Dictionary(); this.persistent["dictionary"] = this.persistentDictionary; this.storage.Root[this.GetStorageKey()] = this.persistent; this.storage.OnSync += this.syncToStorage; this.isNewState = true; this.OnNewGameState(); this.isNewState = false; } } private void reflectOnPersistentFields() { this.persistentFieldHandles = new List(); Type type = base.GetType(); FieldInfo[] fields = type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy); foreach (FieldInfo fieldInfo in fields) { if (fieldInfo.IsDefined(typeof(PersistentAttribute), false)) { this.persistentFieldHandles.Add(fieldInfo.GetFieldHandle()); } } } private Dictionary getFieldsDictionary() { if (this.persistentFields == null && !this.persistent.ContainsKey("fields")) { this.persistent.Add("fields", new Dictionary()); this.persistentFields = (Dictionary)this.persistent["fields"]; } return this.persistentFields; } private void syncToStorage() { if (this.persistentFieldHandles == null) { this.reflectOnPersistentFields(); } if (this.persistent != null) { Dictionary fieldsDictionary = this.getFieldsDictionary(); foreach (RuntimeFieldHandle handle in this.persistentFieldHandles) { FieldInfo fieldFromHandle = AbstractState.GetFieldFromHandle(handle); fieldsDictionary[fieldFromHandle.Name] = fieldFromHandle.GetValue(this); } } } private void syncToFields() { if (this.persistentFieldHandles == null) { this.reflectOnPersistentFields(); } if (this.persistent != null) { Dictionary fieldsDictionary = this.getFieldsDictionary(); foreach (RuntimeFieldHandle handle in this.persistentFieldHandles) { FieldInfo fieldFromHandle = AbstractState.GetFieldFromHandle(handle); if (fieldsDictionary.ContainsKey(fieldFromHandle.Name)) { fieldFromHandle.SetValue(this, fieldsDictionary[fieldFromHandle.Name]); } } } } protected abstract void OnNewGameState(); protected abstract string GetStorageKey(); protected abstract StorageLifecycle GetLifecycle(); private const string DictionaryKey = "dictionary"; private const string FieldsKey = "fields"; private Dictionary persistent; private Dictionary persistentDictionary; private Dictionary persistentFields; private List persistentFieldHandles; private Storage storage; protected bool isNewState; public delegate void ValueChangedHandler(string key, object oldValue, object newValue); public delegate void AnyValueChangedHandler(); } }