using System; using System.Collections.Generic; using UniLinq; namespace KFCommonUtilityLib.Scripts.StaticManagers { public static class CustomEffectEnumManager { private static event Action OnInitDefault; private static event Action OnInitFinal; private static event Action OnPrintResult; //call this in InitMod public static void RegisterEnumType(bool requestMin = false, int requestedMin = 0, bool requestMax = false, int requestedMax = int.MaxValue) where T : struct, Enum { if (EnumHolder.Registered) return; EnumHolder.Registered = true; EnumHolder.RequestMinMax(requestMin, requestedMin, requestMax, requestedMax); OnInitDefault += EnumHolder.InitDefault; OnInitFinal += EnumHolder.InitFinal; OnPrintResult += EnumHolder.PrintResult; } //hooked to GameAwake public static void InitDefault() { OnInitDefault?.Invoke(); } //patched to GameManager.StartGame prefix public static void InitFinal() { OnInitFinal?.Invoke(); } public static void PrintResults() { OnPrintResult?.Invoke(); } //only call these from callbacks hooked to ModEvents.GameStartDone and cache the results for future usage //patched to PassiveEffect.ParsePassiveEffect and MinEventActionBase.ParseXmlAttribute public static T RegisterOrGetEnum(string name, bool ignoreCase = false) where T : struct, Enum { if (!EnumHolder.Registered) { throw new Exception($"Enum not registered: {typeof(T).Name}"); } return EnumHolder.RegisterOrGetEnum(name, ignoreCase); } //public static PassiveEffects RegisterOrGetPassive(string passive) //{ // if (!dict_final_passive.TryGetValue(passive, out var value)) // { // if (dict_final_passive.Count >= byte.MaxValue) // throw new OverflowException("Passive effect count exceeds limit 255!"); // value = (PassiveEffects)(byte)dict_final_passive.Count; // dict_final_passive.Add(passive, value); // } // return value; //} ////patched to MinEventActionBase.ParseXmlAttribute //public static MinEventTypes RegisterOrGetTrigger(string trigger) //{ // if (!dict_final_trigger.TryGetValue(trigger, out var value)) // { // value = (MinEventTypes)dict_final_trigger.Count; // dict_final_trigger.Add(trigger, value); // } // return value; //} private static class EnumHolder where T : struct, Enum { private static int max, min; private static readonly TypeCode typecode; private static readonly Dictionary dict_default_enums = new Dictionary(); private static readonly Dictionary dict_default_enums_lower = new Dictionary(); private static readonly LinkedList<(int start, int end)> link_default_holes = new LinkedList<(int start, int end)>(); private static Dictionary dict_final_enums = new Dictionary(); private static Dictionary dict_final_enums_lower = new Dictionary(); private static LinkedList<(int start, int end)> link_final_holes = new LinkedList<(int start, int end)>(); public static bool Registered { get; set; } = false; private static bool DefaultInited { get; set; } = false; static EnumHolder() { Type underlying = Enum.GetUnderlyingType(typeof(T)); typecode = Type.GetTypeCode(underlying); switch (typecode) { case TypeCode.Byte: min = 0; max = byte.MaxValue; break; case TypeCode.SByte: min = sbyte.MinValue; max = sbyte.MaxValue; break; case TypeCode.Int16: min = short.MinValue; max = short.MaxValue; break; case TypeCode.UInt16: min = 0; max = ushort.MaxValue; break; case TypeCode.Int32: case TypeCode.Int64: min = int.MinValue; max = int.MaxValue; break; case TypeCode.UInt32: case TypeCode.UInt64: min = 0; max = int.MaxValue; break; default: throw new Exception($"Invalid underlying type for enum {typeof(T).Name}"); } } public static void RequestMinMax(bool requestMin, int requestedMin, bool requestMax, int requestedMax) { if (requestMin && requestedMin >= min) { min = requestedMin; } if (requestMax && requestedMax <= max) { max = requestedMax; } } public static void InitDefault() { if (DefaultInited) return; dict_default_enums.Clear(); dict_default_enums_lower.Clear(); link_default_holes.Clear(); var total = Enum.GetNames(typeof(T)).Length; var enums = Enum.GetValues(typeof(T)).Cast().ToArray(); for (int i = 0; i < total; i++) { string name = enums[i].ToString(); dict_default_enums.Add(name, enums[i]); dict_default_enums_lower.Add(name.ToLower(), enums[i]); } var values = enums.Select(e => Convert.ToInt32(e)).OrderBy(i => i).ToArray(); int nextHole = min; foreach (var value in values) { if (nextHole < value) { link_default_holes.AddLast((nextHole, Math.Min(value - 1, max))); if (value >= max) { nextHole = max; break; } nextHole = value + 1; } else if (nextHole == value) { if (value >= max) { break; } nextHole++; } } if (nextHole <= max && values[values.Length - 1] < max) { link_default_holes.AddLast((nextHole, max)); } DefaultInited = true; } public static void InitFinal() { dict_final_enums = new Dictionary(dict_default_enums); dict_final_enums_lower = new Dictionary(dict_default_enums_lower); link_final_holes = new LinkedList<(int start, int end)>(link_default_holes); } public static void PrintResult() { //Log.Out($"{typeof(T).Name}:\n" + string.Join("\n", dict_final_enums.Select(p => $"name: {p.Key} value: {p.Value}"))); } public static T RegisterOrGetEnum(string passive, bool ignoreCase = false) { if (!(ignoreCase ? dict_final_enums_lower : dict_final_enums).TryGetValue(ignoreCase ? passive.ToLower() : passive, out var value)) { if (link_final_holes.Count == 0) throw new OverflowException($"Enum count exceeds limit {max}!"); (int start, int end) = link_final_holes.First.Value; link_final_holes.RemoveFirst(); value = (T)Enum.ToObject(typeof(T), Convert.ChangeType(start, typecode)); dict_final_enums.Add(passive, value); dict_final_enums_lower.Add(passive.ToLower(), value); if (start < end) { start++; link_final_holes.AddFirst((start, end)); } } return value; } } } }