Decompiled source of ConfigurableCompany v3.7.0
Amrv.ConfigurableCompany.dll
Decompiled a month ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Drawing; using System.Globalization; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Serialization; using System.Runtime.Versioning; using System.Text; using Amrv.ConfigurableCompany.API; using Amrv.ConfigurableCompany.API.Accesors; using Amrv.ConfigurableCompany.API.ConfigTypes; using Amrv.ConfigurableCompany.API.Data; using Amrv.ConfigurableCompany.API.Display; using Amrv.ConfigurableCompany.API.Event; using Amrv.ConfigurableCompany.Core; using Amrv.ConfigurableCompany.Core.Config; using Amrv.ConfigurableCompany.Core.Dependency; using Amrv.ConfigurableCompany.Core.Display; using Amrv.ConfigurableCompany.Core.Display.ConfigTypes; using Amrv.ConfigurableCompany.Core.Display.Items; using Amrv.ConfigurableCompany.Core.Display.Menu; using Amrv.ConfigurableCompany.Core.Display.Scripts; using Amrv.ConfigurableCompany.Core.Extensions; using Amrv.ConfigurableCompany.Core.IO; using Amrv.ConfigurableCompany.Core.Net; using Amrv.ConfigurableCompany.Core.Patch; using Amrv.ConfigurableCompany.Plugin; using Amrv.ConfigurableCompany.Utils; using Amrv.ConfigurableCompany.Utils.IO; using Amrv.ConfigurableCompany.Utils.Unity; using Amrv.ConfigurableCompany.content.display; using Amrv.ConfigurableCompany.content.model; using Amrv.ConfigurableCompany.content.model.data; using Amrv.ConfigurableCompany.content.model.events; using Amrv.ConfigurableCompany.content.model.types; using BepInEx; using BepInEx.Configuration; using HarmonyLib; using Microsoft.CodeAnalysis; using TMPro; using Unity.Collections; using Unity.Netcode; using UnityEngine; using UnityEngine.EventSystems; using UnityEngine.Events; using UnityEngine.InputSystem; using UnityEngine.SceneManagement; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("AMRV")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyDescription("An api to allow developers to create configurable parameters for lethal company. These configurations can be modified in-game using a built in menu, persist during sesions and are save-dependant on each game file.")] [assembly: AssemblyFileVersion("3.7.0.0")] [assembly: AssemblyInformationalVersion("3.7.0+539fa0b903db614796175bc4cc1f7ce1c2770753")] [assembly: AssemblyProduct("Amrv.ConfigurableCompany")] [assembly: AssemblyTitle("Amrv.ConfigurableCompany")] [assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/TheAnsuz/Lethal-Company-Configurable-Company-API")] [assembly: AssemblyVersion("3.7.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class IsUnmanagedAttribute : Attribute { } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace Amrv.ConfigurableCompany { [Obsolete("Use CTypes")] public class ConfigurationTypes { public static readonly ConfigurationType String = new StringConfigurationType(); public static readonly ConfigurationType SmallString = new SmallStringConfigurationType(); public static readonly ConfigurationType Boolean = new BooleanConfigurationType(); public static readonly ConfigurationType Percent = new PercentConfigurationType(); public static readonly ConfigurationType Float = new FloatConfigurationType(); public static readonly ConfigurationType Integer = new IntegerConfigurationType(); public static ConfigurationType RangeInteger(int min, int max) { return new IntegerConfigurationType(min, max); } public static ConfigurationType RangeFloat(float min, float max) { return new FloatConfigurationType(min, max); } public static ConfigurationType Slider(float min, float max) { return new SliderConfigurationType(min, max); } public static ConfigurationType StringOfLength(int maxLength) { return new StringConfigurationType(maxLength); } public static ConfigurationType Options(Type enumeration) { return new EnumConfigurationType(enumeration); } public static ConfigurationType Options(params string[] options) { return new ListConfigurationType(options); } private ConfigurationTypes() { } } [Obsolete("Use CEvents")] public class Events { [Obsolete("Use CEvents.ConfigEvents.ChangeConfig")] public static EventType<ConfigurationChanged> ConfigurationChanged = new EventType<ConfigurationChanged>(); [Obsolete("Use CEvents.ConfigEvents.CreateConfig")] public static EventType<ConfigurationCreated> ConfigurationCreated = new EventType<ConfigurationCreated>(); [Obsolete("Use CEvents.LifecycleEvents.PluginStart")] public static EventType<EventArgs> PluginInitialized = new EventType<EventArgs>(); [Obsolete("Use CEvents.LifecycleEvents.PluginStart")] public static EventType<EventArgs> PluginSetup = new EventType<EventArgs>(); [Obsolete("Use CEvents.LifecycleEvents.PluginStart")] public static EventType<EventArgs> PluginEnabled = new EventType<EventArgs>(); [Obsolete("Use CEvents.MenuEvents.Create")] public static EventType<EventArgs> BeforeMenuDisplay = new EventType<EventArgs>(); [Obsolete("Use CEvents.MenuEvents.Prepare")] public static EventType<EventArgs> AfterMenuDisplay = new EventType<EventArgs>(); private Events() { } internal static void Start() { CEvents.ConfigEvents.ChangeConfig.AddListener(delegate(CEventChangeConfig e) { ChangeResult result = ((!e.Success) ? ChangeResult.FAILED : (e.Converted ? ChangeResult.SUCCESS_CONVERTED : ChangeResult.SUCCESS)); if (Configuration.TryGet(e.Config.ID, out var value2)) { ConfigurationChanged.Invoke(new ConfigurationChanged(value2, e.OldValue, e.NewValue, e.Reason.OldReason(), result)); } }); CEvents.ConfigEvents.CreateConfig.AddListener(delegate(CEventCreateConfig e) { if (Configuration.TryGet(e.Config.ID, out var value)) { ConfigurationCreated.Invoke(new ConfigurationCreated(value)); } }); CEvents.LifecycleEvents.PluginStart.AddListener(delegate { PluginSetup.Invoke(EventArgs.Empty); PluginInitialized.Invoke(EventArgs.Empty); PluginEnabled.Invoke(EventArgs.Empty); }); CEvents.MenuEvents.Create.AddListener(delegate { AfterMenuDisplay.Invoke(EventArgs.Empty); }); CEvents.MenuEvents.Prepare.AddListener(delegate { BeforeMenuDisplay.Invoke(EventArgs.Empty); }); } } [Obsolete("Use ConfigAPI")] public sealed class LethalConfiguration { private static readonly Dictionary<Assembly, ConfigurationPage> _defaultModPages = new Dictionary<Assembly, ConfigurationPage>(); private static readonly Dictionary<Assembly, ConfigurationCategory> _defaultModCategories = new Dictionary<Assembly, ConfigurationCategory>(); public const string PLUGIN_GUID = "dev.amrv.lethalCompany.config"; public const string PLUGIN_VERSION = "3.7.0"; public static ConfigurationCategory DefaultCategory => ConfigurationCategory.Default; public static ConfigurationPage DefaultPage => ConfigurationPage.Default; public static Dictionary<string, Configuration>.KeyCollection ConfigIDs => Configuration.Ids; public static Dictionary<string, Configuration>.ValueCollection Configs => Configuration.Configs; public static Dictionary<string, ConfigurationCategory>.KeyCollection CategoryIDs => ConfigurationCategory.Ids; public static Dictionary<string, ConfigurationCategory>.ValueCollection Categories => ConfigurationCategory.Categories; private LethalConfiguration() { } public static ConfigurationBuilder CreateConfig() { return new ConfigurationBuilder(); } public static ConfigurationBuilder CreateConfig(string id) { return new ConfigurationBuilder(id); } public static ConfigurationCategoryBuilder CreateCategory() { return new ConfigurationCategoryBuilder(); } public static ConfigurationCategoryBuilder CreateCategory(string id) { return new ConfigurationCategoryBuilder(id); } public static ConfigurationPageBuilder CreatePage() { return new ConfigurationPageBuilder(); } public static ConfigurationPage PageForMyMod(string name = null) { Assembly callingAssembly = Assembly.GetCallingAssembly(); if (!_defaultModPages.TryGetValue(callingAssembly, out var value)) { value = new ConfigurationPageBuilder { Name = (name ?? Assembly.GetCallingAssembly().GetName().Name) }.Build(); _defaultModPages.Add(callingAssembly, value); } return value; } public static ConfigurationCategory CategoryForMyMod(string name = "General") { Assembly callingAssembly = Assembly.GetCallingAssembly(); if (!_defaultModCategories.TryGetValue(callingAssembly, out var value)) { value = new ConfigurationCategoryBuilder().SetID(callingAssembly.GetName().Name.Replace(" ", "_").Replace(".", "-").ToLower()).SetName(name ?? Assembly.GetCallingAssembly().GetName().Name); _defaultModCategories.Add(callingAssembly, value); } return value; } public static bool TryGetConfig(string id, out Configuration config) { return Configuration.TryGet(id, out config); } public static bool TryGetCategory(string id, out ConfigurationCategory category) { return ConfigurationCategory.TryGet(id, out category); } } public static class PluginInfo { public const string PLUGIN_GUID = "Amrv.ConfigurableCompany"; public const string PLUGIN_NAME = "Amrv.ConfigurableCompany"; public const string PLUGIN_VERSION = "3.7.0"; } } namespace Amrv.ConfigurableCompany.Utils { public class IDGen { [CompilerGenerated] private int <Bytes>P; private readonly List<int> Hash; public IDGen(int Bytes) { <Bytes>P = Bytes; Hash = new List<int>(); base..ctor(); } public static string DeterministicString(object any) { throw new NotImplementedException(); } public static int DeterministicIntHash(string str) { int num = 0; byte[] bytes = Encoding.UTF8.GetBytes(str); byte[] array = new byte[4]; for (int i = 0; i < bytes.Length; i++) { array[i % array.Length] ^= (byte)(((bytes[i] << 7) ^ (bytes[i] >> 3)) | (bytes[i] << 5)); } for (int j = 0; j < array.Length; j++) { num = (num << 8) | array[j]; } return num; } public void AddDeterminant(string any) { Hash.Add(DeterministicIntHash(any)); } private byte[] GenerateID() { byte[] array = new byte[<Bytes>P]; byte[] array2 = new byte[<Bytes>P]; foreach (int item in Hash) { new Random(item).NextBytes(array2); for (int i = 0; i < array2.Length; i++) { array[i] |= array2[i]; } } return array; } public byte[] GetIDBytes() { return GenerateID(); } public string GetIDHex() { return BitConverter.ToString(GenerateID()); } public string GetIDBaseX(int @base) { throw new NotImplementedException(); } public string GetIDBaseX(params char[] notation) { throw new NotImplementedException(); } public string GetIDBase64() { return Convert.ToBase64String(GenerateID()); } } public static class NumberUtils { private static readonly HashSet<Type> DecimalTypes = new HashSet<Type> { typeof(double), typeof(float), typeof(decimal) }; private static readonly HashSet<Type> WholeNumberTypes = new HashSet<Type> { typeof(int), typeof(long), typeof(short), typeof(sbyte), typeof(byte), typeof(ulong), typeof(ushort), typeof(uint) }; private static readonly HashSet<Type> NumericTypes = new HashSet<Type> { typeof(int), typeof(double), typeof(decimal), typeof(long), typeof(short), typeof(sbyte), typeof(byte), typeof(ulong), typeof(ushort), typeof(uint), typeof(float) }; private const double THOUSAND = 1000.0; private const double MILLION = 1000000.0; private const double BILLION = 1000000000.0; private const double TRILLION = 1000000000000.0; private const double QUADRILLION = 1000000000000000.0; private const double QUINTILLION = 1E+18; private const double TOO_MUCH = 1E+21; public static bool IsWhole(object any) { return WholeNumberTypes.Contains(any.GetType()); } public static bool IsWhole(Type type) { return WholeNumberTypes.Contains(type); } public static bool IsWhole<T>() { return WholeNumberTypes.Contains(typeof(T)); } public static bool IsDecimal(object any) { return DecimalTypes.Contains(any.GetType()); } public static bool IsDecimal(Type type) { return DecimalTypes.Contains(type); } public static bool IsDecimal<T>() { return DecimalTypes.Contains(typeof(T)); } public static bool IsNumber(object any) { return NumericTypes.Contains(any.GetType()); } public static bool IsNumber(Type type) { return NumericTypes.Contains(type); } public static bool IsNumber<T>() { return NumericTypes.Contains(Nullable.GetUnderlyingType(typeof(T)) ?? typeof(T)); } public static string NumberWithSuffix(double num) { if (num == double.MinValue || num == double.NegativeInfinity) { return "-Infinite"; } if (num == double.MaxValue || num == double.PositiveInfinity) { return "Infinite"; } if (num == 0.0) { return "0"; } string text = ((num < 0.0) ? "-" : ""); num = Math.Abs(num); if (num > 1E+21) { return text + "Infinite"; } if (num > 1E+18) { return $"{text}{num / 1E+18:#.00}E"; } if (num > 1000000000000000.0) { return $"{text}{num / 1000000000000000.0:#.00}Q"; } if (num > 1000000000000.0) { return $"{text}{num / 1000000000000.0:#.00}T"; } if (num > 1000000000.0) { return $"{text}{num / 1000000000.0:#.00}B"; } if (num > 1000000.0) { return $"{text}{num / 1000000.0:#.00}M"; } if (num > 1000.0) { return $"{text}{num / 1000.0:#.00}K"; } return $"{text}{num:#}"; } public static string NumberWithSuffix(long num) { if (num == long.MinValue) { return "-Infinite"; } if (num == long.MaxValue) { return "Infinite"; } if (num == 0L) { return "0"; } string text = ((num < 0) ? "-" : ""); num = Math.Abs(num); if ((double)num > 1E+21) { return text + "Infinite"; } if ((double)num > 1E+18) { return $"{text}{(double)num / 1E+18:#}E"; } if ((double)num > 1000000000000000.0) { return $"{text}{(double)num / 1000000000000000.0:#}Q"; } if ((double)num > 1000000000000.0) { return $"{text}{(double)num / 1000000000000.0:#}T"; } if ((double)num > 1000000000.0) { return $"{text}{(double)num / 1000000000.0:#}B"; } if ((double)num > 1000000.0) { return $"{text}{(double)num / 1000000.0:#}M"; } if ((double)num > 1000.0) { return $"{text}{(double)num / 1000.0:#}K"; } return $"{text}{num:#}"; } } public class Reference<T> : IDisposable where T : class { private readonly object _lock = new object(); private T _value; public virtual bool IsAlive { get; private set; } = true; public virtual T Item { get { if (IsAlive) { return _value; } throw new NullReferenceException("Tried to get reference item after breaking it's bond"); } set { lock (_lock) { if (IsAlive && value == null) { Break(); } else { Bind(value); } } } } public Reference() { IsAlive = false; } public Reference(T item) { Item = item; } [Obsolete("Reference content may leak")] public static implicit operator T(Reference<T> reference) { return reference.Item; } public virtual void Break() { lock (_lock) { IsAlive = false; _value = null; } } public virtual void Bind(T item) { if (item == null) { Break(); return; } lock (_lock) { IsAlive = true; _value = item; } } public virtual void Dispose() { Break(); } ~Reference() { _value = null; } } } namespace Amrv.ConfigurableCompany.Utils.Unity { public class FastBundle : IDisposable { private readonly AssetBundle Bundle; private string path; public string Path { get { return path; } set { path = value.ToLower(); } } public FastBundle(AssetBundle bundle) { Bundle = bundle; path = ""; base..ctor(); } public void In(string segment) { path += segment.ToLower(); } public void OutAll() { path = string.Empty; } public void Out() { Out("/"); } public void Out(string segment) { int num = path.LastIndexOf(segment); if (num != -1) { path = path.Substring(0, num); } } [Obsolete("use GetAllAssetNames")] public string[] AllAssetNames() { return Bundle.AllAssetNames(); } public string[] GetAllAssetNames() { return Bundle.GetAllAssetNames(); } public string[] GetAllScenePaths() { return Bundle.GetAllScenePaths(); } public override bool Equals(object other) { return ((object)Bundle).Equals(other); } public bool Contains(string name) { return Bundle.Contains(name); } public override int GetHashCode() { return ((object)Bundle).GetHashCode(); } public IntPtr GetCachedPtr() { return ((Object)Bundle).GetCachedPtr(); } public int GetInstanceID() { return ((Object)Bundle).GetInstanceID(); } public override string ToString() { return ((object)Bundle).ToString(); } public void EnsureRunningOnMainThread() { ((Object)Bundle).EnsureRunningOnMainThread(); } public T[] LoadAllAssets<T>() where T : Object { return Bundle.LoadAllAssets<T>(); } public AssetBundleRequest LoadAllAssetsAsync<T>() where T : Object { return Bundle.LoadAllAssetsAsync<T>(); } public T LoadAsset<T>(string name) where T : Object { return Bundle.LoadAsset<T>(path + name); } public AssetBundleRequest LoadAssetAsync<T>(string name) where T : Object { return Bundle.LoadAssetAsync<T>(path + name.ToLower()); } public Object LoadAsset_Internal(string name, Type type) { return Bundle.LoadAsset_Internal(path + name.ToLower(), type); } public bool TryLoadAsset<T>(in string name, out T asset) where T : Object { asset = LoadAsset<T>(name); return (Object)(object)asset != (Object)null; } public T[] LoadAssetWithSubAssets<T>(string name) where T : Object { return Bundle.LoadAssetWithSubAssets<T>(path + name.ToLower()); } public AssetBundleRequest LoadAssetWithSubAssetsAsync<T>(string name) where T : Object { return Bundle.LoadAssetWithSubAssetsAsync<T>(path + name.ToLower()); } public bool LoadAssetWithSubAssets<T>(in string name, out T[] assets) where T : Object { assets = LoadAssetWithSubAssets<T>(name); if (assets != null) { return assets.Length != 0; } return false; } public void Unload(bool unloadAllLoadedObjects) { Bundle.Unload(unloadAllLoadedObjects); } public void UnloadAsync(bool unloadAllLoadedObjects) { Bundle.UnloadAsync(unloadAllLoadedObjects); } public void MarkDirty() { ((Object)Bundle).MarkDirty(); } public void Dispose() { Bundle.Unload(false); } } internal class UnityAsset { public static FastBundle GetBundle(string folder, string name) { return new FastBundle(AssetBundle.LoadFromFile(folder + name)); } public static T LoadAsset<T>(string folder, string name, string assetPath) where T : Object { AssetBundle val = AssetBundle.LoadFromFile(folder + name); if ((Object)(object)val == (Object)null) { return default(T); } T result = val.LoadAsset<T>(assetPath.ToLower()); val.UnloadAsync(false); return result; } public static T FindAsset<T>(string name) where T : Object { T[] array = Resources.FindObjectsOfTypeAll<T>(); if (array == null || array.Length == 0) { return default(T); } T[] array2 = array; foreach (T val in array2) { if (((Object)val).name.Contains(name)) { return val; } } return array[0]; } private UnityAsset() { } } public class UnityObject { private readonly GameObject _gameObject; public static UnityObject Create(string name, GameObject parent = null) { UnityObject unityObject = new UnityObject(name); if ((Object)(object)parent != (Object)null) { unityObject.SetParent(parent); } return unityObject; } private UnityObject(string name) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Expected O, but got Unknown _gameObject = new GameObject(name); } public UnityObject AddComponent<T>(bool dontAddIfExists = true) where T : Component { T component; return AddComponent<T>(out component, dontAddIfExists); } public UnityObject AddComponent<T>(out T component, bool dontAddIfExists = true) where T : Component { if (dontAddIfExists && _gameObject.TryGetComponent<T>(ref component)) { return this; } component = _gameObject.AddComponent<T>(); return this; } public UnityObject SetParent(GameObject parent, bool moveToParent = true) { _gameObject.transform.SetParent(parent.transform, !moveToParent); _gameObject.layer = parent.layer; return this; } public UnityObject SetParent(Transform parent, bool moveToParent = true) { _gameObject.transform.SetParent(parent, !moveToParent); return this; } public GameObject GetObject() { return _gameObject; } public static implicit operator GameObject(UnityObject obj) { return obj.GetObject(); } } } namespace Amrv.ConfigurableCompany.Utils.IO { public abstract class Bundle : IEnumerable { public abstract IEnumerable<string> Keys { get; } public abstract IEnumerable<string> Values { get; } public abstract int Count { get; } public string this[string key] { get { return Get(key, null); } set { Set(key, value); } } public abstract void Clear(); public abstract void Set(string key, string value); public abstract void Add(string key, string value); public abstract void Remove(string key); public abstract string Get(string key, string defaultValue); public abstract string Pack(); public abstract void Unpack(string data); public abstract bool Contains(string key); public abstract bool TryGet(string key, out string value); public abstract IEnumerator<KeyValuePair<string, string>> GetEnumerator(); IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } } public class CCATFile { public const int SIZE_KEY_ESTIMATE = 60; public const int SIZE_VALUE_ESTIMATE = 6; public const char TOKEN_VALUE_SEPARATOR = ':'; public const char TOKEN_DATA_SKIP = '\\'; public const char TOKEN_NEXT_ENTRY = '\n'; public const string STRING_VALUE_SEPARATOR = ":"; public const string STRING_DATA_SKIP = "\\"; public const string STRING_NEXT_ENTRY = "\n"; private readonly Dictionary<string, bool> _states = new Dictionary<string, bool>(); public readonly string File; public CCATFile(string filepath) { File = filepath; base..ctor(); } private static string MakeDataSafe(in string data) { StringBuilder stringBuilder = new StringBuilder(data); stringBuilder.Replace("\\", "\\\\"); stringBuilder.Replace(":", "\\:"); stringBuilder.Replace("\n", "\\\n"); return stringBuilder.ToString(); } private static string RevertDataSafe(in string data) { StringBuilder stringBuilder = new StringBuilder(data); stringBuilder.Replace("\\:", ":"); stringBuilder.Replace("\\\n", "\n"); stringBuilder.Replace("\\\\", "\\"); return stringBuilder.ToString(); } public bool TryGetState(string name, out bool state) { return _states.TryGetValue(name, out state); } public void SetState(string name, bool state) { _states[name] = state; } public void RemoveState(string name) { _states.Remove(name); } public IReadOnlyDictionary<string, bool> States() { return _states; } public void Read() { if (!System.IO.File.Exists(File)) { return; } string text = System.IO.File.ReadAllText(File); _states.Clear(); int startIndex = 0; bool flag = false; for (int i = 0; i < text.Length; i++) { if (flag) { flag = false; continue; } switch (text[i]) { case '\\': flag = true; break; case '\n': ReadSingleEntry(text, startIndex, i); startIndex = i + 1; break; } } } private void ReadSingleEntry(string content, int startIndex, int endIndex) { bool flag = false; for (int i = startIndex; i < endIndex; i++) { if (flag) { flag = false; } else if (content[i] == '\\') { flag = true; } else if (content[i] == ':') { int num = startIndex; string data = content.Substring(num, i - num); num = i + 1; string text = content.Substring(num, endIndex - num); SetState(RevertDataSafe(in data), text.Equals("true")); break; } } } public void Write() { StringBuilder stringBuilder = new StringBuilder(60 + 6 * _states.Count); foreach (KeyValuePair<string, bool> state in _states) { string data = state.Key; stringBuilder.Append(MakeDataSafe(in data)).Append(':').Append(state.Value.ToString().ToLower()) .Append('\n'); } System.IO.File.WriteAllText(File, stringBuilder.ToString()); } } public class CCFGFile { public class CCFGEntry { public readonly Dictionary<string, string> Metadata = new Dictionary<string, string>(); public string Value; public string this[string meta] { get { return Metadata[meta]; } set { Metadata[meta] = value; } } } public const int META_CAPACITY_ESTIMATE = 15; public const int ENTRY_CAPACITY_ESTIMATE = 90; public const char TOKEN_ENTRY_START = '['; public const char TOKEN_ENTRY_END = ']'; public const char TOKEN_META_SEPARATOR = '|'; public const char TOKEN_VALUE_SEPARATOR = ':'; public const char TOKEN_DATA_SKIP = '\\'; public const string STRING_ENTRY_START = "["; public const string STRING_ENTRY_END = "]"; public const string STRING_META_SEPARATOR = "|"; public const string STRING_VALUE_SEPARATOR = ":"; public const string STRING_DATA_SKIP = "\\"; private readonly Dictionary<string, string> _meta = new Dictionary<string, string>(); private readonly Dictionary<string, CCFGEntry> _entries = new Dictionary<string, CCFGEntry>(); public readonly string File; public CCFGFile(string file) { File = file; base..ctor(); } private static string MakeDataSafe(in string data) { StringBuilder stringBuilder = new StringBuilder(data); stringBuilder.Replace("\\", "\\\\"); stringBuilder.Replace("[", "\\["); stringBuilder.Replace("]", "\\]"); stringBuilder.Replace("|", "\\|"); stringBuilder.Replace(":", "\\:"); return stringBuilder.ToString(); } private static string RevertDataSafe(in string data) { StringBuilder stringBuilder = new StringBuilder(data); stringBuilder.Replace("\\[", "["); stringBuilder.Replace("\\]", "]"); stringBuilder.Replace("\\|", "|"); stringBuilder.Replace("\\:", ":"); stringBuilder.Replace("\\\\", "\\"); return stringBuilder.ToString(); } public void AddMetadata(string name, string value) { _meta[name] = value; } public void RemoveMetadata(string name) { _meta.Remove(name); } public bool TryGetMetadata(string name, out string value) { return _meta.TryGetValue(name, out value); } public IReadOnlyDictionary<string, string> Metadata() { return _meta; } public void ClearMetadata() { _meta.Clear(); } public CCFGEntry AddEntry(string name, string value, Dictionary<string, string> meta = null) { if (TryGetEntry(name, out var entry)) { entry.Value = value; entry.Metadata.Clear(); if (meta != null) { foreach (KeyValuePair<string, string> metum in meta) { entry[metum.Key] = metum.Value; } } } else { entry = new CCFGEntry { Value = value }; _entries[name] = entry; if (meta != null) { foreach (KeyValuePair<string, string> metum2 in meta) { entry[metum2.Key] = metum2.Value; } } } return entry; } public void RemoveEntry(string name) { _entries.Remove(name); } public bool TryGetEntry(string name, out CCFGEntry entry) { return _entries.TryGetValue(name, out entry); } public IReadOnlyDictionary<string, CCFGEntry> Entries() { return _entries; } public void Read() { if (System.IO.File.Exists(File)) { string content = System.IO.File.ReadAllText(File); _meta.Clear(); _entries.Clear(); ReadEntries(content); } } public void Write() { int num = 15 * _meta.Count; int num2 = 90 * _entries.Count; StringBuilder stringBuilder = new StringBuilder(num + num2); stringBuilder.Append('['); foreach (KeyValuePair<string, string> metum in _meta) { stringBuilder.Append('|'); string data = metum.Key; StringBuilder stringBuilder2 = stringBuilder.Append(MakeDataSafe(in data)).Append(':'); string data2 = metum.Value; stringBuilder2.Append(MakeDataSafe(in data2)); } stringBuilder.Append(']'); stringBuilder.Append(Environment.NewLine); foreach (KeyValuePair<string, CCFGEntry> entry in _entries) { StringBuilder stringBuilder3 = stringBuilder.Append('['); string data = entry.Key; stringBuilder3.Append(MakeDataSafe(in data)).Append(':').Append(MakeDataSafe(in entry.Value.Value)); foreach (KeyValuePair<string, string> metadatum in entry.Value.Metadata) { stringBuilder.Append('|'); data = metadatum.Key; StringBuilder stringBuilder4 = stringBuilder.Append(MakeDataSafe(in data)).Append(':'); string data2 = metadatum.Value; stringBuilder4.Append(MakeDataSafe(in data2)); } stringBuilder.Append(']'); stringBuilder.Append(Environment.NewLine); } if (!Directory.Exists(Path.GetDirectoryName(File))) { Directory.CreateDirectory(Path.GetDirectoryName(File)); } System.IO.File.WriteAllText(File, stringBuilder.ToString()); } private void ReadEntries(string content) { bool flag = false; for (int i = 0; i < content.Length; i++) { if (flag) { flag = false; } else if (content[i] == '\\') { flag = true; } else if (content[i] == '[') { ReadSingleEntry(content, in i, out i); } } } private void ReadSingleEntry(string content, in int index, out int endIndex) { int num = index + 1; int num2 = -1; int num3 = -1; bool flag = false; bool flag2 = false; bool flag3 = false; string text = null; endIndex = index; for (int i = index; i < content.Length; i++) { if (flag3) { flag3 = false; continue; } switch (content[i]) { case '\\': flag3 = true; break; case '|': if (flag2) { int num4 = num; string data3 = content.Substring(num4, num2 - num4); num4 = num3; string data4 = content.Substring(num4, i - num4); if (flag) { CCFGEntry entry2; if (text == null) { AddMetadata(RevertDataSafe(in data3), RevertDataSafe(in data4)); } else if (TryGetEntry(text, out entry2)) { entry2.Metadata.Add(RevertDataSafe(in data3), RevertDataSafe(in data4)); } } else { text = RevertDataSafe(in data3); AddEntry(text, RevertDataSafe(in data4)); } } num = i + 1; flag = true; flag2 = false; break; case ':': flag2 = true; num2 = i; num3 = i + 1; break; case ']': { endIndex = i; if (!flag2) { return; } int num4 = num; string data = content.Substring(num4, num2 - num4); num4 = num3; string data2 = content.Substring(num4, i - num4); if (flag) { CCFGEntry entry; if (text == null) { AddMetadata(RevertDataSafe(in data), RevertDataSafe(in data2)); } else if (TryGetEntry(text, out entry)) { entry.Metadata.Add(RevertDataSafe(in data), RevertDataSafe(in data2)); } } else { text = RevertDataSafe(in data); AddEntry(text, RevertDataSafe(in data2)); } return; } } } } } public class ConfigBundle { public class ConfigEntry { public readonly Dictionary<string, string> Metadata = new Dictionary<string, string>(); public string Value; public string this[string meta] { get { return Metadata[meta]; } set { Metadata[meta] = value; } } } public const int META_CAPACITY_ESTIMATE = 15; public const int ENTRY_CAPACITY_ESTIMATE = 90; public const char TOKEN_ENTRY_START = '['; public const char TOKEN_ENTRY_END = ']'; public const char TOKEN_META_SEPARATOR = '|'; public const char TOKEN_VALUE_SEPARATOR = ':'; public const char TOKEN_DATA_SKIP = '\\'; public const string STRING_ENTRY_START = "["; public const string STRING_ENTRY_END = "]"; public const string STRING_META_SEPARATOR = "|"; public const string STRING_VALUE_SEPARATOR = ":"; public const string STRING_DATA_SKIP = "\\"; private readonly Dictionary<string, string> _meta = new Dictionary<string, string>(); private readonly Dictionary<string, ConfigEntry> _entries = new Dictionary<string, ConfigEntry>(); private static string MakeDataSafe(in string data) { StringBuilder stringBuilder = new StringBuilder(data); stringBuilder.Replace("\\", "\\\\"); stringBuilder.Replace("[", "\\["); stringBuilder.Replace("]", "\\]"); stringBuilder.Replace("|", "\\|"); stringBuilder.Replace(":", "\\:"); return stringBuilder.ToString(); } private static string RevertDataSafe(in string data) { StringBuilder stringBuilder = new StringBuilder(data); stringBuilder.Replace("\\[", "["); stringBuilder.Replace("\\]", "]"); stringBuilder.Replace("\\|", "|"); stringBuilder.Replace("\\:", ":"); stringBuilder.Replace("\\\\", "\\"); return stringBuilder.ToString(); } public void AddMetadata(string name, string value) { _meta[name] = value; } public void RemoveMetadata(string name) { _meta.Remove(name); } public bool TryGetMetadata(string name, out string value) { return _meta.TryGetValue(name, out value); } public IReadOnlyDictionary<string, string> Metadata() { return _meta; } public void ClearMetadata() { _meta.Clear(); } public ConfigEntry AddEntry(string name, string value, Dictionary<string, string> meta = null) { if (TryGetEntry(name, out var entry)) { entry.Value = value; entry.Metadata.Clear(); if (meta != null) { foreach (KeyValuePair<string, string> metum in meta) { entry[metum.Key] = metum.Value; } } } else { entry = new ConfigEntry { Value = value }; _entries[name] = entry; if (meta != null) { foreach (KeyValuePair<string, string> metum2 in meta) { entry[metum2.Key] = metum2.Value; } } } return entry; } public void RemoveEntry(string name) { _entries.Remove(name); } public bool TryGetEntry(string name, out ConfigEntry entry) { return _entries.TryGetValue(name, out entry); } public IReadOnlyDictionary<string, ConfigEntry> Entries() { return _entries; } public void Read(in string data) { _meta.Clear(); _entries.Clear(); ReadEntries(data); } public void Write(out string data) { int num = 15 * _meta.Count; int num2 = 90 * _entries.Count; StringBuilder stringBuilder = new StringBuilder(num + num2); stringBuilder.Append('['); foreach (KeyValuePair<string, string> metum in _meta) { stringBuilder.Append('|'); string data2 = metum.Key; StringBuilder stringBuilder2 = stringBuilder.Append(MakeDataSafe(in data2)).Append(':'); string data3 = metum.Value; stringBuilder2.Append(MakeDataSafe(in data3)); } stringBuilder.Append(']'); stringBuilder.Append(Environment.NewLine); foreach (KeyValuePair<string, ConfigEntry> entry in _entries) { StringBuilder stringBuilder3 = stringBuilder.Append('['); string data2 = entry.Key; stringBuilder3.Append(MakeDataSafe(in data2)).Append(':').Append(MakeDataSafe(in entry.Value.Value)); foreach (KeyValuePair<string, string> metadatum in entry.Value.Metadata) { stringBuilder.Append('|'); data2 = metadatum.Key; StringBuilder stringBuilder4 = stringBuilder.Append(MakeDataSafe(in data2)).Append(':'); string data3 = metadatum.Value; stringBuilder4.Append(MakeDataSafe(in data3)); } stringBuilder.Append(']'); } data = stringBuilder.ToString(); } private void ReadEntries(string content) { bool flag = false; for (int i = 0; i < content.Length; i++) { if (flag) { flag = false; } else if (content[i] == '\\') { flag = true; } else if (content[i] == '[') { ReadSingleEntry(content, in i, out i); } } } private void ReadSingleEntry(string content, in int index, out int endIndex) { int num = index + 1; int num2 = -1; int num3 = -1; bool flag = false; bool flag2 = false; bool flag3 = false; string text = null; endIndex = index; for (int i = index; i < content.Length; i++) { if (flag3) { flag3 = false; continue; } switch (content[i]) { case '\\': flag3 = true; break; case '|': if (flag2) { int num4 = num; string data3 = content.Substring(num4, num2 - num4); num4 = num3; string data4 = content.Substring(num4, i - num4); if (flag) { ConfigEntry entry2; if (text == null) { AddMetadata(RevertDataSafe(in data3), RevertDataSafe(in data4)); } else if (TryGetEntry(text, out entry2)) { entry2.Metadata.Add(RevertDataSafe(in data3), RevertDataSafe(in data4)); } } else { text = RevertDataSafe(in data3); AddEntry(text, RevertDataSafe(in data4)); } } num = i + 1; flag = true; flag2 = false; break; case ':': flag2 = true; num2 = i; num3 = i + 1; break; case ']': { endIndex = i; if (!flag2) { return; } int num4 = num; string data = content.Substring(num4, num2 - num4); num4 = num3; string data2 = content.Substring(num4, i - num4); if (flag) { ConfigEntry entry; if (text == null) { AddMetadata(RevertDataSafe(in data), RevertDataSafe(in data2)); } else if (TryGetEntry(text, out entry)) { entry.Metadata.Add(RevertDataSafe(in data), RevertDataSafe(in data2)); } } else { text = RevertDataSafe(in data); AddEntry(text, RevertDataSafe(in data2)); } return; } } } } } [Obsolete("")] public class DefaultBundle : Bundle { public const string TOKEN_FILE_START = "{"; public const string TOKEN_FILE_END = "}"; public const string TOKEN_ENTRY_START = "["; public const string TOKEN_ENTRY_END = "]"; public const string TOKEN_ENTRY_SEPARATOR = ":"; public const string TOKEN_ENTRY_VALUE_SEPARATOR = "="; private readonly Dictionary<string, string> _data = new Dictionary<string, string>(); public string TOKEN_SKIP => "\\"; public override IEnumerable<string> Keys => _data.Keys; public override IEnumerable<string> Values => _data.Values; public override int Count => _data.Count; public override void Set(string key, string value) { _data[key] = value; } public override void Add(string key, string value) { _data.Add(key, value); } public override void Clear() { _data.Clear(); } public override bool Contains(string key) { return _data.ContainsKey(key); } public override string Get(string key, string defaultValue) { return _data.GetValueOrDefault(key, defaultValue); } public override IEnumerator<KeyValuePair<string, string>> GetEnumerator() { return _data.GetEnumerator(); } public override void Remove(string key) { _data.Remove(key); } public override bool TryGet(string key, out string value) { return _data.TryGetValue(key, out value); } public override string Pack() { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.Append("{"); foreach (KeyValuePair<string, string> datum in _data) { stringBuilder.Append("[").Append(datum.Key.Replace("=", TOKEN_SKIP + "=")).Append("=") .Append(datum.Value.Replace("]", TOKEN_SKIP + "]")) .Append("]") .Append(":"); } if (_data.Count > 0) { stringBuilder.Remove(stringBuilder.Length - ":".Length, ":".Length); } stringBuilder.AppendLine("}"); return stringBuilder.ToString(); } public override void Unpack(string data) { Step0_findBoundary(data, out var minIndex, out var maxIndex); if (minIndex == -1 || maxIndex == -1) { return; } if (maxIndex < minIndex) { throw new IOException($"Begining {minIndex} and EOD {maxIndex} file are not valid"); } string[] array = Step1_getAllEntries(data, minIndex, maxIndex); foreach (string text in array) { int num = FindNextToken(text, 0, "="); if (num != -1) { string key = text.Substring(0, num).Replace(TOKEN_SKIP + "=", "="); string text2 = text; int num2 = num + 1; Set(key, text2.Substring(num2, text2.Length - num2).Replace(TOKEN_SKIP + "]", "]")); } } } private string[] Step1_getAllEntries(string data, int minIndex, int maxIndex) { int index = minIndex; List<string> list = new List<string>(); int foundBeginIndex; int foundFinalIndex; while (Step11_getNextEntry(data, out foundBeginIndex, out foundFinalIndex, index, maxIndex)) { list.Add(data.Substring(foundBeginIndex + 1, foundFinalIndex - 1 - foundBeginIndex)); index = foundFinalIndex; } return list.ToArray(); } private bool Step11_getNextEntry(string data, out int foundBeginIndex, out int foundFinalIndex, int index, int maxIndex) { foundBeginIndex = FindNextToken(data, index, "[", maxIndex); if (foundBeginIndex == -1) { foundFinalIndex = -1; return false; } foundFinalIndex = FindNextToken(data, foundBeginIndex, "]", maxIndex); return foundFinalIndex != -1; } private void Step0_findBoundary(string data, out int minIndex, out int maxIndex) { minIndex = data.IndexOf("{"); maxIndex = data.LastIndexOf("}"); } private int FindNextToken(string data, int startIndex, string token, int endIndex = -1) { int num = 0; if (endIndex < 0) { endIndex = data.Length; } for (int i = startIndex; i < endIndex; i++) { num = ((data[i] == token[num]) ? (num + 1) : 0); if (num == token.Length) { if (!IsTokenBefore(data, i - token.Length + 1, TOKEN_SKIP)) { return i - token.Length + 1; } num = 0; } } return -1; } private bool IsTokenBefore(string data, int index, string token) { int num = token.Length; int num2 = index; while (num2 > 0) { if (data[num2 - 1] == token[num - 1]) { num--; if (num == 0) { return true; } num2--; continue; } return false; } return false; } } public static class PathUtils { public static string FormPath(params string[] paths) { if (paths == null) { return null; } string text = string.Empty; for (int i = 0; i < paths.Length; i++) { text = Path.Combine(text, paths[i]); } return text; } public static string TryCreateFile(string path, string filename) { return TryCreateFile(Path.Combine(path, filename)); } public static string TryCreateFile(string path) { Directory.CreateDirectory(Path.GetDirectoryName(path)); File.Create(path); return path; } public static bool TryCreateFolder(string path) { try { Directory.CreateDirectory(Path.GetDirectoryName(path)); return true; } catch (Exception) { return false; } } } } namespace Amrv.ConfigurableCompany.Plugin { [BepInPlugin("dev.amrv.lethalCompany.config", "Configurable Company", "3.7.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] internal sealed class ConfigurableCompanyPlugin : BaseUnityPlugin { public const string PLUGIN_GUID = "dev.amrv.lethalCompany.config"; public const string PLUGIN_NAME = "Configurable Company"; public const string PLUGIN_VERSION = "3.7.0"; private static ConfigurableCompanyPlugin _plugin; private readonly Harmony Patcher = new Harmony("dev.amrv.lethalCompany.config"); public static string PluginFolder { get; private set; } public static string DataFolder { get; private set; } public ConfigurableCompanyPlugin() { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Expected O, but got Unknown //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Expected O, but got Unknown if ((Object)(object)_plugin != (Object)null) { throw new Exception("You can't create multiples instances of ConfigurableCompanyPlugin"); } _plugin = this; PluginFolder = Path.GetDirectoryName(((BaseUnityPlugin)this).Info.Location) + Path.DirectorySeparatorChar; DataFolder = Path.Combine(Application.persistentDataPath, "Configurable Company", Directory.GetParent(Paths.BepInExRootPath).Name); Directory.CreateDirectory(DataFolder); Info("Initializating Configurable Company"); MenuPrefabs.Ping(); CTypes.Ping(); Events.Start(); NetEventRouter.RegisterListeners(); Patcher = new Harmony("dev.amrv.lethalCompany.config"); Patcher.PatchAll(typeof(ConfigurableCompanyPlugin).Assembly); DependencyManager.CheckDependencies(Patcher); Application.quitting += OnQuit; Info("Completed Configurable Company Initialization"); LifecycleEventRouter.PluginStart(); } private static void OnQuit() { IOController.SetConfigMetadata(); IOController.SaveCategories(); IOController.SaveSections(); IOController.SaveConfigs(); } internal static void Warn(object data) { ((BaseUnityPlugin)_plugin).Logger.LogWarning(data); } internal static void Error(object data) { ((BaseUnityPlugin)_plugin).Logger.LogError(data); } internal static void Info(object data) { ((BaseUnityPlugin)_plugin).Logger.LogInfo(data); } internal static void Debug(object data) { ((BaseUnityPlugin)_plugin).Logger.LogDebug(data); } } } namespace Amrv.ConfigurableCompany.Core { public class BuildingException : Exception { public BuildingException() { } public BuildingException(string message) : base(message) { } public BuildingException(string message, Exception innerException) : base(message, innerException) { } protected BuildingException(SerializationInfo info, StreamingContext context) : base(info, context) { } } internal static class CCache { private static string _userSeed; public static string UsedSeed { get { return _userSeed; } set { ConfigurableCompanyPlugin.Debug("Set cache UserSeed to " + value); _userSeed = value; } } } public class IDStorage<T> : IReadOnlyDictionary<string, T>, IEnumerable<KeyValuePair<string, T>>, IEnumerable, IReadOnlyCollection<KeyValuePair<string, T>>, IEnumerable<string> { private readonly Dictionary<string, T> _storage; public T this[string key] => _storage[key]; public IEnumerable<string> Keys => _storage.Keys; public IEnumerable<T> Values => _storage.Values; public int Count => _storage.Count; internal IDStorage(Dictionary<string, T> dictionary = null) { _storage = dictionary ?? new Dictionary<string, T>(); } public bool ContainsKey(string key) { return _storage.ContainsKey(key); } public IEnumerator<KeyValuePair<string, T>> GetEnumerator() { return _storage.GetEnumerator(); } public bool TryGetValue(string key, out T value) { return _storage.TryGetValue(key, out value); } IEnumerator IEnumerable.GetEnumerator() { return _storage.GetEnumerator(); } IEnumerator<string> IEnumerable<string>.GetEnumerator() { return _storage.Keys.GetEnumerator(); } } public abstract class InstanceBuilder<T> : IDisposable { private T instance; public virtual bool TryBuild(out T item) { try { item = Build(); return true; } catch (Exception) { item = default(T); return false; } } public virtual T GetOrCreate() { if (TryGetExisting(out var item)) { return item; } return Build(); } public T Build() { try { T val = instance; return (val != null) ? val : (instance = BuildInstance()); } catch (Exception arg) { ConfigurableCompanyPlugin.Error($"Error creating entry{Environment.NewLine}{arg}"); return default(T); } } protected abstract T BuildInstance(); protected abstract bool TryGetExisting(out T item); public virtual void Dispose() { Build(); } public static implicit operator T(InstanceBuilder<T> builder) { return builder.Build(); } } internal static class LifecycleEventRouter { public static void PluginStart() { CEvents.LifecycleEvents.PluginStart.Invoke(); } public static void CreateMenu(MenuManager manager) { //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) MenuLoader.Create(); IOController.LoadCategories(); IOController.LoadSections(); IOController.LoadConfigs(); IOController.GetConfigCache(); MenuController.AfterCreation(AfterCreation); Canvas[] array = Object.FindObjectsOfType<Canvas>(); foreach (Canvas val in array) { if ((Object)(object)((Component)val).gameObject.transform.parent == (Object)null) { Scene scene = ((Component)val).gameObject.scene; if (((Scene)(ref scene)).name == "MainMenu") { MenuController.Create(((Component)val).gameObject, manager); break; } } } } private static IEnumerator AfterCreation(MenuManager manager) { MenuController.SetLocked(GameNetworkManager.Instance?.currentSaveFileName == "LCChallengeFile"); MenuController.UpdateSeedFromCache(); yield return null; MenuLoader.Destroy(); yield return null; } public static void DestroyMenu() { IOController.SaveCategories(); IOController.SaveSections(); IOController.SaveConfigs(); MenuController.Destroy(); MenuLoader.Destroy(); MenuPopup.Destroy(); } } public static class RandomSeedParser { private static readonly Random selector; public static readonly Dictionary<char, int> CHAR_MAPPING; public static readonly char[] CHAR_ARRAY; static RandomSeedParser() { selector = new Random(); CHAR_ARRAY = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ".ToCharArray(); CHAR_MAPPING = new Dictionary<char, int>(CHAR_ARRAY.Length); for (int i = 0; i < CHAR_ARRAY.Length; i++) { CHAR_MAPPING[CHAR_ARRAY[i]] = i; } } public static bool IsValidString(string str) { if (str.Length > 10) { return false; } for (int i = 0; i < str.Length; i++) { if (!IsValidChar(str[i])) { return false; } } return true; } public static bool IsValidChar(char ch) { if (ch <= '/' || ch >= ':') { if (ch > '@') { return ch < '['; } return false; } return true; } public static string GenerateRandom() { return GenerateRandom(selector); } public static string GenerateRandom(Random random) { char[] array = new char[10]; for (int i = 0; i < array.Length; i++) { array[i] = CHAR_ARRAY[random.Next(CHAR_ARRAY.Length)]; } return new string(array); } public static long FromSeed(string str) { str = FormalizeString(str); long num = 0L; for (int i = 0; i < str.Length; i++) { num *= 36; num += CHAR_MAPPING.GetValueOrDefault(str[i], 0); } return num; } public static string FormalizeString(string str) { str = str.Trim(); StringBuilder stringBuilder = new StringBuilder(Math.Min(10, str.Length)); for (int i = 0; i < stringBuilder.Capacity; i++) { if (CHAR_MAPPING.TryGetValue(str[i], out var _)) { stringBuilder.Append(char.ToUpper(str[i])); } } return stringBuilder.ToString(); } } public sealed class ReadonlyDictionary<K, V> : IReadOnlyDictionary<K, V>, IEnumerable<KeyValuePair<K, V>>, IEnumerable, IReadOnlyCollection<KeyValuePair<K, V>> { [CompilerGenerated] private Dictionary<K, V> <wrapper>P; public V this[K key] => <wrapper>P.GetValueOrDefault(key, default(V)); public IEnumerable<K> Keys => <wrapper>P.Keys; public IEnumerable<V> Values => <wrapper>P.Values; public int Count => <wrapper>P.Count; public ReadonlyDictionary(Dictionary<K, V> wrapper) { <wrapper>P = wrapper; base..ctor(); } public bool ContainsKey(K key) { return <wrapper>P.ContainsKey(key); } public IEnumerator<KeyValuePair<K, V>> GetEnumerator() { return <wrapper>P.GetEnumerator(); } public bool TryGetValue(K key, out V value) { return <wrapper>P.TryGetValue(key, out value); } IEnumerator IEnumerable.GetEnumerator() { return <wrapper>P.GetEnumerator(); } } } namespace Amrv.ConfigurableCompany.Core.Patch { [HarmonyPatch(typeof(GameNetworkManager))] internal class GameNetworkManagerPatch { [HarmonyPatch("SaveGame")] [HarmonyPostfix] private static void SaveGameValues_Postfix() { if (NetSynchronizer.IsServer) { IOController.SetConfigCache(); IOController.SaveConfigs(); } } } [HarmonyPatch(typeof(MenuManager))] internal class MenuManagerPatch { [CompilerGenerated] private static class <>O { public static UnityAction <0>__ClickBackButton_Event; } [HarmonyPatch("Start")] [HarmonyPostfix] private static void Start_Postfix(MenuManager __instance) { //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Expected O, but got Unknown ConfigurableCompanyPlugin.Debug("MenuManager::Start [Postfix]"); if (!__instance.isInitScene) { MenuLoader.Create(); LifecycleEventRouter.CreateMenu(__instance); ButtonClickedEvent onClick = __instance.HostSettingsScreen.FindChild("HostSettingsContainer/Back").GetComponent<Button>().onClick; object obj = <>O.<0>__ClickBackButton_Event; if (obj == null) { UnityAction val = ClickBackButton_Event; <>O.<0>__ClickBackButton_Event = val; obj = (object)val; } ((UnityEvent)onClick).AddListener((UnityAction)obj); } } private static void ClickBackButton_Event() { MenuController.SetVisible(visible: false); } [HarmonyPatch("ClickHostButton")] [HarmonyPostfix] private static void ClickHostButton_Postfix() { ConfigurableCompanyPlugin.Debug("MenuManager::ClickHostButton [Postfix]"); MenuController.SetVisible(visible: true); } [HarmonyPatch("ConfirmHostButton")] [HarmonyPostfix] private static void ConfirmHostButton_Postfix() { ConfigurableCompanyPlugin.Debug("MenuManager::ConfirmHostButton [Postfix]"); MenuController.DestroyIfCreating(); LifecycleEventRouter.DestroyMenu(); } } [HarmonyPatch(typeof(NetworkManager))] internal class NetworkManagerPatch { [HarmonyPatch(/*Could not decode attribute arguments.*/)] [HarmonyPostfix] private static void UpdateSingleton(NetworkManager value) { ConfigurableCompanyPlugin.Debug($"Detected NetworkManager singleton modification ({(Object)(object)value == (Object)null}) {value}"); if ((Object)(object)value == (Object)null) { NetSynchronizer.Destroy(); } else { NetSynchronizer.Create(value); } } } [HarmonyPatch(typeof(SaveFileUISlot))] internal class SaveFileUISlotPatch { public static bool Patch_SetFileToThis_Postfix = true; [HarmonyPatch("SetFileToThis")] [HarmonyPostfix] private static void SetFileToThis_Postfix(SaveFileUISlot __instance) { if (Patch_SetFileToThis_Postfix) { ConfigurableCompanyPlugin.Debug($"SaveFileUISlot::SetFileToThis [Postfix] | fileNum: {__instance.fileNum} |"); MenuController.SetLocked(__instance.fileNum == -1); IOController.LoadConfigs(); IOController.GetConfigCache(); MenuController.UpdateSeedFromCache(); MenuController.SetCurrentFileName(GameNetworkManager.Instance.currentSaveFileName); } } } } namespace Amrv.ConfigurableCompany.Core.Net { internal static class NetController { public const string VERSION = "2n"; public const string CONFIGS_SYNC = "configurable-company_client_configs-sync"; public static void SendAllConfigs(ulong client) { //IL_00b6: Unknown result type (might be due to invalid IL or missing references) ConfigBundle configBundle = new ConfigBundle(); configBundle.AddMetadata("VERSION", "2n"); CConfig[] array = new CConfig[CConfig.Storage.Count]; int num = 0; foreach (CConfig value2 in CConfig.Storage.Values) { if (value2.Synchronized) { WriteConfigBundle(value2, configBundle); array[num++] = value2; } } configBundle.Write(out var data); ConfigurableCompanyPlugin.Debug($"Send configuration bundle with size {FastBufferWriter.GetWriteSize(data, false)}"); FastBufferWriter value = default(FastBufferWriter); ((FastBufferWriter)(ref value))..ctor(FastBufferWriter.GetWriteSize(data, false), (Allocator)2, -1); ((FastBufferWriter)(ref value)).WriteValueSafe(data, false); NetSynchronizer.Messaging.Send("configurable-company_client_configs-sync", value, (NetworkDelivery)4, client); Array.Resize(ref array, num + 1); CEvents.IOSEvents.Synchronize.InvokeFull(new CEventSynchronize(sent: true, array)); } public static void SendConfig(params CConfig[] configs) { //IL_008b: Unknown result type (might be due to invalid IL or missing references) ConfigBundle configBundle = new ConfigBundle(); configBundle.AddMetadata("VERSION", "2n"); int num = 0; CConfig[] array = configs; foreach (CConfig cConfig in array) { if (cConfig.Synchronized) { WriteConfigBundle(cConfig, configBundle); num++; } } configBundle.Write(out var data); ConfigurableCompanyPlugin.Debug($"Send configuration bundle with size {FastBufferWriter.GetWriteSize(data, false)}"); FastBufferWriter value = default(FastBufferWriter); ((FastBufferWriter)(ref value))..ctor(FastBufferWriter.GetWriteSize(data, false), (Allocator)2, -1); ((FastBufferWriter)(ref value)).WriteValueSafe(data, false); NetSynchronizer.Messaging.Send("configurable-company_client_configs-sync", value); Array.Resize(ref configs, num + 1); CEvents.IOSEvents.Synchronize.InvokeFull(new CEventSynchronize(sent: true, configs)); } private static void WriteConfigBundle(CConfig config, ConfigBundle bundle) { if (config.SerializeValue(out var data)) { bundle.AddEntry(config.ID, data, new Dictionary<string, string> { ["enabled"] = config.Enabled.ToString() }); } } } internal static class NetEventRouter { public static void RegisterListeners() { NetSynchronizer.ServerCallbacks.Start += Server_Start; NetSynchronizer.ServerCallbacks.Stop += Server_Stop; NetSynchronizer.ServerCallbacks.ClientConnect += Server_ClientConnect; NetSynchronizer.ServerCallbacks.ClientDisconnect += Server_ClientDisconnect; NetSynchronizer.ClientCallbacks.Connect += Client_Connect; NetSynchronizer.ClientCallbacks.Disconnect += Client_Disconnect; } public static void Server_Start() { ConfigurableCompanyPlugin.Debug("NetEventRouter > Server :: Start"); NetReceiveRouter.RegisterServerMessages(); } public static void Server_ClientConnect(ulong client) { ConfigurableCompanyPlugin.Debug($"NetEventRouter > Server :: ClientConnect | id: {client} |"); if (NetSynchronizer.IsServer) { NetController.SendAllConfigs(client); } } public static void Server_ClientDisconnect(ulong obj) { ConfigurableCompanyPlugin.Debug($"NetEventRouter > Server :: ClientDisconnect | id: {obj} |"); } public static void Server_Stop(bool obj) { ConfigurableCompanyPlugin.Debug($"NetEventRouter > Server :: Stop | ???: {obj} |"); } public static void Client_Disconnect(bool obj) { ConfigurableCompanyPlugin.Debug($"NetEventRouter > Client :: Disconnect | ???: {obj} |"); } public static void Client_Connect() { ConfigurableCompanyPlugin.Debug("NetEventRouter > Client :: Connect"); MenuController.DestroyIfCreating(); LifecycleEventRouter.DestroyMenu(); NetReceiveRouter.RegisterClientMessages(); } } internal class NetReceiveRouter { [CompilerGenerated] private static class <>O { public static HandleNamedMessageDelegate <0>__Client_ReceiveConfigs; } public const string CONFIGS_SYNC = "configurable-company_client_configs-sync"; public static void RegisterClientMessages() { //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Expected O, but got Unknown ConfigurableCompanyPlugin.Debug("NetReceiveRouter::RegisterClientMessages"); object obj = <>O.<0>__Client_ReceiveConfigs; if (obj == null) { HandleNamedMessageDelegate val = Client_ReceiveConfigs; <>O.<0>__Client_ReceiveConfigs = val; obj = (object)val; } NetSynchronizer.Messaging.Register("configurable-company_client_configs-sync", (HandleNamedMessageDelegate)obj); } public static void RegisterServerMessages() { ConfigurableCompanyPlugin.Debug("NetReceiveRouter::RegisterServerMessages"); } internal static void Client_ReceiveConfigs(ulong senderClientId, FastBufferReader messagePayload) { ConfigurableCompanyPlugin.Debug($"NetReceiveRouter::Client_ReceiveConfigs {((FastBufferReader)(ref messagePayload)).Length}"); if (NetSynchronizer.IsServer) { return; } ConfigBundle configBundle = new ConfigBundle(); string data = default(string); ((FastBufferReader)(ref messagePayload)).ReadValueSafe(ref data, false); configBundle.Read(in data); if (!configBundle.TryGetMetadata("VERSION", out var value) || !value.Equals("2n")) { ConfigurableCompanyPlugin.Error("Can't sync configurations, version mismatch " + value + " | 2n"); return; } CConfig[] array = new CConfig[configBundle.Entries().Count]; int num = 0; foreach (KeyValuePair<string, ConfigBundle.ConfigEntry> item in configBundle.Entries()) { if (CConfig.Storage.TryGetValue(item.Key, out var value2) && value2.Synchronized) { ReadConfigBundle(value2, item.Value); array[num++] = value2; } } Array.Resize(ref array, num + 1); CEvents.IOSEvents.Synchronize.InvokeFull(new CEventSynchronize(sent: false, array)); } private static void ReadConfigBundle(CConfig config, ConfigBundle.ConfigEntry entry) { config.DeserializeValue(in entry.Value, Amrv.ConfigurableCompany.API.ChangeReason.SYNCHRONIZATION); if (entry.Metadata.TryGetValue("enabled", out var value)) { config.Enabled = value.ToLower().Equals("true"); } } } public static class NetSynchronizer { public static class StateCallbacks { public static event Action<NetworkManager> Start; public static event Action Stop; internal static void TriggerStart(NetworkManager instance) { StateCallbacks.Start?.Invoke(instance); } internal static void TriggerStop() { StateCallbacks.Stop?.Invoke(); } } public static class ServerCallbacks { public static event Action<ulong> ClientConnect; public static event Action<ulong> ClientDisconnect; public static event Action Start; public static event Action<bool> Stop; internal static void TriggerClientConnect(ulong client) { ServerCallbacks.ClientConnect?.Invoke(client); } internal static void TriggerClientDisconnect(ulong client) { ServerCallbacks.ClientDisconnect?.Invoke(client); } internal static void TriggerStart() { ServerCallbacks.Start?.Invoke(); } internal static void TriggerStop(bool forced) { ServerCallbacks.Stop?.Invoke(forced); } } public static class ClientCallbacks { public static event Action Connect; public static event Action<bool> Disconnect; internal static void TriggerConnect() { ClientCallbacks.Connect?.Invoke(); } internal static void TriggerDisconnect(bool forced) { ClientCallbacks.Disconnect?.Invoke(forced); } } public static class Messaging { public static void Send(string identifier, FastBufferWriter? writer = null, params ulong[] clients) { Send(identifier, writer, (NetworkDelivery)3, clients); } public static void Send(string identifier, FastBufferWriter? writer = null, NetworkDelivery delivery = 3, params ulong[] clients) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)NetworkManager.Singleton == (Object)null)) { FastBufferWriter valueOrDefault = writer.GetValueOrDefault(); if (clients == null || clients.Length == 0) { NetworkManager.Singleton.CustomMessagingManager.SendNamedMessageToAll(identifier, valueOrDefault, delivery); } else { NetworkManager.Singleton.CustomMessagingManager.SendNamedMessage(identifier, (IReadOnlyList<ulong>)clients, valueOrDefault, delivery); } } } public static bool Register(string identifier, HandleNamedMessageDelegate handler) { if ((Object)(object)NetworkManager.Singleton == (Object)null) { return false; } NetworkManager.Singleton.CustomMessagingManager.RegisterNamedMessageHandler(identifier, handler); return true; } public static bool Unregister(string identifier) { if ((Object)(object)NetworkManager.Singleton == (Object)null) { return false; } CustomMessagingManager customMessagingManager = NetworkManager.Singleton.CustomMessagingManager; if (customMessagingManager != null) { customMessagingManager.UnregisterNamedMessageHandler(identifier); } return true; } public static FastBufferWriter GetWriter(int size = 0) { //IL_0003: Unknown result type (might be due to invalid IL or missing references) return new FastBufferWriter(size, (Allocator)2, -1); } public static int GetSize(string text, bool oneByteChars = false) { return FastBufferWriter.GetWriteSize(text, oneByteChars); } public static int GetSize<T>(T item) where T : unmanaged { //IL_0004: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Unknown result type (might be due to invalid IL or missing references) return FastBufferWriter.GetWriteSize<T>(ref item, default(ForStructs)); } public static int GetSize<T>(params T[] items) where T : unmanaged { return FastBufferWriter.GetWriteSize<T>(items, -1, 0); } } public static bool IsServer { get { NetworkManager singleton = NetworkManager.Singleton; if (singleton == null) { return false; } return singleton.IsServer; } } public static bool IsClient { get { NetworkManager singleton = NetworkManager.Singleton; if (singleton == null) { return false; } return singleton.IsClient; } } public static bool IsHost { get { NetworkManager singleton = NetworkManager.Singleton; if (singleton == null) { return false; } return singleton.IsHost; } } internal static void Create(NetworkManager instance) { NetworkManager.Singleton.OnClientStarted += ClientCallbacks.TriggerConnect; NetworkManager.Singleton.OnClientStopped += ClientCallbacks.TriggerDisconnect; NetworkManager.Singleton.OnClientConnectedCallback += ServerCallbacks.TriggerClientConnect; NetworkManager.Singleton.OnClientDisconnectCallback += ServerCallbacks.TriggerClientDisconnect; NetworkManager.Singleton.OnServerStarted += ServerCallbacks.TriggerStart; NetworkManager.Singleton.OnServerStopped += ServerCallbacks.TriggerStop; StateCallbacks.TriggerStart(instance); } internal static void Destroy() { StateCallbacks.TriggerStop(); } } } namespace Amrv.ConfigurableCompany.Core.IO { public sealed class ConfigFile { public const string METADATA_VERSION = "VERSION"; public const string FLAG_ENABLED = "enabled"; private readonly CCFGFile _ccfg; public string File => _ccfg.File; public string Version => _ccfg.Metadata().GetValueOrDefault("VERSION", null); public ConfigFile(string path, string file, int version, char type) { _ccfg = new CCFGFile(Path.Combine(path, file)); _ccfg.AddMetadata("VERSION", $"{version}{type}"); } public bool IsValidVersion(int version, char type) { if (_ccfg.TryGetMetadata("VERSION", out var value)) { string text = value; if (int.TryParse(text.Substring(0, text.Length - 1), out var result)) { return version >= result; } return false; } return false; } public bool WriteConfigValue(CConfig config) { Dictionary<string, string> dictionary = new Dictionary<string, string>(); if (config.SerializeValue(out var data)) { if (config.Toggleable) { dictionary["enabled"] = $"{config.Enabled}"; } _ccfg.AddEntry(config.ID, data, dictionary); return true; } return false; } public bool ReadConfigValue(CConfig config) { if (_ccfg.TryGetEntry(config.ID, out var entry)) { config.DeserializeValue(in entry.Value, Amrv.ConfigurableCompany.API.ChangeReason.READ_FROM_FILE); if (config.Toggleable && entry.Metadata.TryGetValue("enabled", out var value)) { config.Enabled = value.ToLower().Equals("true"); } return true; } return false; } public void Load() { _ccfg.Read(); } public void Save() { _ccfg.Write(); } } internal static class IOCategories { private static readonly CCATFile File = new CCATFile(Path.Combine(ConfigurableCompanyPlugin.DataFolder, "categories.ccat")); public static void Load() { File.Read(); } public static void Save() { File.Write(); } public static bool GetOpenState(CCategory category) { if (File.TryGetState(category.ID, out var state)) { return state; } return false; } public static void SetOpenState(CCategory category, bool open) { File.SetState(category.ID, open); } } internal static class IOConfigurations { private const string FALLBACK_FILE = "LCUnknownFile"; private static readonly Dictionary<string, CCFGFile> _files = new Dictionary<string, CCFGFile>(); public static string FileName => GameNetworkManager.Instance?.currentSaveFileName ?? "LCUnknownFile"; public static string FullPath => Path.Combine(ConfigurableCompanyPlugin.DataFolder, GameNetworkManager.Instance?.currentSaveFileName ?? "LCUnknownFile"); public static string GetFullPath(string file) { return Path.Combine(ConfigurableCompanyPlugin.DataFolder, file + ".ccfg"); } public static void Load(string file) { if (!_files.TryGetValue(file, out var value)) { value = new CCFGFile(GetFullPath(file)); _files.Add(file, value); } value.Read(); } public static void Save(string file) { if (_files.TryGetValue(file, out var value)) { value.Write(); } } public static void GetOrCreate(string file, out CCFGFile cfg) { if (!_files.TryGetValue(file, out cfg)) { cfg = new CCFGFile(GetFullPath(file)); _files.Add(file, cfg); } } public static bool TryGetFile(string file, out CCFGFile cfg) { return _files.TryGetValue(file, out cfg); } internal static void Delete(string file) { if (_files.TryGetValue(file, out var _)) { File.Delete(file); _files.Remove(file); } } } public static class IOController { public const string VERSION = "2"; public const string FIELD_CUSTOM_SEED = "Seed"; public static void SaveCategories() { IOCategories.Save(); } public static void LoadCategories() { IOCategories.Load(); } public static void SaveSections() { IOSections.Save(); } public static void LoadSections() { IOSections.Load(); } public static bool GetCategoryOpenState(CCategory category) { return IOCategories.GetOpenState(category); } public static void SetCategoryOpenState(CCategory category, bool open) { IOCategories.SetOpenState(category, open); } public static bool GetSectionOpenState(CSection section) { return IOSections.GetOpenState(section); } public static void SetSectionOpenState(CSection section, bool open) { IOSections.SetOpenState(section, open); } public static void SaveConfigs() { IOConfigurations.Save(IOConfigurations.FileName); } public static void LoadConfigs() { IOConfigurations.Load(IOConfigurations.FileName); } public static void RemoveConfigs() { IOConfigurations.Delete(IOConfigurations.FileName); } public static void SetConfigCache(CConfig config) { IOConfigurations.GetOrCreate(IOConfigurations.FileName, out var cfg); ApplyMetadata(cfg); WriteConfigEntryCache(config, cfg); } public static bool GetConfigCache(CConfig config) { if (IOConfigurations.TryGetFile(IOConfigurations.FileName, out var cfg) && cfg.TryGetEntry(config.ID, out var entry)) { ReadConfigEntryCache(config, entry); } return false; } public static void SetConfigMetadata() { IOConfigurations.GetOrCreate(IOConfigurations.FileName, out var cfg); ApplyMetadata(cfg); } public static void SetConfigCache() { IOConfigurations.GetOrCreate(IOConfigurations.FileName, out var cfg); ApplyMetadata(cfg); foreach (CConfig value in CConfig.Storage.Values) { WriteConfigEntryCache(value, cfg); } } public static void GetConfigCache() { if (IOConfigurations.TryGetFile(IOConfigurations.FileName, out var cfg)) { if (cfg.TryGetMetadata("Seed", out var value) && value != null) { CCache.UsedSeed = value; } else { CCache.UsedSeed = ""; } { foreach (CConfig value2 in CConfig.Storage.Values) { if (cfg.TryGetEntry(value2.ID, out var entry)) { ReadConfigEntryCache(value2, entry); } else { value2.Reset(Amrv.ConfigurableCompany.API.ChangeReason.READ_FROM_FILE); } } return; } } foreach (CConfig value3 in CConfig.Storage.Values) { value3.Reset(Amrv.ConfigurableCompany.API.ChangeReason.READ_FROM_FILE); } } private static void ApplyMetadata(CCFGFile cfg) { cfg.AddMetadata("VERSION", "2"); if (CCache.UsedSeed != null) { cfg.AddMetadata("Seed", CCache.UsedSeed); } } private static void ReadConfigEntryCache(CConfig config, CCFGFile.CCFGEntry entry) { config.DeserializeValue(in entry.Value, Amrv.ConfigurableCompany.API.ChangeReason.READ_FROM_FILE); if (entry.Metadata.TryGetValue("enabled", out var value)) { config.Enabled = value.ToLower().Equals("true"); } } private static void WriteConfigEntryCache(CConfig config, CCFGFile file) { if (config.SerializeValue(out var data)) { file.AddEntry(config.ID, data, new Dictionary<string, string> { ["enabled"] = config.Enabled.ToString() }); } } } internal static class IOSections { private static readonly CCATFile File = new CCATFile(Path.Combine(ConfigurableCompanyPlugin.DataFolder, "sections.ccat")); public static void Load() { File.Read(); } public static void Save() { File.Write(); } public static bool GetOpenState(CSection section) { if (File.TryGetState(section.ID, out var state)) { return state; } return false; } public static void SetOpenState(CSection section, bool open) { File.SetState(section.ID, open); } } } namespace Amrv.ConfigurableCompany.Core.Extensions { public static class DictionaryExtensions { public static ReadonlyDictionary<K, V> AsReadOnly<K, V>(this Dictionary<K, V> dictionary) { return new ReadonlyDictionary<K, V>(dictionary); } } public static class GameObjectExtensions { public static GameObject FindChild(this GameObject gameObject, string child) { Transform obj = gameObject.transform.Find(child); return ((obj != null) ? ((Component)obj).gameObject : null) ?? null; } public static GameObject GetChild(this GameObject gameObject, int index) { Transform child = gameObject.transform.GetChild(index); return ((child != null) ? ((Component)child).gameObject : null) ?? null; } public static GameObject GetChild(this GameObject gameObject, params int[] indexes) { Transform val = gameObject.transform; for (int i = 0; i < indexes.Length; i++) { val = ((val != null) ? val.GetChild(indexes[i]) : null) ?? null; } return ((val != null) ? ((Component)val).gameObject : null) ?? null; } public static void AddComponent<T>(this GameObject gameObject, out T addedComponent) where T : Component { addedComponent = gameObject.AddComponent<T>(); } } public static class RandomExtensions { public static ulong NextULong(this Random rng) { byte[] array = new byte[8]; rng.NextBytes(array); return BitConverter.ToUInt64(array, 0); } public static ulong NextULong(this Random rng, ulong max, bool inclusiveUpperBound = false) { return rng.NextULong(0uL, max, inclusiveUpperBound); } public static ulong NextULong(this Random rng, ulong min, ulong max, bool inclusiveUpperBound = false) { ulong num = max - min; if (inclusiveUpperBound) { if (num == ulong.MaxValue) { return rng.NextULong(); } num++; } if (num == 0) { throw new ArgumentOutOfRangeException("Max must be greater than min when inclusiveUpperBound is false, and greater than or equal to when true", "max"); } ulong num2 = ulong.MaxValue - ulong.MaxValue % num; ulong num3; do { num3 = rng.NextULong(); } while (num3 > num2); return num3 % num + min; } public static long NextLong(this Random rng) { byte[] array = new byte[8]; rng.NextBytes(array); return BitConverter.ToInt64(array, 0); } public static long NextLong(this Random rng, long max, bool inclusiveUpperBound = false) { return rng.NextLong(long.MinValue, max, inclusiveUpperBound); } public static long NextLong(this Random rng, long min, long max, bool inclusiveUpperBound = false) { ulong num = (ulong)(max - min); if (inclusiveUpperBound) { if (num == ulong.MaxValue) { return rng.NextLong(); } num++; } if (num == 0) { throw new ArgumentOutOfRangeException("Max must be greater than min when inclusiveUpperBound is false, and greater than or equal to when true", "max"); } ulong num2 = ulong.MaxValue - ulong.MaxValue % num; ulong num3; do { num3 = rng.NextULong(); } while (num3 > num2); return (long)(num3 % num) + min; } public static double NextDouble(this Random random, double minValue, double maxValue) { return random.NextDouble() * (maxValue - minValue) + minValue; } public static bool NextBool(this Random random) { return random.Next() % 2 == 0; } public static long Gaussian(this Random random, long expected, double deviation) { double d = 1.0 - random.NextDouble(); double num = 1.0 - random.NextDouble(); return (long)(Math.Sqrt(-2.0 * Math.Log(d)) * Math.Cos(Math.PI * 2.0 * num) * deviation + (double)expected); } public static double Gaussian(this Random random, double expected, double deviation) { double d = 1.0 - random.NextDouble(); double num = 1.0 - random.NextDouble(); return Math.Sqrt(-2.0 * Math.Log(d)) * Math.Cos(Math.PI * 2.0 * num) * deviation + expected; } } } namespace Amrv.ConfigurableCompany.Core.Display { public static class GlobalCanvas { private static GameObject _canvasObject; private static Canvas _canvas; private static CanvasScaler _canvasScaler; private static EventSystem _eventSystem; private static GraphicRaycaster _raycaster; private static object _creationLock = new object(); private static bool _created = false; public static Canvas Instance { get { lock (_creationLock) { if (!_created || (Object)(object)_canvas == (Object)null) { Destroy(); Create(); } return _canvas; } } } public static void Create() { //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Expected O, but got Unknown lock (_creationLock) { if (!_created) { _canvasObject = new GameObject("ConfigurableCompanyCanvas", new Type[4] { typeof(Canvas), typeof(CanvasScaler), typeof(LifecycleListener), typeof(GraphicRaycaster) }); Object.DontDestroyOnLoad((Object)(object)_canvasObject); _canvas = _canvasObject.GetComponent<Canvas>(); _canvasScaler = _canvasObject.GetComponent<CanvasScaler>(); _raycaster = _canvasObject.GetComponent<GraphicRaycaster>(); _canvasObject.GetComponent<LifecycleListener>().DestroyEvent += Destroy; _canvas.renderMode = (RenderMode)0; _canvas.pixelPerfect = true; _canvas.sortingOrder = 0; _canvasScaler.uiScaleMode = (ScaleMode)0; _canvasScaler.scaleFactor = 1.55f; _canvasScaler.referencePixelsPerUnit = 1f; _raycaster.blockingObjects = (BlockingObjects)1; _created = true; } } } public static void Destroy() { lock (_creationLock) { if (_created) { Object.Destroy((Object)(object)_canvasObject); _canvas = null; _canvasObject = null; _canvasScaler = null; _created = false; } } } } internal class MenuBind { private static MenuBind _instance; private readonly Reference<MenuBind> CurrentBind = new Reference<MenuBind>(); public readonly Reference<MenuToggle> Toggler = new Reference<MenuToggle>(); public readonly Reference<MenuPages> Pages = new Reference<MenuPages>(); public readonly Reference<MenuButtons> Buttons = new Reference<MenuButtons>(); public readonly Reference<MenuTooltip> Tooltip = new Reference<MenuTooltip>(); public readonly Reference<MenuCategories> Categories = new Reference<MenuCategories>(); public readonly Reference<MenuSections> Sections = new Reference<MenuSections>(); public readonly Reference<MenuConfigs> Configs = new Reference<MenuConfigs>(); public readonly Reference<MenuPresets> Presets = new Reference<MenuPresets>(); protected GameObject Container { get; private set; } public GameObject Overlay { get; private set; } public GameObject ShowMenu { get; private set; } public GameObject Menu { get; private set; } protected GameObject FileName { get; private set; } protected TextMeshProUGUI FileText { get; private set; } protected TextMeshProUGUI BetaText { get; private set; } public string Filename { get { return ((TMP_Text)FileText).text; } set { FileName.SetActive(!string.IsNullOrEmpty(value)); ((TMP_Text)FileText).SetText(value, true); } } public static IEnumerator Create(Transform parent) { if (_instance == null || (Object)(object)_instance.Container == (Object)null) { _instance = new MenuBind(parent); yield return null; yield return _instance.UpdateMenu(); } else { ConfigurableCompanyPlugin.Warn("Can't create MenuBind while there is an existing one"); } _instance.Toggler.Item.Open = false; _instance.Toggler.Item.Visible = false; _instance.Filename = GameNetworkManager.Instance.currentSaveFileName; MenuLoader.GetInstance().Fill = 1f; } public static MenuBind GetInstance() { return _instance; } private MenuBind(Transform parent) { //IL_0206: Unknown result type (might be due to invalid IL or missing references) //IL_0210: Expected O, but got Unknown MenuLoader instance = MenuLoader.GetInstance(); ConfigurableCompanyPlugin.Debug("[MenuBind] Preparing menu"); instance.Text = "Creating menu<br>Preparing menu..."; instance.Fill = 0.1f; MenuEventRouter.OnAction_PrepareMenu(); ConfigurableCompanyPlugin.Debug("[MenuBind] Instantiating container"); instance.Text = "Creating menu<br>Instantiating container..."; instance.Fill = 0.05f; Container = Object.Instantiate<GameObject>(MenuPrefabs.Menu); Container.SetActive(false); ((Object)Container).name = "Configuration menu"; Container.transform.SetParent(parent, false); Container.AddComponent<LifecycleListener>().DestroyEvent += Event_OnDestroy; instance.Fill = 0.1f; Overlay = ((Component)Container.transform.Find("Overlay")).gameObject; ShowMenu = ((Component)Container.transform.Find("Show menu")).gameObject; Menu = ((Component)Container.transform.Find("Menu")).gameObject; instance.Fill = 0.12f; FileName = Menu.FindChild("Info/File name"); FileText = FileName.FindChild("Area/Text").GetComponent<TextMeshProUGUI>(); instance.Fill = 0.135f; Menu.FindChild("Beta").AddComponent<RegionButton>().OnMouseClick += OnIssuesButtonClick; ((UnityEvent)Menu.FindChild("Help").GetComponent<Button>().onClick).AddListener(new UnityAction(OnHelpButtonClick)); BetaText = Menu.FindChild("Beta").GetComponent<TextMeshProUGUI>(); CurrentBind.Item = this; instance.Text = "Creating menu<br>Creating Toggler..."; instance.Fill = 0.15f; ConfigurableCompanyPlugin.Debug("[MenuBind] Creating 'Toggler'"); Toggler.Item = new MenuToggle(CurrentBind, Container); instance.Text = "Creating menu<br>Creating Pages..."; instance.Fill = 0.2f; ConfigurableCompanyPlugin.Debug("[MenuBind] Creating 'Pages'"); Pages.Item = new MenuPages(CurrentBind); instance.Text = "Creating menu<br>Creating Buttons..."; instance.Fill = 0.24f; ConfigurableCompanyPlugin.Debug("[MenuBind] Creating 'Buttons'"); Buttons.Item = new MenuButtons(CurrentBind); instance.Text = "Creating menu<br>Creating Tooltip..."; instance.Fill = 0.29f; ConfigurableCompanyPlugin.Debug("[MenuBind] Creating 'Tooltip'"); Tooltip.Item = new MenuTooltip(CurrentBind); instance.Text = "Creating menu<br>Creating Categories..."; instance.Fill = 0.33f; ConfigurableCompanyPlugin.Debug("[MenuBind] Creating 'Categories'"); Categories.Item = new MenuCategories(CurrentBind); instance.Text = "Creating menu<br>Creating Sections..."; instance.Fill = 0.38f; ConfigurableCompanyPlugin.Debug("[MenuBind] Creating 'Sections'"); Sections.Item = new MenuSections(CurrentBind); instance.Text = "Creating menu<br>Creating Configs..."; instance.Fill = 0.42f; ConfigurableCompanyPlugin.Debug("[MenuBind] Creating 'Configs'"); Configs.Item = new MenuConfigs(CurrentBind); instance.Text = "Creating menu<br>Creating Presets..."; instance.Fill = 0.49f; ConfigurableCompanyPlugin.Debug("[MenuBind] Creating 'Presets'"); Presets.Item = new MenuPresets(CurrentBind); } private IEnumerator UpdateMenu() { MenuLoader loader = MenuLoader.GetInstance(); loader.Text = "Populating menu<br>Updating Pages..."; loader.Fill = 0.5f; yield return null; ConfigurableCompanyPlugin.Debug("[MenuBind] Updating 'Pages'"); yield return Pages.Item.UpdateContent(); loader.Fill = 0.54f; yield return null; yield return Pages.Item.UpdateSelf(); loader.Fill = 0.59f; yield return null; loader.Text = "Populating menu<br>Updating Categories..."; ConfigurableCompanyPlugin.Debug("[MenuBind] Updating 'Categories'"); yield return Categories.Item.UpdateContent(); loader.Fill = 0.62f; yield return null; yield return Categories.Item.UpdateSelf(); loader.Fill = 0.66f; yield return null; loader.Text = "Populating menu<br>Updating Sections..."; ConfigurableCompanyPlugin.Debug("[MenuBind] Updating 'Sections'"); yield return Sections.Item.UpdateContent(); loader.Fill = 0.7f; yield return null; yield return Sections.Item.UpdateSelf(); loader.Fill = 0.74f; yield return null; loader.Text = "Populating menu<br>Updating Configs (0%)..."; ConfigurableCompanyPlugin.Debug("[MenuBind] Updating 'Configs' 1/2"); yield return Configs.Item.UpdateContent(); loader.Fill = 0.85f; yield return null; loader.Text = "Populating menu<br>Updating Config holder..."; ConfigurableCompanyPlugin.Debug("[MenuBind] Updating 'Configs' 2/2"); yield return Configs.Item.UpdateSelf(); loader.Fill = 0.89f; yield return null; loader.Text = "Populating menu<br>Updating Presets..."; ConfigurableCompanyPlugin.Debug("[MenuBind] Updating 'Presets'"); yield return Presets.Item.UpdateContent(); loader.Fill = 0.92f; yield return null; yield return Presets.Item.UpdateSelf(); loader.Fill = 0.96f; yield return null; ConfigurableCompanyPlugin.Debug("[MenuBind] Menu created"); MenuEventRouter.OnAction_CreateMenu(); loader.Fill = 0.99f; yield return null; } private void OnHelpButtonClick() { Application.OpenURL("https://github.com/TheAnsuz/Lethal-Company-Configurable-Company-API/wiki/user_usage"); } private void OnIssuesButtonClick(object sender, PointerEventData e) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) if (TMP_TextUtilities.FindIntersectingLink((TMP_Text)(object)BetaText, e.pointerPressRaycast.worldPosition, (Camera)null) != -1) { Application.OpenURL("https://github.com/TheAnsuz/Lethal-Company-Configurable-Company-API/issues/new/choose"); } } private void Event_OnDestroy() { MenuEventRouter.OnAction_DestroyMenu(); } internal void Destroy() { ConfigurableCompanyPlugin.Debug("[Destroy] MenuBind deletion in progress"); Toggler.Item.Destroy(); Toggler.Break(); Pages.Item.Destroy(); Pages.Break(); Buttons.Item.Destroy(); Buttons.Break(); Tooltip.Item.Destroy(); Tooltip.Break(); Categories.Item.Destroy(); Categories.Break(); Sections.Item.Destroy(); Sections.Break(); Configs.Item.Destroy(); Configs.Break(); Presets.Item.Destroy(); Presets.Break(); FileText = null; BetaText = null; Object.Destroy((Object)(object)Overlay); Overlay = null; Object.Destroy((Object)(object)ShowMenu); ShowMenu = null; Object.Destroy((Object)(object)Menu); Menu = null; Object.Destroy((Object)(object)FileName); FileName = null; Object.Destroy((Object)(object)Container); Container = null; CurrentBind.Break(); _instance = null; } ~MenuBind() { ConfigurableCompanyPlugin.Debug("[Destroy] MenuBind deleted"); } } internal static class MenuController { public delegate IEnumerator AfterCreationProcess(MenuManager manager); private static MenuBind Instance; private static GameObject _creator; private static CoroutinePool _pool; private static AfterCreationProcess _afterCreation; public static void AfterCreation(AfterCreationProcess action) { _afterCreation = (AfterCreationProcess)Delegate.Combine(_afterCreation, action); } public static void Create(GameObject parent, MenuManager manager) { //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Expected O, but got Unknown _creator = new GameObject("Configurable company menu creator", new Type[1] { typeof(CoroutinePool) }); _pool = _creator.GetComponent<CoroutinePool>(); ((MonoBehaviour)_pool).StartCoroutine(CreateAsync(parent, manager, _pool)); } public static void DestroyIfCreating() { if ((Object)(object)_pool != (Object)null) { ((MonoBehaviour)_pool).StopAllCoroutines(); _pool = null; } Object.Destroy((Object)(object)_creator); _creator = null; } private static IEnumerator CreateAsync(GameObject parent, MenuManager manager, CoroutinePool creatorPool) { MenuLoader.GetInstance().Visible = true; MenuLoader.GetInstance().Fill = 0f; MenuLoader.GetInstance().Text = "Creating menu"; yield return MenuBind.Create(parent.transform); Instance = MenuBind.GetInstance(); MenuLoader.GetInstance().Visible = true; MenuLoader.GetInstance().Fill = 1f; MenuLoader.GetInstance().Text = "Activating"; yield return null; SetVisible(manager.HostSettingsScreen.activeSelf); Instance.Toggler.Item.Open = false; MenuLoader.GetInstance().Visible = false; if (_afterCreation != null) { yield return _afterCreation(manager); } yield return null; Object.Destroy((Object)(object)((Component)creatorPool).gameObject, 5f); } public static bool IsLocked() { return Instance?.Toggler.Item.Locked ?? false; } public static void SetLocked(bool locked) { if (Instance != null) { Instance.Toggler.Item.Locked = locked; } } public static void SetVisible(bool visible) { if (Instance != null) { Instance.Toggler.Item.Visible = visible; } } public static void SetCurrentFileName(string filename) { if (Instance != null) { Instance.Filename = filename; } } public static void SetRandomizerDetails(InfoProvider info) { if (Instance != null) { Instance.Buttons.Item.SetRandomizerDetails(info); } } public static void SetCurrentPage(CPage page) { if (Instance != null) { Instance.Pages.Item.CurrentPage = page; } } public static void AddPage(CPage page) { if (Instance != null) { Instance.Pages.Item.AddPage(page); } } public static void AddCategory(CCategory category) { if (Instance != null) { Instance.Categories.Item.AddCategory(category); } } public static void AddSection(CSection section) { if (Instance != null) { Instance.Sections.Item.AddSection(section); } } public static void AddConfig(CConfig config) { if (Instance != null) { Instance.Configs.Item.AddConfig(config); } } public static void RefreshConfig(CConfig config) { if (Instance != null) { Instance.Configs.Item.Refresh(config); } } public static void SaveConfigs() { if (Instance != null) { Instance.Configs.Item.SaveToConfig(); } } public static void LoadConfigs() { if (Instance != null) { Instance.Configs.Item.LoadFromConfig(); } } public static void UpdateConfig(CConfig config, Amrv.ConfigurableCompany.API.ChangeReason reason) { if (Instance != null) { if (reason == Amrv.ConfigurableCompany.API.ChangeReason.USER_RESET || reason == Amrv.ConfigurableCompany.API.ChangeReason.SCRIPT_RESET) { Instance.Configs.Item.ReceiveReset(config); } else { Instance.Configs.Item.Refresh(config); } } } public static void TriggerToggleConfig(CConfig config, bool enabled) { if (Instance != null) { Instance.Configs.Item.ReceiveToggle(config, enabled); } } public static void Destroy() { if (Instance != null) { Instance.Destroy(); Instance = null; } } public static void RefreshPresets() { if (Instance != null) { Instance.Presets.Item.UpdateContentFull(); } } public static void UpdateSeedFromCache() { ConfigurableCompanyPlugin.Debug("Trying to update seed info with cached seed"); if (Instance != null) { if (CCache.UsedSeed == null) { ConfigurableCompanyPlugin.Debug("Invalid cached seed for update: " + CCache.UsedSeed); return; } InfoProvider infoProvider = InfoProvider.Create(CCache.UsedSeed, SpecialSeed.GetSpecialSeed(CCache.UsedSeed)); SetRandomizerDetails(infoProvider); ConfigurableCompanyPlugin.Debug("Updated seed from " + (infoProvider.IsSpecialSeed ? "Special seed" : (infoProvider.IsChallenge ? "Challenge seed" : "Normal seed")) + ": " + infoProvider.SeedString); } } } internal static class MenuEventRouter { public static void OnClick_Save() { ConfigurableCompanyPlugin.Debug("MenuEventRouter > OnClick | Save"); MenuController.SaveConfigs(); IOController.SetConfigCache(); IOController.SaveConfigs(); CEvents.MenuEvents.Save.Invoke(); } public static void OnClick_Reset() { ConfigurableCompanyPlugin.Debug("MenuEventRouter > OnClick | Reset"); foreach (CConfig value in CConfig.Storage.Values) { value.Reset(Amrv.ConfigurableCompany.API.ChangeReason.USER_RESET); } IOController.SetConfigCache(); IOController.SaveConfigs(); CEvents.MenuEvents.Reset.Invoke(); } public static void OnClick_Restore() { ConfigurableCompanyPlugin.Debug("MenuEventRouter > OnClick | Restore"); MenuController.LoadConfigs(); CEvents.MenuEvents.Restore.Invoke(); } public static void OnClick_Copy() { ConfigurableCompanyPlugin.Debug("MenuEventRouter > OnClick | Copy"); Clipboard.CopyToClipboard(); CEvents.MenuEvents.Copy.Invoke(); } public static void OnClick_Paste() { ConfigurableCompanyPlugin.Debug("MenuEventRouter > OnClick | Paste"); Clipboard.PasteFromClipboard(); CEvents.MenuEvents.Paste.Invoke(); } public static void OnClick_Randomize(string seed) { ConfigurableCompanyPlugin.Debug("MenuEventRouter > OnClick | Randomize (" + seed + ")"); if (seed == null || seed == "") { foreach (CConfig value in CConfig.Storage.Values) { value.Reset(Amrv.ConfigurableCompany.API.ChangeReason.USER_RANDOMIZED); } CEvents.MenuEvents.Randomize.InvokeFull(new CEventRandomize(RNGProvider.Static, InfoProvider.Default)); CCache.UsedSeed = ""; MenuController.SetRandomizerDetails(InfoProvider.Default); return; } InfoProvider infoProvider = InfoProvider.Create(seed, SpecialSeed.GetSpecialSeed(seed)); RNGProvider rNGProvider = (infoProvider.IsSpecialSeed ? new RNGProvider(infoProvider.SpecialSeed.Seed) : new RNGProvider(RandomSeedParser.FromSeed(seed))); CCache.UsedSeed = infoProvider.SeedString; MenuController.SetRandomizerDetails(infoProvider); CEvents.MenuEvents.Randomize.InvokeFull(new CEventRandomize(rNGProvider, infoProvider)); List<CConfig> list = new List<CConfig>(); foreach (CConfig value2 in CConfig.Storage.Values) { try { value2.Randomize(rNGProvider, infoProvider, Amrv.ConfigurableCompany.API.ChangeReason.USER_RANDOMIZED); } catch (Exception data) { list.Add(value2); ConfigurableCompanyPlugin.Error(data); } } if (list.Count > 0) { MenuPopup.Show("ERROR", $"Unable to randomize all configs ({list.Count} errors)", MenuPopup.NO_ACTION, null); } } public static void OnClick_ShowPage(CPage page) { ConfigurableCompanyPlugin.Debug("MenuEventRouter > OnClick | ShowPage (" + page.Name + ")"); MenuController.SetCurrentPage(page); CEvents.MenuEvents.ChangePage.InvokeFull(new CEventChangePage(page)); } public static void OnAction_PrepareMenu() { ConfigurableCompanyPlugin.Debug("MenuEventRouter > OnAction | Prepare"); CEvents.MenuEvents.Prepare.InvokeFull(); } public static void OnAction_CreateMenu() { ConfigurableCompanyPlugin.Debug("MenuEventRouter > OnAction | Create"); CEvents.MenuEvents.Create.InvokeFull(); } public static void OnAction_DestroyMenu() { ConfigurableCompanyPlugin.Debug("MenuEventRouter > OnAction | Destroy"); CEvents.MenuEvents.Destroy.InvokeFull(); } public static void OnClick_ToggleMenu(bool open) { ConfigurableCompanyPlugin.Debug("MenuEventRouter > OnClick | Toggle (" + (open ? "Open" : "Close") + ")"); CEvents.MenuEvents.Toggle.InvokeFull(new CEventMenuToggle(open)); } public static void OnClick_PresetCreate(string name) { ConfigurableCompanyPlugin.Debug("MenuEventRouter > OnClick | Preset create | name: " + name); Presets.Create(name); } public static void OnClick_PresetLoad(string name) { ConfigurableCompanyPlugin.Debug("MenuEventRouter > OnClick | Preset load | name: " + name); Presets.Stablish(name); } public static void OnClick_PresetSave(string name) { ConfigurableCompanyPlugin.Debug("MenuEventRouter > OnClick | Preset save | name: " + name); Presets.Update(name); } public static void OnClick_PresetDelete(string name) { ConfigurableCompanyPlugin.Debug("MenuEventRouter > OnClick | Preset remove |