using System; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using SUISS.Storage; namespace SUISSEngine { public abstract class StatefulSingleton : Singleton where T : StatefulSingleton, new() { protected StatefulSingleton() { this._storage = Storage.Get(this.GetLifecycle()); this.LoadState(); } public static FieldInfo GetFieldFromHandle(RuntimeFieldHandle handle) { return FieldInfo.GetFieldFromHandle(handle); } //[DebuggerBrowsable(DebuggerBrowsableState.Never)] public event StatefulSingleton.ValueChangedHandler ValueChangedEvent; //[DebuggerBrowsable(DebuggerBrowsableState.Never)] public event StatefulSingleton.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(); } } public 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; } } public virtual object GetValue(string key) { return this.GetValue(key, null); } 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); } } } public virtual bool ContainsValue(string key) { return this.Persistent.ContainsKey(key); } 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; } } protected abstract void OnNewGameState(); protected abstract string GetStorageKey(); protected abstract StorageLifecycle GetLifecycle(); 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 = StatefulSingleton.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 = StatefulSingleton.GetFieldFromHandle(handle); if (fieldsDictionary.ContainsKey(fieldFromHandle.Name)) { fieldFromHandle.SetValue(this, fieldsDictionary[fieldFromHandle.Name]); } } } } 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(); } }