using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Jotunn.Entities; using Jotunn.Managers; using Microsoft.CodeAnalysis; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: AssemblyTitle("ConfigurationsForEveryone")] [assembly: AssemblyDescription("Adds server-synced BepInEx configs for items, pieces and creatures of Jotunn-based content mods that ship without any")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("ConfigurationsForEveryone")] [assembly: AssemblyCopyright("Copyright © 2026")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("b7e2c1d4-9a8f-4c3e-bd21-7f0a4e6d2c91")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: AssemblyVersion("1.0.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [CompilerGenerated] [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 ConfigurationsForEveryone { [BepInPlugin("IAmOnTheInternetAndItIsScary.ConfigurationsForEveryone", "ConfigurationsForEveryone", "1.0.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] public class ConfigurationsForEveryonePlugin : BaseUnityPlugin { [HarmonyPatch(typeof(FejdStartup), "Awake")] private static class FejdStartupPatch { private static bool built; [HarmonyPostfix] private static void Postfix() { if (!built) { built = true; ConfigBuilder.BuildAll("FejdStartup.Awake"); } } } internal const string ModName = "ConfigurationsForEveryone"; internal const string ModGUID = "IAmOnTheInternetAndItIsScary.ConfigurationsForEveryone"; internal const string ModVersion = "1.0.0"; internal static readonly ManualLogSource Log = Logger.CreateLogSource("ConfigurationsForEveryone"); internal static ConfigEntry? DebugLogging; private readonly Harmony _harmony = new Harmony("IAmOnTheInternetAndItIsScary.ConfigurationsForEveryone"); public void Awake() { DebugLogging = ((BaseUnityPlugin)this).Config.Bind("General", "Debug Logging", false, "Log every config value as it is applied to the game so you can confirm changes take effect"); CommandManager.Instance.AddConsoleCommand((ConsoleCommand)(object)new RefreshCommand()); _harmony.PatchAll(Assembly.GetExecutingAssembly()); Debug("ConfigurationsForEveryone 1.0.0 loaded, waiting for the main menu to discover content"); } internal static void Debug(string message) { if (DebugLogging != null && DebugLogging.Value) { Log.LogInfo((object)message); } } } internal sealed class DiscoveredMod { public string Guid = ""; public string Name = ""; public string Version = ""; public readonly List Items = new List(); public readonly List Pieces = new List(); public readonly List Creatures = new List(); public int Count => Items.Count + Pieces.Count + Creatures.Count; } internal static class Discovery { private const BindingFlags InstanceNonPublic = BindingFlags.Instance | BindingFlags.NonPublic; public static int LastItemCount { get; private set; } public static int LastPieceCount { get; private set; } public static int LastCreatureCount { get; private set; } public static int LastUnattributed { get; private set; } public static List Run() { Dictionary dictionary = new Dictionary(StringComparer.OrdinalIgnoreCase); int num = 0; int num2 = 0; int num3 = 0; int num4 = 0; foreach (CustomItem item in ReadRegistry(typeof(ItemManager), ItemManager.Instance, "Items")) { num++; DiscoveredMod mod = GetMod(dictionary, ((CustomEntity)item).SourceMod); if (mod == null) { num4++; } else { mod.Items.Add(item); } } foreach (CustomPiece item2 in ReadRegistry(typeof(PieceManager), PieceManager.Instance, "Pieces")) { num2++; DiscoveredMod mod2 = GetMod(dictionary, ((CustomEntity)item2).SourceMod); if (mod2 == null) { num4++; } else { mod2.Pieces.Add(item2); } } foreach (CustomCreature item3 in ReadRegistry(typeof(CreatureManager), CreatureManager.Instance, "Creatures")) { num3++; DiscoveredMod mod3 = GetMod(dictionary, ((CustomEntity)item3).SourceMod); if (mod3 == null) { num4++; } else { mod3.Creatures.Add(item3); } } LastItemCount = num; LastPieceCount = num2; LastCreatureCount = num3; LastUnattributed = num4; if (num4 > 0) { ConfigurationsForEveryonePlugin.Log.LogWarning((object)$"{num4} registered entries had no resolvable source mod and were skipped"); } return (from m in dictionary.Values where m.Count > 0 orderby m.Name select m).ToList(); } private static DiscoveredMod? GetMod(Dictionary byGuid, BepInPlugin? sourceMod) { if (sourceMod == null || string.IsNullOrEmpty(sourceMod.GUID)) { return null; } if (!byGuid.TryGetValue(sourceMod.GUID, out DiscoveredMod value)) { value = new DiscoveredMod { Guid = sourceMod.GUID, Name = (string.IsNullOrEmpty(sourceMod.Name) ? sourceMod.GUID : sourceMod.Name), Version = (sourceMod.Version?.ToString() ?? "0.0.0") }; byGuid[sourceMod.GUID] = value; } return value; } private static IEnumerable ReadRegistry(Type managerType, object instance, string fieldName) where T : class { FieldInfo field = managerType.GetField(fieldName, BindingFlags.Instance | BindingFlags.NonPublic); if (field == null) { ConfigurationsForEveryonePlugin.Log.LogWarning((object)("Could not find " + managerType.Name + "." + fieldName + " - Jotunn version may have changed")); yield break; } object value = field.GetValue(instance); if (!(value is IEnumerable registry)) { yield break; } DictionaryEntry dictionaryEntry = default(DictionaryEntry); foreach (object entry in registry) { object value2 = entry; int num; if (entry is DictionaryEntry) { dictionaryEntry = (DictionaryEntry)entry; num = 1; } else { num = 0; } if (num != 0) { value2 = dictionaryEntry.Value; } else { PropertyInfo valueProperty = entry.GetType().GetProperty("Value"); if (valueProperty != null && entry.GetType().IsGenericType) { value2 = valueProperty.GetValue(entry); } } if (value2 is T typed) { yield return typed; } dictionaryEntry = default(DictionaryEntry); } } } internal sealed class ModConfig { public readonly ConfigFile File; private readonly BepInPlugin _metadata; private readonly Dictionary _displayNames = new Dictionary(StringComparer.Ordinal); public ModConfig(DiscoveredMod mod) { //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Expected O, but got Unknown //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Expected O, but got Unknown string text = Path.Combine(Paths.ConfigPath, "ConfigurationsForEveryone"); Directory.CreateDirectory(text); string path = Sanitize(mod.Guid) + ".cfg"; _metadata = new BepInPlugin(mod.Guid, mod.Name, mod.Version); File = new ConfigFile(Path.Combine(text, path), true, _metadata) { SaveOnConfigSet = false }; File.SettingChanged += OnSettingChanged; RegisterForSync(); } private void OnSettingChanged(object sender, SettingChangedEventArgs args) { ConfigEntryBase changedSetting = args.ChangedSetting; ConfigurationsForEveryonePlugin.Debug($"[{_metadata.Name}] {changedSetting.Definition.Section} > {changedSetting.Definition.Key} changed to '{changedSetting.BoxedValue}', applied and synced"); } public void SetDisplayName(string section, string displayName) { if (!string.IsNullOrEmpty(displayName) && displayName != section) { _displayNames[section] = displayName; } } public ConfigEntry Bind(string section, string key, T value, string description, AcceptableValueBase? acceptableValues = null, int order = 0, Action? customDrawer = null) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Expected O, but got Unknown //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Expected O, but got Unknown ConfigurationManagerAttributes val = new ConfigurationManagerAttributes { IsAdminOnly = true, Order = order }; if (_displayNames.TryGetValue(section, out string value2)) { val.Category = value2 + " (" + section + ")"; } if (customDrawer != null) { val.CustomDrawer = customDrawer; } return File.Bind(section, key, value, new ConfigDescription(description, acceptableValues, new object[1] { val })); } public void Save() { File.SaveOnConfigSet = true; File.Save(); } private void RegisterForSync() { try { SynchronizationManager.Instance.RegisterCustomConfig(File); } catch (Exception ex) { ConfigurationsForEveryonePlugin.Log.LogWarning((object)("Could not register " + _metadata.Name + " config for server sync: " + ex.Message)); } } public void CreateMenuProxy(GameObject host) { try { ProxyPlugin proxyPlugin = host.AddComponent(); OverwriteBackingField(typeof(BaseUnityPlugin), proxyPlugin, "Config", File); PluginInfo info = ((BaseUnityPlugin)proxyPlugin).Info; if (info != null) { OverwriteProperty(typeof(PluginInfo), info, "Metadata", _metadata); } } catch (Exception ex) { ConfigurationsForEveryonePlugin.Log.LogWarning((object)("Could not surface " + _metadata.Name + " in the configuration manager: " + ex.Message)); } } private static void OverwriteBackingField(Type owner, object instance, string propertyName, object value) { owner.GetField("<" + propertyName + ">k__BackingField", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(instance, value); } private static void OverwriteProperty(Type owner, object instance, string propertyName, object value) { MethodInfo methodInfo = owner.GetProperty(propertyName, BindingFlags.Instance | BindingFlags.Public)?.GetSetMethod(nonPublic: true); if (methodInfo != null) { methodInfo.Invoke(instance, new object[1] { value }); } else { OverwriteBackingField(owner, instance, propertyName, value); } } private static string Sanitize(string name) { return Path.GetInvalidFileNameChars().Aggregate(name, (string current, char invalid) => current.Replace(invalid, '_')); } } [BepInPlugin("IAmOnTheInternetAndItIsScary.ConfigurationsForEveryone.Proxy", "ConfigurationsForEveryone Proxy", "1.0.0")] [BepInProcess("ConfigurationsForEveryone.ProxyNeverRuns")] internal class ProxyPlugin : BaseUnityPlugin { } internal static class ConfigBuilder { private static readonly HashSet Configured = new HashSet(StringComparer.OrdinalIgnoreCase); private static GameObject? _proxyHost; public static void BuildAll(string trigger) { try { List list = Discovery.Run(); if (list.Count == 0) { ConfigurationsForEveryonePlugin.Log.LogInfo((object)$"{trigger}: no RtD content found in the Jotunn registries yet ({Discovery.LastItemCount} item(s), {Discovery.LastPieceCount} piece(s), {Discovery.LastCreatureCount} creature(s) scanned)"); return; } int num = 0; foreach (DiscoveredMod item in list) { if (!Configured.Add(item.Guid)) { continue; } EnsureProxyHost(); ModConfig modConfig = new ModConfig(item); foreach (CustomCreature creature in item.Creatures) { try { Creatures.Bind(modConfig, creature); } catch (Exception ex) { ConfigurationsForEveryonePlugin.Log.LogWarning((object)(item.Name + ": skipped a creature (" + ex.Message + ")")); } } foreach (CustomItem item2 in item.Items) { try { Items.Bind(modConfig, item2); } catch (Exception ex2) { ConfigurationsForEveryonePlugin.Log.LogWarning((object)(item.Name + ": skipped an item (" + ex2.Message + ")")); } } foreach (CustomPiece piece in item.Pieces) { try { Pieces.Bind(modConfig, piece); } catch (Exception ex3) { ConfigurationsForEveryonePlugin.Log.LogWarning((object)(item.Name + ": skipped a piece (" + ex3.Message + ")")); } } modConfig.Save(); modConfig.CreateMenuProxy(_proxyHost); num++; ConfigurationsForEveryonePlugin.Log.LogInfo((object)$"✓ {item.Name}: {item.Items.Count} item(s), {item.Pieces.Count} piece(s), {item.Creatures.Count} creature(s) configured"); } if (num > 0) { ConfigurationsForEveryonePlugin.Log.LogInfo((object)string.Format("✓ Generated synced config files for {0} new mod(s) under config/{1}", num, "ConfigurationsForEveryone")); } } catch (Exception arg) { ConfigurationsForEveryonePlugin.Log.LogError((object)$"Failed to build configs: {arg}"); } } private static void EnsureProxyHost() { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Expected O, but got Unknown if (!Object.op_Implicit((Object)(object)_proxyHost)) { _proxyHost = new GameObject("ConfigurationsForEveryone_Proxies"); Object.DontDestroyOnLoad((Object)(object)_proxyHost); } } } internal static class Appliers { public const string KindItem = "item recipe(s)"; public const string KindPiece = "piece(s)"; public const string KindCreatureSpawn = "creature spawn(s)"; public const string KindCreatureTaming = "creature taming"; public const string KindCreatureDrops = "creature drops"; private static readonly List<(Action Run, string Kind)> Registered = new List<(Action, string)>(); public static void Register(Action applier, string kind) { Registered.Add((applier, kind)); } public static int RunAll() { int num = 0; Dictionary dictionary = new Dictionary(); foreach (var (action, text) in Registered) { try { action(); num++; dictionary[text] = ((!dictionary.TryGetValue(text, out var value)) ? 1 : (value + 1)); } catch (Exception ex) { ConfigurationsForEveryonePlugin.Log.LogWarning((object)("Applier failed (" + text + "): " + ex.Message)); } } if (num > 0) { string text2 = string.Join(", ", from c in dictionary orderby c.Key select $"{c.Value} {c.Key}"); ConfigurationsForEveryonePlugin.Log.LogInfo((object)("Applied config to loaded content: " + text2)); } return num; } } internal sealed class ApplyScheduler : MonoBehaviour { private const float DebounceSeconds = 0.4f; private static ApplyScheduler? _instance; private static readonly Dictionary Pending = new Dictionary(); private static readonly List Due = new List(); public static void Schedule(Action applier) { EnsureInstance(); Pending[applier] = Time.realtimeSinceStartup + 0.4f; } private static void EnsureInstance() { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Expected O, but got Unknown if (!Object.op_Implicit((Object)(object)_instance)) { GameObject val = new GameObject("ConfigurationsForEveryone_ApplyScheduler"); Object.DontDestroyOnLoad((Object)(object)val); _instance = val.AddComponent(); } } private void Update() { if (Pending.Count == 0) { return; } float realtimeSinceStartup = Time.realtimeSinceStartup; Due.Clear(); foreach (KeyValuePair item in Pending) { if (realtimeSinceStartup >= item.Value) { Due.Add(item.Key); } } if (Due.Count == 0) { return; } foreach (Action item2 in Due) { Pending.Remove(item2); try { item2(); } catch (Exception ex) { ConfigurationsForEveryonePlugin.Log.LogWarning((object)("Applier failed: " + ex.Message)); } } ConfigurationsForEveryonePlugin.Debug($"Config edit settled, re-applied {Due.Count} group(s) to prefabs"); } } [HarmonyPatch(typeof(ZNetScene), "Awake")] internal static class ZNetSceneAwakePatch { [HarmonyPostfix] private static void Postfix() { ConfigBuilder.BuildAll("ZNetScene.Awake"); Appliers.RunAll(); } } [HarmonyPatch(typeof(ObjectDB), "Awake")] internal static class ObjectDBAwakePatch { [HarmonyPostfix] private static void Postfix() { ConfigBuilder.BuildAll("ObjectDB.Awake"); Appliers.RunAll(); } } internal static class Reqs { private const string MockPrefix = "JVLmock_"; public static string Localize(string? token, string fallback) { if (string.IsNullOrEmpty(token)) { return fallback; } try { if (Localization.instance == null) { return fallback; } string text = Localization.instance.Localize(token); return (string.IsNullOrWhiteSpace(text) || text.StartsWith("[")) ? fallback : text; } catch { return fallback; } } public static string CleanName(string? prefabName) { if (string.IsNullOrEmpty(prefabName)) { return ""; } return prefabName.StartsWith("JVLmock_") ? prefabName.Substring("JVLmock_".Length) : prefabName; } public static string SerializeRequirements(Requirement[]? requirements, bool includePerLevel = false) { if (requirements == null) { return ""; } return string.Join(",", from r in requirements where r != null && Object.op_Implicit((Object)(object)r.m_resItem) select includePerLevel ? $"{CleanName(((Object)r.m_resItem).name)}:{r.m_amount}:{r.m_amountPerLevel}" : $"{CleanName(((Object)r.m_resItem).name)}:{r.m_amount}"); } public static Requirement[] ParseRequirements(string value) { if (!Object.op_Implicit((Object)(object)ObjectDB.instance) || string.IsNullOrWhiteSpace(value)) { return Array.Empty(); } return (from requirement in (from part in value.Split(new char[1] { ',' }) select part.Trim() into part where part.Length > 0 select part).Select((Func)delegate(string part) { //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Unknown result type (might be due to invalid IL or missing references) string[] array = part.Split(new char[1] { ':' }); string text = CleanName(array[0].Trim()); int result; int num = ((array.Length <= 1 || !int.TryParse(array[1], out result)) ? 1 : result); int result2; int amountPerLevel = ((array.Length > 2 && int.TryParse(array[2], out result2)) ? result2 : num); GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(text); ItemDrop val = ((itemPrefab != null) ? itemPrefab.GetComponent() : null); return ((Object)(object)val == (Object)null) ? ((Requirement)null) : new Requirement { m_resItem = val, m_amount = num, m_amountPerLevel = amountPerLevel, m_recover = true }; }) where requirement != null select (requirement)).ToArray(); } public static string SerializeDrops(List? drops) { if (drops == null) { return ""; } return string.Join(",", from d in drops where d != null && Object.op_Implicit((Object)(object)d.m_prefab) select $"{CleanName(((Object)d.m_prefab).name)}:{d.m_amountMin}-{d.m_amountMax}:{(d.m_chance * 100f).ToString(CultureInfo.InvariantCulture)}"); } public static List ParseDrops(string value) { //IL_015a: Unknown result type (might be due to invalid IL or missing references) //IL_015f: Unknown result type (might be due to invalid IL or missing references) //IL_0167: Unknown result type (might be due to invalid IL or missing references) //IL_016f: Unknown result type (might be due to invalid IL or missing references) //IL_0177: Unknown result type (might be due to invalid IL or missing references) //IL_0185: Unknown result type (might be due to invalid IL or missing references) //IL_018c: Unknown result type (might be due to invalid IL or missing references) //IL_0198: Expected O, but got Unknown List list = new List(); if (!Object.op_Implicit((Object)(object)ZNetScene.instance) || string.IsNullOrWhiteSpace(value)) { return list; } foreach (string item in from s in value.Split(new char[1] { ',' }) select s.Trim() into s where s.Length > 0 select s) { string[] array = item.Split(new char[1] { ':' }); GameObject prefab = ZNetScene.instance.GetPrefab(CleanName(array[0].Trim())); if (Object.op_Implicit((Object)(object)prefab)) { int result = 1; int amountMax = 1; if (array.Length > 1) { string[] array2 = array[1].Split(new char[1] { '-' }); int.TryParse(array2[0], out result); amountMax = ((array2.Length > 1 && int.TryParse(array2[1], out var result2)) ? result2 : result); } float result3 = 100f; if (array.Length > 2) { float.TryParse(array[2], NumberStyles.Float, CultureInfo.InvariantCulture, out result3); } list.Add(new Drop { m_prefab = prefab, m_amountMin = result, m_amountMax = amountMax, m_chance = result3 / 100f, m_onePerPlayer = false, m_levelMultiplier = true }); } } return list; } } internal static class Creatures { private enum SpawnTime { Day, Night, Always } private enum SpawnArea { Center, Edge, Everywhere } private enum ForestSetting { Yes, No, Both } private static readonly FieldRef BaseAiTamableRef = AccessTools.FieldRefAccess("m_tamable"); public static void Bind(ModConfig config, CustomCreature creature) { GameObject prefab = creature.Prefab; if (!((Object)(object)prefab == (Object)null)) { string name = ((Object)prefab).name; Character val = default(Character); config.SetDisplayName(name, prefab.TryGetComponent(ref val) ? Reqs.Localize(val.m_name, name) : name); if (creature.Spawns.Count > 0) { BindSpawn(config, creature, name); } BindTaming(config, prefab, name); BindDrops(config, prefab, name); } } private static void BindSpawn(ModConfig config, CustomCreature creature, string section) { //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) SpawnData val = creature.Spawns[0]; ConfigEntry enabled = config.Bind(section, "Spawn Enabled", val.m_enabled, "Whether this creature spawns naturally in the world", null, 40); ConfigEntry biome = config.Bind(section, "Spawn Biome", val.m_biome, "Biome the creature spawns in", null, 39); ConfigEntry area = config.Bind(section, "Spawn Area", FromBiomeArea(val.m_biomeArea), "Where inside the biome the creature spawns", null, 38); ConfigEntry time = config.Bind(section, "Spawn Time", FromSpawnData(val), "Time of day the creature spawns", null, 37); ConfigEntry maximum = config.Bind(section, "Maximum Count", val.m_maxSpawned, "Maximum number of this creature near the player before spawning stops", null, 36); ConfigEntry interval = config.Bind(section, "Spawn Interval", val.m_spawnInterval, "Seconds between spawn attempts", null, 35); ConfigEntry chance = config.Bind(section, "Spawn Chance", val.m_spawnChance, "Percent chance to spawn on each attempt", (AcceptableValueBase?)(object)new AcceptableValueRange(0f, 100f), 34); ConfigEntry groupMin = config.Bind(section, "Group Size Min", val.m_groupSizeMin, "Minimum number spawned together", null, 33); ConfigEntry groupMax = config.Bind(section, "Group Size Max", val.m_groupSizeMax, "Maximum number spawned together", null, 32); ConfigEntry altitudeMin = config.Bind(section, "Altitude Min", val.m_minAltitude, "Minimum altitude required to spawn", null, 31); ConfigEntry altitudeMax = config.Bind(section, "Altitude Max", val.m_maxAltitude, "Maximum altitude allowed to spawn", null, 30); ConfigEntry oceanMin = config.Bind(section, "Ocean Depth Min", val.m_minOceanDepth, "Minimum ocean depth required to spawn", null, 29); ConfigEntry oceanMax = config.Bind(section, "Ocean Depth Max", val.m_maxOceanDepth, "Maximum ocean depth allowed to spawn", null, 28); ConfigEntry groundOffset = config.Bind(section, "Spawn Altitude", val.m_groundOffset, "Height above the ground the creature spawns at", null, 27); ConfigEntry forest = config.Bind(section, "Forest Condition", FromForest(val), "Whether the creature spawns in forests, outside forests, or both", null, 26); ConfigEntry huntPlayer = config.Bind(section, "Hunt Player", val.m_huntPlayer, "Whether the creature immediately hunts the player after spawning", null, 25); ConfigEntry canHaveStars = config.Bind(section, "Can Have Stars", val.m_maxLevel > 1, "Whether the creature can spawn with stars", null, 24); ConfigEntry globalKey = config.Bind(section, "Required Global Key", val.m_requiredGlobalKey ?? "", "Global key required before the creature spawns", null, 23); ConfigEntry environments = config.Bind(section, "Required Weather", string.Join(",", val.m_requiredEnvironments ?? new List()), "Comma separated weather environment names required to spawn", null, 22); Action applySpawn = ApplySpawn; applySpawn(); Appliers.Register(applySpawn, "creature spawn(s)"); enabled.SettingChanged += delegate { ApplyScheduler.Schedule(applySpawn); }; biome.SettingChanged += delegate { ApplyScheduler.Schedule(applySpawn); }; area.SettingChanged += delegate { ApplyScheduler.Schedule(applySpawn); }; time.SettingChanged += delegate { ApplyScheduler.Schedule(applySpawn); }; maximum.SettingChanged += delegate { ApplyScheduler.Schedule(applySpawn); }; interval.SettingChanged += delegate { ApplyScheduler.Schedule(applySpawn); }; chance.SettingChanged += delegate { ApplyScheduler.Schedule(applySpawn); }; groupMin.SettingChanged += delegate { ApplyScheduler.Schedule(applySpawn); }; groupMax.SettingChanged += delegate { ApplyScheduler.Schedule(applySpawn); }; altitudeMin.SettingChanged += delegate { ApplyScheduler.Schedule(applySpawn); }; altitudeMax.SettingChanged += delegate { ApplyScheduler.Schedule(applySpawn); }; oceanMin.SettingChanged += delegate { ApplyScheduler.Schedule(applySpawn); }; oceanMax.SettingChanged += delegate { ApplyScheduler.Schedule(applySpawn); }; groundOffset.SettingChanged += delegate { ApplyScheduler.Schedule(applySpawn); }; forest.SettingChanged += delegate { ApplyScheduler.Schedule(applySpawn); }; huntPlayer.SettingChanged += delegate { ApplyScheduler.Schedule(applySpawn); }; canHaveStars.SettingChanged += delegate { ApplyScheduler.Schedule(applySpawn); }; globalKey.SettingChanged += delegate { ApplyScheduler.Schedule(applySpawn); }; environments.SettingChanged += delegate { ApplyScheduler.Schedule(applySpawn); }; void ApplySpawn() { //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_02a0: Unknown result type (might be due to invalid IL or missing references) foreach (SpawnData spawn in creature.Spawns) { spawn.m_enabled = enabled.Value; spawn.m_biome = biome.Value; spawn.m_biomeArea = ToBiomeArea(area.Value); spawn.m_maxSpawned = maximum.Value; spawn.m_spawnInterval = interval.Value; spawn.m_spawnChance = chance.Value; spawn.m_groupSizeMin = groupMin.Value; spawn.m_groupSizeMax = groupMax.Value; spawn.m_minAltitude = altitudeMin.Value; spawn.m_maxAltitude = altitudeMax.Value; spawn.m_minOceanDepth = oceanMin.Value; spawn.m_maxOceanDepth = oceanMax.Value; spawn.m_groundOffset = groundOffset.Value; spawn.m_huntPlayer = huntPlayer.Value; spawn.m_maxLevel = ((!canHaveStars.Value) ? 1 : 3); spawn.m_requiredGlobalKey = globalKey.Value; spawn.m_requiredEnvironments = (from s in environments.Value.Split(new char[1] { ',' }) select s.Trim() into s where s.Length > 0 select s).ToList(); SpawnData val2 = spawn; SpawnTime value = time.Value; bool spawnAtNight = (uint)(value - 1) <= 1u; val2.m_spawnAtNight = spawnAtNight; SpawnData val3 = spawn; value = time.Value; spawnAtNight = ((value == SpawnTime.Day || value == SpawnTime.Always) ? true : false); val3.m_spawnAtDay = spawnAtNight; SpawnData val4 = spawn; ForestSetting value2 = forest.Value; spawnAtNight = ((value2 == ForestSetting.Yes || value2 == ForestSetting.Both) ? true : false); val4.m_inForest = spawnAtNight; SpawnData val5 = spawn; value2 = forest.Value; spawnAtNight = (uint)(value2 - 1) <= 1u; val5.m_outsideForest = spawnAtNight; } ConfigurationsForEveryonePlugin.Debug($"[{section}] applied spawn: enabled={enabled.Value} biome={biome.Value} chance={chance.Value} max={maximum.Value}"); } } private static void BindTaming(ModConfig config, GameObject prefab, string section) { //IL_00e8: Unknown result type (might be due to invalid IL or missing references) //IL_00ed: Unknown result type (might be due to invalid IL or missing references) //IL_01a4: Unknown result type (might be due to invalid IL or missing references) Tameable val = default(Tameable); bool value = prefab.TryGetComponent(ref val); float value2 = (Object.op_Implicit((Object)(object)val) ? val.m_fedDuration : 0f); float value3 = (Object.op_Implicit((Object)(object)val) ? val.m_tamingTime : 1800f); bool value4 = Object.op_Implicit((Object)(object)val) && val.m_startsTamed; MonsterAI val2 = default(MonsterAI); string value5 = (prefab.TryGetComponent(ref val2) ? string.Join(",", from i in val2.m_consumeItems where Object.op_Implicit((Object)(object)i) && i.m_itemData != null && Object.op_Implicit((Object)(object)i.m_itemData.m_dropPrefab) select Reqs.CleanName(((Object)i.m_itemData.m_dropPrefab).name)) : ""); Character val3 = default(Character); Faction value6 = (Faction)((!prefab.TryGetComponent(ref val3)) ? 1 : ((int)val3.m_faction)); ConfigEntry canBeTamed = config.Bind(section, "Can Be Tamed", value, "Whether the creature can be tamed", null, 19); ConfigEntry foodItems = config.Bind(section, "Food Items", value5, "Comma separated item names the creature eats to tame", null, 18); ConfigEntry fedDuration = config.Bind(section, "Fed Duration", value2, "Seconds the creature stays fed after eating", null, 17); ConfigEntry tamingTime = config.Bind(section, "Taming Time", value3, "Seconds it takes to fully tame the creature", null, 16); ConfigEntry spawnsTamed = config.Bind(section, "Spawns Tamed", value4, "Whether the creature spawns already tamed", null, 15); ConfigEntry faction = config.Bind(section, "Faction", value6, "Faction the creature belongs to", null, 14); Action applyTaming = ApplyTaming; Appliers.Register(applyTaming, "creature taming"); canBeTamed.SettingChanged += delegate { ApplyScheduler.Schedule(applyTaming); }; foodItems.SettingChanged += delegate { ApplyScheduler.Schedule(applyTaming); }; fedDuration.SettingChanged += delegate { ApplyScheduler.Schedule(applyTaming); }; tamingTime.SettingChanged += delegate { ApplyScheduler.Schedule(applyTaming); }; spawnsTamed.SettingChanged += delegate { ApplyScheduler.Schedule(applyTaming); }; faction.SettingChanged += delegate { ApplyScheduler.Schedule(applyTaming); }; void ApplyTaming() { //IL_021b: Unknown result type (might be due to invalid IL or missing references) //IL_01e1: Unknown result type (might be due to invalid IL or missing references) //IL_01e6: Unknown result type (might be due to invalid IL or missing references) Tameable val4 = prefab.GetComponent(); if (canBeTamed.Value && !Object.op_Implicit((Object)(object)val4)) { val4 = prefab.AddComponent(); BaseAI val5 = default(BaseAI); if (prefab.TryGetComponent(ref val5)) { BaseAiTamableRef.Invoke(val5) = val4; } } else if (!canBeTamed.Value && Object.op_Implicit((Object)(object)val4)) { Object.Destroy((Object)(object)val4); val4 = null; } if (Object.op_Implicit((Object)(object)val4)) { val4.m_fedDuration = fedDuration.Value; val4.m_tamingTime = tamingTime.Value; val4.m_startsTamed = spawnsTamed.Value; } MonsterAI val6 = default(MonsterAI); if (prefab.TryGetComponent(ref val6) && Object.op_Implicit((Object)(object)ObjectDB.instance)) { val6.m_consumeItems = (from drop in (from s in foodItems.Value.Split(new char[1] { ',' }) select s.Trim() into s where s.Length > 0 select s).Select(delegate(string name) { GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(Reqs.CleanName(name)); return (itemPrefab != null) ? itemPrefab.GetComponent() : null; }) where (Object)(object)drop != (Object)null select (drop)).ToList(); } Character val7 = default(Character); if (prefab.TryGetComponent(ref val7)) { val7.m_faction = faction.Value; } ConfigurationsForEveryonePlugin.Debug($"[{section}] applied taming: canBeTamed={canBeTamed.Value} faction={faction.Value} spawnsTamed={spawnsTamed.Value} food='{foodItems.Value}'"); } } private static void BindDrops(ModConfig config, GameObject prefab, string section) { CharacterDrop component = prefab.GetComponent(); string value = (Object.op_Implicit((Object)(object)component) ? Reqs.SerializeDrops(component.m_drops) : ""); ConfigEntry drops = config.Bind(section, "Drops", value, "Comma separated itemName:min-max:chance drops when killed", null, 13, Drawer.Drops); Action applyDrops = ApplyDrops; Appliers.Register(applyDrops, "creature drops"); drops.SettingChanged += delegate { ApplyScheduler.Schedule(applyDrops); }; void ApplyDrops() { if (!Object.op_Implicit((Object)(object)ZNetScene.instance)) { ConfigurationsForEveryonePlugin.Debug("[" + section + "] drops not applied yet: world not loaded"); } else { List list = Reqs.ParseDrops(drops.Value); if (list.Count == 0 && drops.Value.Trim().Length > 0) { ConfigurationsForEveryonePlugin.Log.LogWarning((object)("[" + section + "] drops '" + drops.Value + "' resolved to nothing, leaving existing drops unchanged")); } else { CharacterDrop val = prefab.GetComponent(); if (!Object.op_Implicit((Object)(object)val)) { val = prefab.AddComponent(); } val.m_drops = list; ConfigurationsForEveryonePlugin.Debug($"[{section}] applied {list.Count} drop(s) '{drops.Value}' (visible on next kill)"); } } } } private static SpawnTime FromSpawnData(SpawnData data) { if (data.m_spawnAtDay && data.m_spawnAtNight) { return SpawnTime.Always; } return data.m_spawnAtNight ? SpawnTime.Night : SpawnTime.Day; } private static SpawnArea FromBiomeArea(BiomeArea area) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Invalid comparison between Unknown and I4 //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Invalid comparison between Unknown and I4 if (1 == 0) { } SpawnArea result = (((int)area == 1) ? SpawnArea.Edge : (((int)area != 2) ? SpawnArea.Everywhere : SpawnArea.Center)); if (1 == 0) { } return result; } private static BiomeArea ToBiomeArea(SpawnArea area) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0021: 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_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) if (1 == 0) { } BiomeArea result = (BiomeArea)(area switch { SpawnArea.Center => 2, SpawnArea.Edge => 1, _ => 3, }); if (1 == 0) { } return result; } private static ForestSetting FromForest(SpawnData data) { if (data.m_inForest && data.m_outsideForest) { return ForestSetting.Both; } return (!data.m_inForest) ? ForestSetting.No : ForestSetting.Yes; } } internal static class Items { public static void Bind(ModConfig config, CustomItem item) { GameObject itemPrefab = item.ItemPrefab; if ((Object)(object)itemPrefab == (Object)null) { return; } CustomRecipe recipe = item.Recipe; Recipe recipe2 = ((recipe != null) ? recipe.Recipe : null); string section; ConfigEntry craftable; ConfigEntry craftAmount; ConfigEntry station; ConfigEntry stationLevel; ConfigEntry resources; if (!((Object)(object)recipe2 == (Object)null)) { section = ((Object)itemPrefab).name; ItemDrop component = itemPrefab.GetComponent(); bool flag = Object.op_Implicit((Object)(object)component) && component.m_itemData?.m_shared != null && component.m_itemData.m_shared.m_maxQuality > 1; config.SetDisplayName(section, Reqs.Localize((Object.op_Implicit((Object)(object)component) && component.m_itemData?.m_shared != null) ? component.m_itemData.m_shared.m_name : null, section)); craftable = config.Bind(section, "Craftable", recipe2.m_enabled, "Whether the item can be crafted", null, 40); craftAmount = config.Bind(section, "Craft Amount", recipe2.m_amount, "Number of items produced by a single craft", null, 39); station = config.Bind(section, "Crafting Station", Object.op_Implicit((Object)(object)recipe2.m_craftingStation) ? Reqs.CleanName(((Object)recipe2.m_craftingStation).name) : "", "Crafting station prefab name required to craft, empty for hand crafting", null, 38); stationLevel = config.Bind(section, "Crafting Station Level", recipe2.m_minStationLevel, "Minimum crafting station level required to craft", null, 37); resources = config.Bind(section, "Crafting Costs", Reqs.SerializeRequirements(recipe2.m_resources, flag), flag ? "Comma separated itemName:amount:perUpgradeLevel resources, the third number is added for each upgrade level" : "Comma separated itemName:amount resources required to craft", null, 36, flag ? Drawer.RequirementsWithUpgrade : Drawer.Requirements); Action apply = Apply; Appliers.Register(apply, "item recipe(s)"); craftable.SettingChanged += delegate { ApplyScheduler.Schedule(apply); }; craftAmount.SettingChanged += delegate { ApplyScheduler.Schedule(apply); }; station.SettingChanged += delegate { ApplyScheduler.Schedule(apply); }; stationLevel.SettingChanged += delegate { ApplyScheduler.Schedule(apply); }; resources.SettingChanged += delegate { ApplyScheduler.Schedule(apply); }; } void Apply() { recipe2.m_enabled = craftable.Value; recipe2.m_amount = craftAmount.Value; recipe2.m_minStationLevel = stationLevel.Value; if (Object.op_Implicit((Object)(object)ObjectDB.instance)) { Requirement[] array = Reqs.ParseRequirements(resources.Value); if (array.Length != 0) { recipe2.m_resources = array; } } if (Object.op_Implicit((Object)(object)ZNetScene.instance)) { if (string.IsNullOrEmpty(station.Value)) { recipe2.m_craftingStation = null; } else { GameObject prefab = ZNetScene.instance.GetPrefab(Reqs.CleanName(station.Value)); CraftingStation val = ((prefab != null) ? prefab.GetComponent() : null); if ((Object)(object)val == (Object)null) { ConfigurationsForEveryonePlugin.Log.LogWarning((object)("[" + section + "] crafting station '" + station.Value + "' could not be resolved")); } recipe2.m_craftingStation = val; } } ConfigurationsForEveryonePlugin.Debug($"[{section}] applied item: craftable={craftable.Value} amount={craftAmount.Value} station='{station.Value}' level={stationLevel.Value} costs='{resources.Value}'"); } } } internal static class Pieces { public static void Bind(ModConfig config, CustomPiece customPiece) { //IL_00b5: Unknown result type (might be due to invalid IL or missing references) Piece piece = customPiece.Piece; string section; ConfigEntry buildable; ConfigEntry category; ConfigEntry station; ConfigEntry resources; if (!((Object)(object)piece == (Object)null)) { section = (Object.op_Implicit((Object)(object)customPiece.PiecePrefab) ? ((Object)customPiece.PiecePrefab).name : ((Object)piece).name); config.SetDisplayName(section, Reqs.Localize(piece.m_name, section)); buildable = config.Bind(section, "Buildable", piece.m_enabled, "Whether the piece can be built", null, 40); category = config.Bind(section, "Category", piece.m_category, "Build menu category the piece appears in", null, 39); station = config.Bind(section, "Crafting Station", Object.op_Implicit((Object)(object)piece.m_craftingStation) ? Reqs.CleanName(((Object)piece.m_craftingStation).name) : "", "Crafting station prefab name required to build, empty for none", null, 38); resources = config.Bind(section, "Build Costs", Reqs.SerializeRequirements(piece.m_resources), "Comma separated itemName:amount resources required to build", null, 37, Drawer.Requirements); Action apply = Apply; Appliers.Register(apply, "piece(s)"); buildable.SettingChanged += delegate { ApplyScheduler.Schedule(apply); }; category.SettingChanged += delegate { ApplyScheduler.Schedule(apply); }; station.SettingChanged += delegate { ApplyScheduler.Schedule(apply); }; resources.SettingChanged += delegate { ApplyScheduler.Schedule(apply); }; } void Apply() { //IL_0023: 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_015c: Unknown result type (might be due to invalid IL or missing references) piece.m_enabled = buildable.Value; piece.m_category = category.Value; if (Object.op_Implicit((Object)(object)ObjectDB.instance)) { Requirement[] array = Reqs.ParseRequirements(resources.Value); if (array.Length != 0) { piece.m_resources = array; } } if (Object.op_Implicit((Object)(object)ZNetScene.instance)) { if (string.IsNullOrEmpty(station.Value)) { piece.m_craftingStation = null; } else { GameObject prefab = ZNetScene.instance.GetPrefab(Reqs.CleanName(station.Value)); CraftingStation val = ((prefab != null) ? prefab.GetComponent() : null); if ((Object)(object)val == (Object)null) { ConfigurationsForEveryonePlugin.Log.LogWarning((object)("[" + section + "] crafting station '" + station.Value + "' could not be resolved")); } piece.m_craftingStation = val; } } ConfigurationsForEveryonePlugin.Debug($"[{section}] applied piece: buildable={buildable.Value} category={category.Value} station='{station.Value}' costs='{resources.Value}'"); } } } internal static class Drawer { private struct Req { public string Name; public int Amount; public int PerLevel; } private struct DropRow { public string Name; public int Min; public int Max; public float Chance; } public static readonly Action Requirements = delegate(ConfigEntryBase cfg) { Guard(cfg, delegate(ConfigEntryBase c) { DrawRequirements(c, withUpgrade: false); }); }; public static readonly Action RequirementsWithUpgrade = delegate(ConfigEntryBase cfg) { Guard(cfg, delegate(ConfigEntryBase c) { DrawRequirements(c, withUpgrade: true); }); }; public static readonly Action Drops = delegate(ConfigEntryBase cfg) { Guard(cfg, DrawDrops); }; private const int ButtonWidth = 24; private static GUIStyle? _textStyle; private static GUIStyle? _buttonStyle; private static GUIStyle? _centerLabelStyle; private static object? _configManager; private static bool _configManagerResolved; private static void EnsureStyles() { //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Expected O, but got Unknown //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Expected O, but got Unknown //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Expected O, but got Unknown if (_textStyle == null) { _textStyle = new GUIStyle(GUI.skin.textField); _buttonStyle = new GUIStyle(GUI.skin.button); _centerLabelStyle = new GUIStyle(GUI.skin.label) { alignment = (TextAnchor)4 }; } } private static void Guard(ConfigEntryBase cfg, Action draw) { try { EnsureStyles(); draw(cfg); } catch (Exception ex) { GUILayout.Label((string)cfg.BoxedValue, Array.Empty()); ConfigurationsForEveryonePlugin.Debug("drawer failed for '" + cfg.Definition.Key + "': " + ex.Message); } } private static int ColumnWidth() { if (!_configManagerResolved) { _configManagerResolved = true; try { Type type = AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault((Assembly a) => a.GetName().Name == "ConfigurationManager")?.GetType("ConfigurationManager.ConfigurationManager"); if (type != null && Object.op_Implicit((Object)(object)Chainloader.ManagerObject)) { _configManager = Chainloader.ManagerObject.GetComponent(type); } } catch { } } try { if (_configManager?.GetType().GetProperty("RightColumnWidth", BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(_configManager) is int num && num > 0) { return num; } } catch { } return 130; } private static void DrawRequirements(ConfigEntryBase cfg, bool withUpgrade) { List list = ParseReqs((string)cfg.BoxedValue); List list2 = new List(); bool flag = false; int num = 119 + (withUpgrade ? 77 : 0); int num2 = Math.Max(60, ColumnWidth() - num); GUILayout.BeginVertical(Array.Empty()); if (list.Count == 0) { list.Add(new Req { Name = "", Amount = 1, PerLevel = 1 }); flag = true; } foreach (Req item in list) { GUILayout.BeginHorizontal(Array.Empty()); int num3 = item.Amount; if (int.TryParse(GUILayout.TextField(num3.ToString(), _textStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(45f) }), out var result) && result != num3) { num3 = result; flag = true; } GUILayout.Label("x", _centerLabelStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(12f) }); string text = GUILayout.TextField(item.Name, _textStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width((float)num2) }); flag = flag || text != item.Name; int num4 = item.PerLevel; if (withUpgrade) { if (int.TryParse(GUILayout.TextField(num4.ToString(), _textStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(45f) }), out var result2) && result2 != num4) { num4 = result2; flag = true; } GUILayout.Label("/lvl", _centerLabelStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(32f) }); } bool flag2 = GUILayout.Button("✕", _buttonStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(24f) }); bool flag3 = GUILayout.Button("+", _buttonStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(24f) }); GUILayout.EndHorizontal(); if (flag2) { flag = true; } else { list2.Add(new Req { Name = text, Amount = num3, PerLevel = num4 }); } if (flag3) { flag = true; list2.Add(new Req { Name = "", Amount = 1, PerLevel = 1 }); } } GUILayout.EndVertical(); if (flag) { cfg.BoxedValue = SerializeReqs(list2, withUpgrade); } } private static string SerializeReqs(List reqs, bool withUpgrade) { return string.Join(",", reqs.Select((Req r) => withUpgrade ? $"{r.Name.Trim()}:{r.Amount}:{r.PerLevel}" : $"{r.Name.Trim()}:{r.Amount}")); } private static List ParseReqs(string value) { List list = new List(); if (string.IsNullOrWhiteSpace(value)) { return list; } foreach (string item in from p in value.Split(new char[1] { ',' }) select p.Trim() into p where p.Length > 0 select p) { string[] array = item.Split(new char[1] { ':' }); int result; int num = ((array.Length <= 1 || !int.TryParse(array[1], out result)) ? 1 : result); int result2; int perLevel = ((array.Length > 2 && int.TryParse(array[2], out result2)) ? result2 : num); list.Add(new Req { Name = array[0].Trim(), Amount = num, PerLevel = perLevel }); } return list; } private static void DrawDrops(ConfigEntryBase cfg) { List list = ParseDrops((string)cfg.BoxedValue); List list2 = new List(); bool flag = false; int num = 201; int num2 = Math.Max(60, ColumnWidth() - num); GUILayout.BeginVertical(Array.Empty()); if (list.Count == 0) { list.Add(new DropRow { Name = "", Min = 1, Max = 1, Chance = 100f }); flag = true; } foreach (DropRow item in list) { GUILayout.BeginHorizontal(Array.Empty()); int num3 = item.Min; if (int.TryParse(GUILayout.TextField(num3.ToString(), _textStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(35f) }), out var result) && result != num3) { num3 = result; flag = true; } GUILayout.Label("-", _centerLabelStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(10f) }); int num4 = item.Max; if (int.TryParse(GUILayout.TextField(num4.ToString(), _textStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(35f) }), out var result2) && result2 != num4) { num4 = result2; flag = true; } string text = GUILayout.TextField(item.Name, _textStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width((float)num2) }); flag = flag || text != item.Name; float num5 = item.Chance; if (float.TryParse(GUILayout.TextField(num5.ToString(CultureInfo.InvariantCulture), _textStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(45f) }), out var result3) && Math.Abs(result3 - num5) > 1E-05f) { num5 = result3; flag = true; } GUILayout.Label("%", _centerLabelStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(14f) }); bool flag2 = GUILayout.Button("✕", _buttonStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(24f) }); bool flag3 = GUILayout.Button("+", _buttonStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(24f) }); GUILayout.EndHorizontal(); if (flag2) { flag = true; } else { list2.Add(new DropRow { Name = text, Min = num3, Max = num4, Chance = num5 }); } if (flag3) { flag = true; list2.Add(new DropRow { Name = "", Min = 1, Max = 1, Chance = 100f }); } } GUILayout.EndVertical(); if (flag) { cfg.BoxedValue = SerializeDrops(list2); } } private static string SerializeDrops(List drops) { return string.Join(",", drops.Select((DropRow d) => $"{d.Name.Trim()}:{d.Min}-{d.Max}:{d.Chance.ToString(CultureInfo.InvariantCulture)}")); } private static List ParseDrops(string value) { List list = new List(); if (string.IsNullOrWhiteSpace(value)) { return list; } foreach (string item in from s in value.Split(new char[1] { ',' }) select s.Trim() into s where s.Length > 0 select s) { string[] array = item.Split(new char[1] { ':' }); int result = 1; int max = 1; if (array.Length > 1) { string[] array2 = array[1].Split(new char[1] { '-' }); int.TryParse(array2[0], out result); max = ((array2.Length > 1 && int.TryParse(array2[1], out var result2)) ? result2 : result); } float result3 = 100f; if (array.Length > 2) { float.TryParse(array[2], NumberStyles.Float, CultureInfo.InvariantCulture, out result3); } list.Add(new DropRow { Name = array[0].Trim(), Min = result, Max = max, Chance = result3 }); } return list; } } internal sealed class RefreshCommand : ConsoleCommand { public override string Name => "cfe_refresh"; public override string Help => "Re-apply every ConfigurationsForEveryone setting to the loaded game content"; public override void Run(string[] args, Terminal context) { int num = Appliers.RunAll(); if (context != null) { context.AddString($"ConfigurationsForEveryone re-applied {num} setting group(s)"); } } } }