Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of ConfigurableCompany v3.7.0
Amrv.ConfigurableCompany.dll
Decompiled 2 years 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 |