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 ServerRates v1.4.9
plugins\ServerRates\ServerRates.dll
Decompiled a week agousing System; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text; using System.Text.RegularExpressions; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: AssemblyCompany("ServerRates")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.4.9.0")] [assembly: AssemblyInformationalVersion("1.4.9")] [assembly: AssemblyProduct("ServerRates")] [assembly: AssemblyTitle("ServerRates")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.4.9.0")] [module: UnverifiableCode] namespace ServerRates; internal static class CategoryGroundAmp { private static readonly int CatFlag = StringExtensionMethods.GetStableHashCode("SR.Cat"); private static readonly int NoCatFlag = StringExtensionMethods.GetStableHashCode("SR.NoCat"); private static readonly HashSet<ZDOID> Done = new HashSet<ZDOID>(); private static readonly List<ZDO> Near = new List<ZDO>(256); private static readonly List<ZDO> Distant = new List<ZDO>(256); private static float _nextScan; private static int _diag; private static int _seen; public static void LogStatus() { if (Plugin.Log != null && Plugin.Settings != null) { ModConfig settings = Plugin.Settings; Plugin.Log.LogInfo((object)("ServerRates loot: GroundAmp=" + settings.CategoryGroundAmp.Value + " SnapGround=" + settings.SnapExtraDropsToGround.Value + " Wood=x" + settings.WoodDropMultiplier.Value + " Hide=x" + settings.HideDropMultiplier.Value + " Meat=x" + settings.MeatDropMultiplier.Value + " Ore=x" + settings.OreDropMultiplier.Value + " (fine settings in 6a/6b/6c)")); } } public static void MarkPlayerDrop(ItemDrop drop) { //IL_0043: Unknown result type (might be due to invalid IL or missing references) ZNetView val = (((Object)(object)drop != (Object)null) ? ((Component)drop).GetComponent<ZNetView>() : null); if (!((Object)(object)val == (Object)null) && val.IsValid()) { ZDO zDO = val.GetZDO(); if (zDO != null) { zDO.Set(NoCatFlag, 1, false); Done.Add(zDO.m_uid); } } } public static void Tick() { //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Unknown result type (might be due to invalid IL or missing references) if (!DropScale.Ready() || Plugin.Settings == null || !Plugin.Settings.CategoryGroundAmp.Value || ZDOMan.instance == null || (Object)(object)ZNet.instance == (Object)null || (Object)(object)ZNetScene.instance == (Object)null || Time.time < _nextScan) { return; } _nextScan = Time.time + 0.35f; Near.Clear(); Distant.Clear(); List<ZNetPeer> peers = ZNet.instance.GetPeers(); if (peers == null || peers.Count == 0) { return; } SimulationDistance syncedSimulationDistance = ZNet.instance.GetSyncedSimulationDistance(); for (int i = 0; i < peers.Count; i++) { ZNetPeer val = peers[i]; if (val != null && val.IsReady()) { Vector2s zone = ZoneSystem.GetZone(val.GetRefPos()); ZDOMan.instance.FindSectorObjects(zone, syncedSimulationDistance, Near, Distant); } } for (int j = 0; j < Near.Count; j++) { TryAmplifyZdo(Near[j]); } for (int k = 0; k < Distant.Count; k++) { TryAmplifyZdo(Distant[k]); } if (Done.Count > 4000) { Done.Clear(); } } public static void TryAmplifyZdo(ZDO zdo) { //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_0297: Unknown result type (might be due to invalid IL or missing references) //IL_029c: Unknown result type (might be due to invalid IL or missing references) //IL_029f: Unknown result type (might be due to invalid IL or missing references) //IL_02a4: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_02bb: Unknown result type (might be due to invalid IL or missing references) //IL_02bd: 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_0193: Unknown result type (might be due to invalid IL or missing references) if (zdo == null || !DropScale.Ready() || Plugin.Settings == null || !Plugin.Settings.CategoryGroundAmp.Value || (Object)(object)ZNetScene.instance == (Object)null || Done.Contains(zdo.m_uid)) { return; } if (zdo.GetInt(NoCatFlag, 0) != 0) { Done.Add(zdo.m_uid); return; } if (zdo.GetInt(CatFlag, 0) != 0) { Done.Add(zdo.m_uid); return; } GameObject prefab = ZNetScene.instance.GetPrefab(zdo.GetPrefab()); if ((Object)(object)prefab == (Object)null) { return; } ItemDrop component = prefab.GetComponent<ItemDrop>(); if ((Object)(object)component == (Object)null || component.m_itemData == null) { return; } DropClassifier.Kind kind = DropClassifier.Classify(prefab); if (kind == DropClassifier.Kind.Other) { kind = DropClassifier.Classify(component.m_itemData); } float num = Mathf.Max(0f, DropClassifier.MultiplierFor(kind, Plugin.Settings)); ItemData val = component.m_itemData.Clone(); ItemDrop.LoadFromZDO(val, zdo, 0); int num2 = Mathf.Max(1, val.m_stack); if (_seen < 30 && Plugin.Log != null) { _seen++; Plugin.Log.LogInfo((object)("ServerRates ground amp check: '" + ((Object)prefab).name + "' -> " + kind.ToString() + " x" + num.ToString("0.##") + " stack=" + num2)); } Done.Add(zdo.m_uid); try { zdo.Set(CatFlag, 1, false); } catch { } if (num <= 1.001f) { return; } int num3 = Mathf.Max(0, Mathf.RoundToInt((float)num2 * num)); if (num3 > num2) { if (_diag < 40 && Plugin.Log != null) { _diag++; Plugin.Log.LogInfo((object)("ServerRates ground amp: " + kind.ToString() + " x" + num.ToString("0.##") + " '" + ((Object)prefab).name + "' " + num2 + " -> " + num3)); } int num4 = 1; if (val.m_shared != null) { num4 = Mathf.Max(1, val.m_shared.m_maxStackSize); } int num5 = num3 - num2; Vector3 position = zdo.GetPosition(); Quaternion rotation = zdo.GetRotation(); while (num5 > 0) { int num6 = Mathf.Min(num5, num4); num5 -= num6; SpawnExtra(prefab, position, rotation, val, num6); } } } private static void SpawnExtra(GameObject prefab, Vector3 pos, Quaternion rot, ItemData template, int stack) { //IL_0000: 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) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0117: Unknown result type (might be due to invalid IL or missing references) //IL_0140: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_01a1: Unknown result type (might be due to invalid IL or missing references) //IL_01a8: Unknown result type (might be due to invalid IL or missing references) //IL_01ad: Unknown result type (might be due to invalid IL or missing references) //IL_01af: Unknown result type (might be due to invalid IL or missing references) //IL_01d5: Unknown result type (might be due to invalid IL or missing references) //IL_01bf: Unknown result type (might be due to invalid IL or missing references) Vector2 val = Random.insideUnitCircle * 0.45f; Vector3 val2 = pos + new Vector3(val.x, 0.15f, val.y); ModConfig settings = Plugin.Settings; if (settings != null && settings.SnapExtraDropsToGround.Value && (Object)(object)ZoneSystem.instance != (Object)null) { float solidHeight = ZoneSystem.instance.GetSolidHeight(val2); if (solidHeight > -1000f && solidHeight < 5000f && (val2.y > solidHeight + 0.35f || val2.y < solidHeight - 0.1f)) { val2.y = solidHeight + 0.2f; } } GameObject val3 = Object.Instantiate<GameObject>(prefab, val2, rot); ItemDrop component = val3.GetComponent<ItemDrop>(); if ((Object)(object)component == (Object)null) { Object.Destroy((Object)(object)val3); return; } if (component.m_itemData != null && template != null) { component.m_itemData = template.Clone(); component.m_itemData.m_stack = stack; } ZNetView component2 = ((Component)component).GetComponent<ZNetView>(); if ((Object)(object)component2 != (Object)null && component2.IsValid()) { ZDO zDO = component2.GetZDO(); if (zDO != null) { Done.Add(zDO.m_uid); zDO.Set(CatFlag, 1, false); zDO.Set(NoCatFlag, 0, false); zDO.SetPosition(val2); if (component.m_itemData != null) { ItemDrop.SaveToZDO(component.m_itemData, zDO, 0); } } } ItemDrop.OnCreateNew(val3, false); float num = ((settings != null) ? Mathf.Max(0f, settings.ExtraDropScatterForce.Value) : 4f); Rigidbody component3 = val3.GetComponent<Rigidbody>(); if ((Object)(object)component3 != (Object)null && num > 0.01f) { Vector3 val4 = Random.insideUnitSphere * num; if (val4.y < 0f) { val4.y = 0f - val4.y; } component3.WakeUp(); component3.AddForce(val4, (ForceMode)2); } } } [HarmonyPatch(typeof(ItemDrop), "OnPlayerDrop")] internal static class ItemDropOnPlayerDropPatch { private static void Postfix(ItemDrop __instance) { CategoryGroundAmp.MarkPlayerDrop(__instance); } } [HarmonyPatch(typeof(ZNetScene), "CreateObject")] internal static class ZNetSceneCreateObjectPatch { private static void Postfix(ZDO zdo, GameObject __result) { if (zdo != null) { CategoryGroundAmp.TryAmplifyZdo(zdo); } else if ((Object)(object)__result != (Object)null) { ZNetView component = __result.GetComponent<ZNetView>(); if ((Object)(object)component != (Object)null && component.IsValid()) { CategoryGroundAmp.TryAmplifyZdo(component.GetZDO()); } } } } internal static class ConfigWatch { private static FileSystemWatcher _watcher; private static float _reloadAt; private static bool _pending; private static string _cfgFileName; private static float _suppressUntil; public static void Start() { if (_watcher != null) { return; } try { _cfgFileName = (((Object)(object)Plugin.Instance != (Object)null) ? Path.GetFileName(((BaseUnityPlugin)Plugin.Instance).Config.ConfigFilePath) : "com.morda.serverrates.cfg"); _watcher = new FileSystemWatcher(Paths.ConfigPath); _watcher.Filter = _cfgFileName; _watcher.NotifyFilter = NotifyFilters.FileName | NotifyFilters.Size | NotifyFilters.LastWrite; _watcher.Changed += OnChanged; _watcher.Created += OnChanged; _watcher.EnableRaisingEvents = true; Plugin.Log.LogInfo((object)("ServerRates config watcher: " + Path.Combine(Paths.ConfigPath, _cfgFileName))); } catch (Exception ex) { Plugin.Log.LogWarning((object)("ServerRates config watcher failed: " + ex.Message)); } } public static void SuppressReloadBriefly(float seconds = 2f) { _suppressUntil = Time.unscaledTime + Mathf.Max(0.1f, seconds); _pending = false; } public static void Tick() { if (Time.unscaledTime < _suppressUntil) { _pending = false; } else if (_pending && !(Time.unscaledTime < _reloadAt)) { _pending = false; Reload(); } } private static void OnChanged(object sender, FileSystemEventArgs e) { _pending = true; _reloadAt = Time.unscaledTime + 0.5f; } private static void Reload() { try { if ((Object)(object)Plugin.Instance != (Object)null) { ((BaseUnityPlugin)Plugin.Instance).Config.Reload(); } RateApplier.NotifyConfigReloaded(); RateApplier.ApplyGlobalKeys(); Plugin.Log.LogInfo((object)"ServerRates config reloaded from disk and applied."); CategoryGroundAmp.LogStatus(); } catch (Exception ex) { Plugin.Log.LogWarning((object)("ServerRates reload failed: " + ex.Message)); } } } internal static class DropClassifier { public enum Kind { Other, Wood, FineWood, CoreWood, SpecialWood, Ore, Scrap, Stone, Flint, Crystal, Fuel, Gems, BossMats, Crops, Seeds, Mushrooms, BerriesHoney, Fish, Potions, Hide, Trophy, Meat, Parts, Feathers, SpecialParts } private static readonly HashSet<string> Wood = new HashSet<string> { "wood" }; private static readonly HashSet<string> FineWood = new HashSet<string> { "finewood" }; private static readonly HashSet<string> CoreWood = new HashSet<string> { "roundlog" }; private static readonly HashSet<string> SpecialWood = new HashSet<string> { "elderbark", "yggdrasilwood", "ashwood", "blackwood" }; private static readonly HashSet<string> Ore = new HashSet<string> { "copperore", "tinore", "ironore", "silverore", "flametalore", "flametalorenew" }; private static readonly HashSet<string> Scrap = new HashSet<string> { "ironscrap", "blackmetalscrap", "copperscrap" }; private static readonly HashSet<string> Stone = new HashSet<string> { "stone", "grausten", "sharpeningstone", "thunderstone" }; private static readonly HashSet<string> Flint = new HashSet<string> { "flint" }; private static readonly HashSet<string> Crystal = new HashSet<string> { "crystal", "obsidian" }; private static readonly HashSet<string> Fuel = new HashSet<string> { "coal", "resin", "tar" }; private static readonly HashSet<string> Gems = new HashSet<string> { "coins", "amber", "amberpearl", "ruby", "silvernecklace" }; private static readonly HashSet<string> BossMats = new HashSet<string> { "surtlingcore", "dragontear", "ancientseed", "ymirremains", "queenbee", "yagluthdrop", "vegvisirshard_bonemass", "blackcore", "refinedeitr", "mechanicalspring", "dvergrkeyfragment", "trophybonemass", "trophyeikthyr", "trophytheelder", "trophydragonqueen", "trophygoblinking", "trophyseekerqueen", "trophyfader" }; private static readonly HashSet<string> Crops = new HashSet<string> { "barley", "barleyflour", "flax", "carrot", "onion", "turnip", "thistle", "dandelion", "sap", "royaljelly", "jotunpuffs", "smokepuffs" }; private static readonly HashSet<string> Seeds = new HashSet<string> { "carrotseeds", "onionseeds", "turnipseeds", "beechseeds", "birchseeds", "fircone", "pinecone", "acorn", "oakseeds" }; private static readonly HashSet<string> Mushrooms = new HashSet<string> { "mushroom", "mushroomyellow", "mushroomblue", "magecap" }; private static readonly HashSet<string> BerriesHoney = new HashSet<string> { "raspberry", "blueberry", "cloudberry", "honey", "bukeperries" }; private static readonly HashSet<string> Fish = new HashSet<string> { "fishraw", "fish", "perch", "pike", "tuna", "trollfish", "pufferfish", "anglerfish", "coralcod", "northernsalmon", "magmapander", "voltureegg" }; private static readonly HashSet<string> Potions = new HashSet<string> { "meadbasehealth", "meadbasehealthminor", "meadbasestamina", "meadbasetasty", "meadbasepoisonresist", "meadbasefrostresist", "meadbaseeitr", "meadbaselight", "potion_health_minor", "potion_health_medium", "potion_stamina_minor", "potion_stamina_medium", "potion_eitr_minor", "poisonbomb" }; private static readonly HashSet<string> Hide = new HashSet<string> { "deerhide", "leatherscraps", "trollhide", "wolfpelt", "loxpelt", "serpentscale", "chitin", "scalehide", "asksvinhide", "harepelt", "hare_pelt", "wolfhairbundle" }; private static readonly HashSet<string> Meat = new HashSet<string> { "rawmeat", "necktail", "boarmeat", "deer", "deermeat", "wolfmeat", "loxmeat", "serpentmeat", "chickenmeat", "haremeat", "asksvinmeat", "bugmeat", "meatrotten", "necktailgrilled", "cookedmeat", "cookedbackmeat", "serpentmeatcooked", "cookeddeer", "cookedwolf", "loxpie", "fishcooked" }; private static readonly HashSet<string> Parts = new HashSet<string> { "bonefragments", "witheredbone", "entrails", "bloodbag", "needle", "greydwarfeye", "freezegland", "hardantler", "wolffang", "root", "mandible", "chain" }; private static readonly HashSet<string> Feathers = new HashSet<string> { "feathers" }; private static readonly HashSet<string> SpecialParts = new HashSet<string> { "guck", "ooze", "softtissue", "bilebag", "refinedeitr", "blackcore", "dvergrkeyfragment", "mechanicalspring", "seekerchitin", "carapace", "moltencore", "charredskull", "flametal", "proustitepowder" }; public static Kind Classify(GameObject prefab) { if ((Object)(object)prefab == (Object)null) { return Kind.Other; } ItemDrop component = prefab.GetComponent<ItemDrop>(); if ((Object)(object)component != (Object)null && component.m_itemData != null && component.m_itemData.m_shared != null) { Kind kind = ClassifyKey(Normalize(component.m_itemData.m_shared.m_name)); if (kind != Kind.Other) { return kind; } } return ClassifyKey(Normalize(((Object)prefab).name)); } public static Kind Classify(ItemData data) { if (data == null || data.m_shared == null) { return Kind.Other; } return ClassifyKey(Normalize(data.m_shared.m_name)); } private static Kind ClassifyKey(string key) { if (string.IsNullOrEmpty(key)) { return Kind.Other; } if (FineWood.Contains(key)) { return Kind.FineWood; } if (CoreWood.Contains(key)) { return Kind.CoreWood; } if (SpecialWood.Contains(key)) { return Kind.SpecialWood; } if (Wood.Contains(key) || key == "wood") { return Kind.Wood; } if (key.EndsWith("wood") && !key.Contains("yggdrasil")) { return Kind.Wood; } if (Ore.Contains(key) || (key.EndsWith("ore") && !key.Contains("flametalorenew"))) { return Kind.Ore; } if (Scrap.Contains(key) || (key.EndsWith("scrap") && (key.Contains("iron") || key.Contains("metal") || key.Contains("copper") || key.Contains("black")))) { return Kind.Scrap; } if (Flint.Contains(key)) { return Kind.Flint; } if (Crystal.Contains(key)) { return Kind.Crystal; } if (Stone.Contains(key)) { return Kind.Stone; } if (Fuel.Contains(key)) { return Kind.Fuel; } if (Gems.Contains(key)) { return Kind.Gems; } if (BossMats.Contains(key)) { return Kind.BossMats; } if (Seeds.Contains(key) || key.EndsWith("seeds") || key.EndsWith("cone") || key == "acorn") { return Kind.Seeds; } if (Mushrooms.Contains(key) || key.Contains("mushroom") || key == "magecap") { return Kind.Mushrooms; } if (BerriesHoney.Contains(key) || key.Contains("berry") || key == "honey") { return Kind.BerriesHoney; } if (Fish.Contains(key) || key.StartsWith("fish") || key.Contains("salmon") || key.Contains("puffer")) { return Kind.Fish; } if (Potions.Contains(key) || key.Contains("mead") || key.Contains("potion")) { return Kind.Potions; } if (Crops.Contains(key)) { return Kind.Crops; } if (key.Contains("trophy")) { return Kind.Trophy; } if (Hide.Contains(key) || key.Contains("hide") || key.Contains("pelt") || key.Contains("leather") || key.Contains("scale")) { return Kind.Hide; } if (Meat.Contains(key) || key.Contains("meat") || key.Contains("necktail")) { return Kind.Meat; } if (Feathers.Contains(key) || key.Contains("feather")) { return Kind.Feathers; } if (SpecialParts.Contains(key)) { return Kind.SpecialParts; } if (Parts.Contains(key) || key.Contains("bone") || key.Contains("entrails") || key.Contains("gland") || key.Contains("fang") || key.Contains("eye")) { return Kind.Parts; } return Kind.Other; } public static float MultiplierFor(Kind kind, ModConfig c) { if (c == null) { return 1f; } return kind switch { Kind.Wood => c.WoodDropMultiplier.Value, Kind.FineWood => c.FineWoodDropMultiplier.Value, Kind.CoreWood => c.CoreWoodDropMultiplier.Value, Kind.SpecialWood => c.SpecialWoodDropMultiplier.Value, Kind.Ore => c.OreDropMultiplier.Value, Kind.Scrap => c.ScrapDropMultiplier.Value, Kind.Stone => c.StoneDropMultiplier.Value, Kind.Flint => c.FlintDropMultiplier.Value, Kind.Crystal => c.CrystalDropMultiplier.Value, Kind.Fuel => c.FuelDropMultiplier.Value, Kind.Gems => c.GemDropMultiplier.Value, Kind.BossMats => c.BossDropMultiplier.Value, Kind.Crops => c.CropDropMultiplier.Value, Kind.Seeds => c.SeedDropMultiplier.Value, Kind.Mushrooms => c.MushroomDropMultiplier.Value, Kind.BerriesHoney => c.BerryHoneyDropMultiplier.Value, Kind.Fish => c.FishDropMultiplier.Value, Kind.Potions => c.PotionDropMultiplier.Value, Kind.Hide => c.HideDropMultiplier.Value, Kind.Trophy => c.TrophyDropMultiplier.Value, Kind.Meat => c.MeatDropMultiplier.Value, Kind.Parts => c.PartsDropMultiplier.Value, Kind.Feathers => c.FeatherDropMultiplier.Value, Kind.SpecialParts => c.SpecialPartsDropMultiplier.Value, _ => c.OtherDropMultiplier.Value, }; } private static string Normalize(string raw) { if (string.IsNullOrEmpty(raw)) { return ""; } string text = raw.Trim().ToLowerInvariant(); int num = text.IndexOf("(clone)"); if (num >= 0) { text = text.Substring(0, num).Trim(); } if (text.StartsWith("$item_")) { text = text.Substring(6); } return text.Replace(" ", "").Replace("-", "").Replace("_", ""); } } public class ModConfig { private static readonly AcceptableValueList<string> ToggleValues = new AcceptableValueList<string>(new string[3] { "Unchanged", "On", "Off" }); public ConfigEntry<bool> Enabled { get; } public ConfigEntry<bool> ChatCommandsEnabled { get; } public ConfigEntry<string> ChatCommandPrefix { get; } public ConfigEntry<float> SkillGainPercent { get; } public ConfigEntry<float> SkillReductionPercent { get; } public ConfigEntry<float> PlayerDamagePercent { get; } public ConfigEntry<float> EnemyDamagePercent { get; } public ConfigEntry<float> EnemySpeedSizePercent { get; } public ConfigEntry<float> EnemyLevelUpPercent { get; } public ConfigEntry<float> EventRatePercent { get; } public ConfigEntry<int> WorldLevel { get; } public ConfigEntry<string> PassiveMobs { get; } public ConfigEntry<string> PlayerEvents { get; } public ConfigEntry<float> StaminaPercent { get; } public ConfigEntry<float> MoveStaminaPercent { get; } public ConfigEntry<float> StaminaRegenPercent { get; } public ConfigEntry<float> EitrPercent { get; } public ConfigEntry<float> AdrenalinePercent { get; } public ConfigEntry<float> FoodPercent { get; } public ConfigEntry<float> DurabilityPercent { get; } public ConfigEntry<float> CarryWeightPercent { get; } public ConfigEntry<float> ResourceRatePercent { get; } public ConfigEntry<bool> CategoryGroundAmp { get; } public ConfigEntry<bool> SnapExtraDropsToGround { get; } public ConfigEntry<float> ExtraDropScatterForce { get; } public ConfigEntry<float> OtherDropMultiplier { get; } public ConfigEntry<float> WoodDropMultiplier { get; } public ConfigEntry<float> FineWoodDropMultiplier { get; } public ConfigEntry<float> CoreWoodDropMultiplier { get; } public ConfigEntry<float> SpecialWoodDropMultiplier { get; } public ConfigEntry<float> OreDropMultiplier { get; } public ConfigEntry<float> ScrapDropMultiplier { get; } public ConfigEntry<float> StoneDropMultiplier { get; } public ConfigEntry<float> FlintDropMultiplier { get; } public ConfigEntry<float> CrystalDropMultiplier { get; } public ConfigEntry<float> FuelDropMultiplier { get; } public ConfigEntry<float> GemDropMultiplier { get; } public ConfigEntry<float> BossDropMultiplier { get; } public ConfigEntry<float> CropDropMultiplier { get; } public ConfigEntry<float> SeedDropMultiplier { get; } public ConfigEntry<float> MushroomDropMultiplier { get; } public ConfigEntry<float> BerryHoneyDropMultiplier { get; } public ConfigEntry<float> FishDropMultiplier { get; } public ConfigEntry<float> PotionDropMultiplier { get; } public ConfigEntry<float> HideDropMultiplier { get; } public ConfigEntry<float> TrophyDropMultiplier { get; } public ConfigEntry<float> MeatDropMultiplier { get; } public ConfigEntry<float> PartsDropMultiplier { get; } public ConfigEntry<float> FeatherDropMultiplier { get; } public ConfigEntry<float> SpecialPartsDropMultiplier { get; } public ConfigEntry<string> DeathKeepEquip { get; } public ConfigEntry<string> DeathKeepInventory { get; } public ConfigEntry<string> DeathDeleteItems { get; } public ConfigEntry<string> DeathDeleteUnequipped { get; } public ConfigEntry<string> DeathSkillsReset { get; } public ConfigEntry<string> NoBuildCost { get; } public ConfigEntry<string> NoCraftCost { get; } public ConfigEntry<string> AllPiecesUnlocked { get; } public ConfigEntry<string> AllRecipesUnlocked { get; } public ConfigEntry<string> NoWorkbench { get; } public ConfigEntry<string> WorldLevelLockedTools { get; } public ConfigEntry<string> NoMap { get; } public ConfigEntry<string> NoPortals { get; } public ConfigEntry<string> NoBossPortals { get; } public ConfigEntry<string> TeleportAll { get; } public ConfigEntry<string> DungeonBuild { get; } public ConfigEntry<string> NoPseudoDrops { get; } public ConfigEntry<string> NoBuildingFall { get; } public ConfigEntry<string> NoHeavySnow { get; } public ConfigEntry<string> AllHeavySnow { get; } public ConfigEntry<string> Fire { get; } public ConfigEntry<float> SmelterSpeedMultiplier { get; } public ConfigEntry<float> FermenterSpeedMultiplier { get; } public ConfigEntry<float> CookingSpeedMultiplier { get; } public ConfigEntry<float> PlantGrowSpeedMultiplier { get; } public ModConfig(ConfigFile file) { //IL_015d: Unknown result type (might be due to invalid IL or missing references) //IL_0167: Expected O, but got Unknown //IL_0324: Unknown result type (might be due to invalid IL or missing references) //IL_032e: Expected O, but got Unknown Enabled = file.Bind<bool>("1 - General", "Enabled", true, "Master switch. Dedicated server only; vanilla clients need no install."); ChatCommandsEnabled = file.Bind<bool>("1 - General", "ChatCommandsEnabled", true, "Allow rate commands in chat (for console players). No admin check — anyone can use. Prefix below."); ChatCommandPrefix = file.Bind<string>("1 - General", "ChatCommandPrefix", "!", "Chat prefix, e.g. !sr_wood 9 or !rates status"); SkillGainPercent = Percent(file, "2 - Skills", "SkillGainPercent", 100f, "XP for ALL skills. 100 = vanilla, 200 = x2, 1000 = x10."); SkillReductionPercent = Percent(file, "2 - Skills", "SkillReductionPercent", 100f, "Skill loss on death. 100 = vanilla, 0 = none."); PlayerDamagePercent = Percent(file, "3 - Combat", "PlayerDamagePercent", 100f, "Damage players deal. 100 = vanilla."); EnemyDamagePercent = Percent(file, "3 - Combat", "EnemyDamagePercent", 100f, "Damage enemies deal. 100 = vanilla."); EnemySpeedSizePercent = Percent(file, "3 - Combat", "EnemySpeedSizePercent", 100f, "Enemy move speed / size scaling. 100 = vanilla."); EnemyLevelUpPercent = Percent(file, "3 - Combat", "EnemyLevelUpPercent", 100f, "How fast enemies star-up. 100 = vanilla."); EventRatePercent = Percent(file, "3 - Combat", "EventRatePercent", 100f, "Raid / event frequency. 100 = vanilla, 0 = none."); WorldLevel = file.Bind<int>("3 - Combat", "WorldLevel", 0, new ConfigDescription("World level 0-10. 0 = vanilla start.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 10), Array.Empty<object>())); PassiveMobs = Toggle(file, "3 - Combat", "PassiveMobs", "On = mobs do not attack. Unchanged = leave vanilla/world setting."); PlayerEvents = Toggle(file, "3 - Combat", "PlayerEvents", "Player-based raid events."); StaminaPercent = Percent(file, "4 - Survival", "StaminaPercent", 100f, "Stamina drain. Lower = less drain. 100 = vanilla."); MoveStaminaPercent = Percent(file, "4 - Survival", "MoveStaminaPercent", 100f, "Movement stamina drain. 100 = vanilla."); StaminaRegenPercent = Percent(file, "4 - Survival", "StaminaRegenPercent", 100f, "Stamina regen. Higher = faster. 100 = vanilla."); EitrPercent = Percent(file, "4 - Survival", "EitrPercent", 100f, "Eitr rate. 100 = vanilla."); AdrenalinePercent = Percent(file, "4 - Survival", "AdrenalinePercent", 100f, "Adrenaline rate. 100 = vanilla."); FoodPercent = Percent(file, "4 - Survival", "FoodPercent", 100f, "Food duration scaling. 100 = vanilla."); DurabilityPercent = Percent(file, "4 - Survival", "DurabilityPercent", 100f, "Tool/weapon durability loss. Lower = lasts longer. 100 = vanilla."); CarryWeightPercent = Percent(file, "4 - Survival", "CarryWeightPercent", 100f, "Carry weight. 200 = x2 capacity. 100 = vanilla."); ResourceRatePercent = Percent(file, "5 - Resources", "ResourceRatePercent", 100f, "GLOBAL drop rate (vanilla World Modifier ResourceRate). 100 = vanilla, 200 = x2. Synced to all clients."); CategoryGroundAmp = file.Bind<bool>("6 - Loot", "CategoryGroundAmp", true, "Server amplifies categorized ground loot after it spawns (vanilla/PS5 clients OK). Player-thrown items are skipped."); SnapExtraDropsToGround = file.Bind<bool>("6 - Loot", "SnapExtraDropsToGround", true, "Place amplified extra piles on the ground (fixes floating server extras)."); ExtraDropScatterForce = file.Bind<float>("6 - Loot", "ExtraDropScatterForce", 4f, new ConfigDescription("Physics push on extra piles (vanilla mob loot uses ~5). 0 = no push.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 20f), Array.Empty<object>())); OtherDropMultiplier = Mult(file, "6 - Loot", "OtherDropMultiplier", LegacyFloat(file, "OtherDropMultiplier", 1f), "Anything not matched below. Keep at 1 unless you want everything amplified."); float def = LegacyFloat(file, "WoodDropMultiplier", 1f); WoodDropMultiplier = Mult(file, "6a - Materials", "WoodDropMultiplier", def, "Basic wood."); FineWoodDropMultiplier = Mult(file, "6a - Materials", "FineWoodDropMultiplier", def, "Fine wood."); CoreWoodDropMultiplier = Mult(file, "6a - Materials", "CoreWoodDropMultiplier", def, "Core wood (RoundLog)."); SpecialWoodDropMultiplier = Mult(file, "6a - Materials", "SpecialWoodDropMultiplier", def, "Elder bark, Yggdrasil, Ash, Black wood."); float def2 = LegacyFloat(file, "OreDropMultiplier", 1f); OreDropMultiplier = Mult(file, "6a - Materials", "OreDropMultiplier", def2, "Raw ores."); ScrapDropMultiplier = Mult(file, "6a - Materials", "ScrapDropMultiplier", def2, "Iron/black metal/copper scrap."); float def3 = LegacyFloat(file, "StoneDropMultiplier", 1f); StoneDropMultiplier = Mult(file, "6a - Materials", "StoneDropMultiplier", def3, "Stone and similar."); FlintDropMultiplier = Mult(file, "6a - Materials", "FlintDropMultiplier", def3, "Flint."); CrystalDropMultiplier = Mult(file, "6a - Materials", "CrystalDropMultiplier", def3, "Crystal, obsidian."); FuelDropMultiplier = Mult(file, "6a - Materials", "FuelDropMultiplier", LegacyFloat(file, "FuelDropMultiplier", 1f), "Coal, resin, tar."); GemDropMultiplier = Mult(file, "6a - Materials", "GemDropMultiplier", LegacyFloat(file, "GemDropMultiplier", 1f), "Coins, amber, rubies, necklace."); BossDropMultiplier = Mult(file, "6a - Materials", "BossDropMultiplier", LegacyFloat(file, "BossDropMultiplier", 1f), "Boss materials and boss trophies."); float def4 = LegacyFloat(file, "CropDropMultiplier", 1f); CropDropMultiplier = Mult(file, "6b - Consumables", "CropDropMultiplier", def4, "Crops / plants when they spawn as ground ItemDrops."); SeedDropMultiplier = Mult(file, "6b - Consumables", "SeedDropMultiplier", def4, "Seeds and cones."); MushroomDropMultiplier = Mult(file, "6b - Consumables", "MushroomDropMultiplier", 1f, "Mushrooms / magecap."); BerryHoneyDropMultiplier = Mult(file, "6b - Consumables", "BerryHoneyDropMultiplier", 1f, "Berries, honey."); FishDropMultiplier = Mult(file, "6b - Consumables", "FishDropMultiplier", 1f, "Fish and similar."); PotionDropMultiplier = Mult(file, "6b - Consumables", "PotionDropMultiplier", 1f, "Meads / potions if they land as ground loot."); HideDropMultiplier = Mult(file, "6c - Mob Drops", "HideDropMultiplier", LegacyFloat(file, "HideDropMultiplier", 1f), "Hides, leather, pelts, scales."); TrophyDropMultiplier = Mult(file, "6c - Mob Drops", "TrophyDropMultiplier", 1f, "Normal mob trophies."); MeatDropMultiplier = Mult(file, "6c - Mob Drops", "MeatDropMultiplier", 1f, "Raw / cooked meat drops."); PartsDropMultiplier = Mult(file, "6c - Mob Drops", "PartsDropMultiplier", LegacyFloat(file, "PartsDropMultiplier", 1f), "Bones, entrails, eyes, glands, fangs."); FeatherDropMultiplier = Mult(file, "6c - Mob Drops", "FeatherDropMultiplier", 1f, "Feathers."); SpecialPartsDropMultiplier = Mult(file, "6c - Mob Drops", "SpecialPartsDropMultiplier", 1f, "Guck, ooze, soft tissue, carapace, bile, …"); DeathKeepEquip = Toggle(file, "7 - Death", "DeathKeepEquip", "Keep equipped gear on death."); DeathKeepInventory = Toggle(file, "7 - Death", "DeathKeepInventory", "Keep full inventory on death."); DeathDeleteItems = Toggle(file, "7 - Death", "DeathDeleteItems", "Delete items on death."); DeathDeleteUnequipped = Toggle(file, "7 - Death", "DeathDeleteUnequipped", "Delete unequipped items on death."); DeathSkillsReset = Toggle(file, "7 - Death", "DeathSkillsReset", "Reset skills on death."); NoBuildCost = Toggle(file, "8 - Build Craft", "NoBuildCost", "Building costs nothing."); NoCraftCost = Toggle(file, "8 - Build Craft", "NoCraftCost", "Crafting costs nothing."); AllPiecesUnlocked = Toggle(file, "8 - Build Craft", "AllPiecesUnlocked", "All build pieces unlocked."); AllRecipesUnlocked = Toggle(file, "8 - Build Craft", "AllRecipesUnlocked", "All recipes unlocked."); NoWorkbench = Toggle(file, "8 - Build Craft", "NoWorkbench", "No workbench range required."); WorldLevelLockedTools = Toggle(file, "8 - Build Craft", "WorldLevelLockedTools", "World-level tool locks."); NoMap = Toggle(file, "9 - Map Portals", "NoMap", "Disable map."); NoPortals = Toggle(file, "9 - Map Portals", "NoPortals", "Disable portals."); NoBossPortals = Toggle(file, "9 - Map Portals", "NoBossPortals", "Disable boss portals."); TeleportAll = Toggle(file, "9 - Map Portals", "TeleportAll", "Teleport with ores/metals."); DungeonBuild = Toggle(file, "9 - Map Portals", "DungeonBuild", "Allow building in dungeons."); NoPseudoDrops = Toggle(file, "10 - World Flags", "NoPseudoDrops", "Disable pseudo drops."); NoBuildingFall = Toggle(file, "10 - World Flags", "NoBuildingFall", "Buildings do not fall."); NoHeavySnow = Toggle(file, "10 - World Flags", "NoHeavySnow", "No heavy snow."); AllHeavySnow = Toggle(file, "10 - World Flags", "AllHeavySnow", "Force heavy snow rules."); Fire = Toggle(file, "10 - World Flags", "Fire", "Fire-related world flag."); SmelterSpeedMultiplier = Mult(file, "11 - Stations", "SmelterSpeedMultiplier", 1f, "Smelter / kiln / similar. 2 = twice as fast."); FermenterSpeedMultiplier = Mult(file, "11 - Stations", "FermenterSpeedMultiplier", 1f, "Fermenter speed. 2 = twice as fast."); CookingSpeedMultiplier = Mult(file, "11 - Stations", "CookingSpeedMultiplier", 1f, "Cooking station speed. 2 = twice as fast."); PlantGrowSpeedMultiplier = Mult(file, "11 - Stations", "PlantGrowSpeedMultiplier", 1f, "Plant grow speed. 2 = twice as fast (half grow time)."); } private static ConfigEntry<float> Percent(ConfigFile file, string section, string key, float def, string desc) { //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Expected O, but got Unknown return file.Bind<float>(section, key, def, new ConfigDescription(desc, (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 10000f), Array.Empty<object>())); } private static ConfigEntry<float> Mult(ConfigFile file, string section, string key, float def, string desc) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Expected O, but got Unknown return file.Bind<float>(section, key, def, new ConfigDescription(desc + " 1 = vanilla.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 100f), Array.Empty<object>())); } private static float LegacyFloat(ConfigFile file, string key, float fallback) { try { string configFilePath = file.ConfigFilePath; if (string.IsNullOrEmpty(configFilePath) || !File.Exists(configFilePath)) { return fallback; } string text = null; string[] array = File.ReadAllLines(configFilePath); for (int i = 0; i < array.Length; i++) { string text2 = array[i].Trim(); if (text2.Length == 0 || text2.StartsWith("#")) { continue; } if (text2.StartsWith("[") && text2.EndsWith("]")) { text = text2.Substring(1, text2.Length - 2); } else { if (text != "6 - Drop Categories") { continue; } int num = text2.IndexOf('='); if (num > 0 && string.Equals(text2.Substring(0, num).Trim(), key, StringComparison.OrdinalIgnoreCase)) { string text3 = text2.Substring(num + 1).Trim(); int num2 = text3.IndexOf('#'); if (num2 >= 0) { text3 = text3.Substring(0, num2).Trim(); } if (float.TryParse(text3, NumberStyles.Float, CultureInfo.InvariantCulture, out var result)) { return result; } } } } } catch { } return fallback; } private static ConfigEntry<string> Toggle(ConfigFile file, string section, string key, string desc) { //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Expected O, but got Unknown return file.Bind<string>(section, key, "Unchanged", new ConfigDescription(desc + " Values: Unchanged | On | Off", (AcceptableValueBase)(object)ToggleValues, Array.Empty<object>())); } } [HarmonyPatch(typeof(ZNet), "Awake")] internal static class ZNetAwakePatch { private static void Postfix(ZNet __instance) { Plugin.TryActivate(__instance); } } [HarmonyPatch(typeof(ZoneSystem), "Start")] internal static class ZoneSystemStartPatch { private static void Postfix() { if ((Object)(object)ZNet.instance != (Object)null) { Plugin.TryActivate(ZNet.instance); } RateApplier.ApplyGlobalKeys(); } } [HarmonyPatch(typeof(Game), "UpdateWorldRates")] internal static class UpdateWorldRatesPatch { private static void Postfix() { RateApplier.ApplyGlobalKeys(); } } internal static class DropScale { public static bool Ready() { if (Plugin.Active && Plugin.Settings != null && Plugin.Settings.Enabled.Value && (Object)(object)ZNet.instance != (Object)null) { return ZNet.instance.IsDedicated(); } return false; } } [HarmonyPatch(typeof(Smelter), "GetDeltaTime")] internal static class SmelterSpeedPatch { private static void Postfix(ref double __result) { float num = StationRates.Mult((Plugin.Settings != null) ? Plugin.Settings.SmelterSpeedMultiplier.Value : 1f); if (num > 0f && !Mathf.Approximately(num, 1f)) { __result *= num; } } } [HarmonyPatch(typeof(Fermenter), "GetFermentationTime")] internal static class FermenterSpeedPatch { private static void Postfix(ref double __result) { float num = StationRates.Mult((Plugin.Settings != null) ? Plugin.Settings.FermenterSpeedMultiplier.Value : 1f); if (num > 0f && !Mathf.Approximately(num, 1f)) { __result *= num; } } } [HarmonyPatch(typeof(CookingStation), "GetDeltaTime")] internal static class CookingSpeedPatch { private static void Postfix(ref float __result) { float num = StationRates.Mult((Plugin.Settings != null) ? Plugin.Settings.CookingSpeedMultiplier.Value : 1f); if (num > 0f && !Mathf.Approximately(num, 1f)) { __result *= num; } } } [HarmonyPatch(typeof(Plant), "GetGrowTime")] internal static class PlantGrowSpeedPatch { private static void Postfix(ref float __result) { float num = StationRates.Mult((Plugin.Settings != null) ? Plugin.Settings.PlantGrowSpeedMultiplier.Value : 1f); if (num > 0f && !Mathf.Approximately(num, 1f)) { __result /= num; } } } internal static class StationRates { public static float Mult(float value) { if (!DropScale.Ready()) { return 1f; } return Mathf.Max(0.01f, value); } } [BepInPlugin("com.morda.serverrates", "ServerRates", "1.4.9")] public class Plugin : BaseUnityPlugin { public const string ModGuid = "com.morda.serverrates"; public const string ModName = "ServerRates"; public const string ModVersion = "1.4.9"; public const string ModAuthor = "Morda"; private Harmony _harmony; internal static Plugin Instance { get; private set; } internal static ManualLogSource Log { get; private set; } internal static ModConfig Settings { get; private set; } internal static bool Active { get; private set; } private void Awake() { //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Expected O, but got Unknown Instance = this; Log = ((BaseUnityPlugin)this).Logger; Settings = new ModConfig(((BaseUnityPlugin)this).Config); _harmony = new Harmony("com.morda.serverrates"); _harmony.PatchAll(Assembly.GetExecutingAssembly()); ConfigWatch.Start(); ((BaseUnityPlugin)this).Logger.LogInfo((object)"ServerRates v1.4.9 by Morda loaded (dedicated server only — vanilla clients OK)."); } private void Update() { ConfigWatch.Tick(); if (Active) { CategoryGroundAmp.Tick(); } } private void OnDestroy() { Harmony harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } if ((Object)(object)Instance == (Object)(object)this) { Instance = null; } Active = false; } internal static void TryActivate(ZNet net) { if ((Object)(object)net == (Object)null || !net.IsDedicated()) { Active = false; if ((Object)(object)net != (Object)null && net.IsServer() && !net.IsDedicated()) { Log.LogWarning((object)"ServerRates: listen/host worlds are not supported. Use a dedicated server."); } } else { Active = true; Log.LogInfo((object)"ServerRates: dedicated server detected — rates enabled."); RateApplier.ApplyGlobalKeys(); CategoryGroundAmp.LogStatus(); RatesCommands.Register(); } } } internal static class RateApplier { private static bool _busy; private static bool _logged; public static void ApplyGlobalKeys() { if (_busy || !Plugin.Active || Plugin.Settings == null || !Plugin.Settings.Enabled.Value || (Object)(object)ZoneSystem.instance == (Object)null) { return; } ModConfig settings = Plugin.Settings; _busy = true; try { bool flag = false; flag |= SetScalar((GlobalKeys)12, settings.SkillGainPercent.Value); flag |= SetScalar((GlobalKeys)13, settings.SkillReductionPercent.Value); flag |= SetScalar((GlobalKeys)0, settings.PlayerDamagePercent.Value); flag |= SetScalar((GlobalKeys)1, settings.EnemyDamagePercent.Value); flag |= SetScalar((GlobalKeys)14, settings.EnemySpeedSizePercent.Value); flag |= SetScalar((GlobalKeys)15, settings.EnemyLevelUpPercent.Value); flag |= SetScalar((GlobalKeys)3, settings.EventRatePercent.Value); flag |= SetWorldLevel(settings.WorldLevel.Value); flag |= SetScalar((GlobalKeys)5, settings.StaminaPercent.Value); flag |= SetScalar((GlobalKeys)10, settings.MoveStaminaPercent.Value); flag |= SetScalar((GlobalKeys)11, settings.StaminaRegenPercent.Value); flag |= SetScalar((GlobalKeys)7, settings.EitrPercent.Value); flag |= SetScalar((GlobalKeys)6, settings.AdrenalinePercent.Value); flag |= SetScalar((GlobalKeys)9, settings.FoodPercent.Value); flag |= SetScalar((GlobalKeys)8, settings.DurabilityPercent.Value); flag |= SetScalar((GlobalKeys)16, settings.CarryWeightPercent.Value); flag |= SetScalar((GlobalKeys)4, settings.ResourceRatePercent.Value); flag |= SetToggle((GlobalKeys)30, settings.PassiveMobs.Value); flag |= SetToggle((GlobalKeys)17, settings.PlayerEvents.Value); flag |= SetToggle((GlobalKeys)19, settings.DeathKeepEquip.Value); flag |= SetToggle((GlobalKeys)23, settings.DeathKeepInventory.Value); flag |= SetToggle((GlobalKeys)20, settings.DeathDeleteItems.Value); flag |= SetToggle((GlobalKeys)21, settings.DeathDeleteUnequipped.Value); flag |= SetToggle((GlobalKeys)22, settings.DeathSkillsReset.Value); flag |= SetToggle((GlobalKeys)24, settings.NoBuildCost.Value); flag |= SetToggle((GlobalKeys)25, settings.NoCraftCost.Value); flag |= SetToggle((GlobalKeys)26, settings.AllPiecesUnlocked.Value); flag |= SetToggle((GlobalKeys)28, settings.AllRecipesUnlocked.Value); flag |= SetToggle((GlobalKeys)27, settings.NoWorkbench.Value); flag |= SetToggle((GlobalKeys)29, settings.WorldLevelLockedTools.Value); flag |= SetToggle((GlobalKeys)31, settings.NoMap.Value); flag |= SetToggle((GlobalKeys)32, settings.NoPortals.Value); flag |= SetToggle((GlobalKeys)33, settings.NoBossPortals.Value); flag |= SetToggle((GlobalKeys)35, settings.TeleportAll.Value); flag |= SetToggle((GlobalKeys)34, settings.DungeonBuild.Value); flag |= SetToggle((GlobalKeys)36, settings.NoPseudoDrops.Value); flag |= SetToggle((GlobalKeys)37, settings.NoBuildingFall.Value); flag |= SetToggle((GlobalKeys)38, settings.NoHeavySnow.Value); flag |= SetToggle((GlobalKeys)39, settings.AllHeavySnow.Value); flag |= SetToggle((GlobalKeys)18, settings.Fire.Value); if (!_logged) { _logged = true; Plugin.Log.LogInfo((object)"ServerRates global keys applied (percent keys: 100 = vanilla)."); } else if (flag) { Plugin.Log.LogInfo((object)"ServerRates global keys refreshed live (no restart)."); } } finally { _busy = false; } } public static void NotifyConfigReloaded() { _logged = false; } private static bool SetScalar(GlobalKeys key, float value) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) value = Mathf.Max(0f, value); float num = default(float); if (ZoneSystem.instance.GetGlobalKey(key, ref num) && Mathf.Abs(num - value) < 0.001f) { return false; } ZoneSystem.instance.SetGlobalKey(key, value); return true; } private static bool SetWorldLevel(int level) { level = Mathf.Clamp(level, 0, 10); float num = default(float); if (ZoneSystem.instance.GetGlobalKey((GlobalKeys)2, ref num) && Mathf.Abs(num - (float)level) < 0.001f) { return false; } ZoneSystem.instance.SetGlobalKey((GlobalKeys)2, (float)level); return true; } private static bool SetToggle(GlobalKeys key, string mode) { //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) string text = (mode ?? "Unchanged").Trim(); if (text.Equals("Unchanged", StringComparison.OrdinalIgnoreCase)) { return false; } bool flag = text.Equals("On", StringComparison.OrdinalIgnoreCase) || text.Equals("True", StringComparison.OrdinalIgnoreCase) || text.Equals("1", StringComparison.OrdinalIgnoreCase); bool flag2 = text.Equals("Off", StringComparison.OrdinalIgnoreCase) || text.Equals("False", StringComparison.OrdinalIgnoreCase) || text.Equals("0", StringComparison.OrdinalIgnoreCase); if (!flag && !flag2) { return false; } bool globalKey = ZoneSystem.instance.GetGlobalKey(key); if (flag) { if (globalKey) { return false; } ZoneSystem.instance.SetGlobalKey(key); return true; } if (!globalKey) { return false; } ZoneSystem.instance.RemoveGlobalKey(key); return true; } } internal static class RatesChat { [HarmonyPatch(typeof(Chat), "RPC_ChatMessage")] private static class ChatRpcPatch { private static bool Prefix(long sender, Vector3 position, int type, UserInfo userInfo, string text) { if (!Plugin.Active || Plugin.Settings == null) { return true; } if (!Plugin.Settings.ChatCommandsEnabled.Value) { return true; } if (string.IsNullOrWhiteSpace(text)) { return true; } string text2 = Plugin.Settings.ChatCommandPrefix.Value ?? "!"; if (string.IsNullOrEmpty(text2)) { text2 = "!"; } string text3 = text.Trim(); if (!text3.StartsWith(text2, StringComparison.OrdinalIgnoreCase)) { return true; } string text4 = text3.Substring(text2.Length).Trim(); if (text4.Length == 0) { return true; } if (!LooksLikeRatesCommand(text4)) { return true; } string text5 = ((userInfo != null && !string.IsNullOrEmpty(userInfo.Name)) ? userInfo.Name : "player"); ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)("ServerRates chat cmd from " + text5 + ": " + text4)); } RatesCommands.EnsureMaps(); RatesCommands.ProcessLine(text4, delegate(string s) { RatesFeedback.Say(s, yellowHud: false); }); return false; } } private static bool LooksLikeRatesCommand(string body) { string text = body.ToLowerInvariant(); if (text.StartsWith("rates") || text.StartsWith("sr_") || text.StartsWith("sr ")) { return true; } int num = body.IndexOf(' '); return RatesCommands.IsKnownShortOrKey((num > 0) ? body.Substring(0, num) : body); } } internal static class RatesCommands { private static bool _added; private static string[] _keyCache; private static readonly Dictionary<string, string> ShortToKey = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase); private static readonly Dictionary<string, string> KeyToShort = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase); private static bool _mapBuilt; public static void EnsureMaps() { if (!_mapBuilt) { BuildShortNameMap(); _mapBuilt = true; } } public static bool IsKnownShortOrKey(string token) { EnsureMaps(); if (string.IsNullOrEmpty(token)) { return false; } if (ShortToKey.ContainsKey(token)) { return true; } if (token.StartsWith("sr_", StringComparison.OrdinalIgnoreCase) && ShortToKey.ContainsKey(token.Substring(3))) { return true; } return FindProp(token) != null; } public static void ProcessLine(string line, Action<string> reply) { if (reply == null) { return; } EnsureMaps(); if (!Plugin.Active || (Object)(object)ZNet.instance == (Object)null || !ZNet.instance.IsDedicated()) { reply("ServerRates: commands only work on the dedicated server."); return; } string[] array = SplitArgs(line); if (array.Length == 0) { PrintHelp(reply); return; } string text = array[0]; string text2 = text.ToLowerInvariant(); if (text2.StartsWith("sr_") || ShortToKey.ContainsKey(text) || FindProp(text) != null) { string text3 = ResolveKey(text); if (text3 == null) { reply("ServerRates: unknown '" + text + "' — try !rates cmds"); return; } string value; string text4 = (KeyToShort.TryGetValue(text3, out value) ? value : text); if (array.Length < 2) { if (TryGet(text3, out var text5, out var error)) { reply("ServerRates: " + text5 + " (set: !sr_" + text4 + " <value>)"); } else { reply("rates get failed: " + error); } } else { ApplySet(reply, text3, JoinParts(array, 1)); } } else if (text2 == "rates") { ProcessRatesMeta(array, reply); } else { PrintHelp(reply); } } private static void ProcessRatesMeta(string[] parts, Action<string> reply) { if (parts.Length < 2) { PrintHelp(reply); return; } string text = parts[1].ToLowerInvariant(); if (ShortToKey.TryGetValue(text, out var _) || KeyToShort.ContainsKey(parts[1])) { string value2; string text2 = (ShortToKey.TryGetValue(text, out value2) ? value2 : FindProp(parts[1])?.Name); if (text2 == null) { PrintHelp(reply); } else if (parts.Length < 3) { if (TryGet(text2, out var text3, out var error)) { reply("ServerRates: " + text3); } else { reply("rates get failed: " + error); } } else { ApplySet(reply, text2, JoinParts(parts, 2)); } return; } switch (text) { case "help": case "?": PrintHelp(reply); break; case "status": PrintStatus(reply, all: false); break; case "list": case "keys": PrintStatus(reply, all: true); break; case "cmds": case "commands": PrintAllCommands(reply); break; case "get": { if (parts.Length < 3) { reply("Usage: !rates get <Key|short>"); break; } string text5 = ResolveKey(parts[2]); string text6; string error2; if (text5 == null) { reply("unknown key '" + parts[2] + "' (!rates cmds)"); } else if (!TryGet(text5, out text6, out error2)) { reply("rates get failed: " + error2); } else { reply("ServerRates: " + text6); } break; } case "set": case "apply": { if (parts.Length < 4) { reply("Usage: !rates set <Key|short> <value>"); break; } string text4 = ResolveKey(parts[2]); if (text4 == null) { reply("unknown key '" + parts[2] + "' (!rates cmds)"); } else { ApplySet(reply, text4, JoinParts(parts, 3)); } break; } default: PrintHelp(reply); break; } } private static string[] SplitArgs(string line) { if (string.IsNullOrWhiteSpace(line)) { return Array.Empty<string>(); } return line.Split(new char[2] { ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries); } private static string JoinParts(string[] parts, int startIndex) { if (parts == null || startIndex >= parts.Length) { return ""; } if (startIndex == parts.Length - 1) { return parts[startIndex]; } return string.Join(" ", parts, startIndex, parts.Length - startIndex); } public static void Register() { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Expected O, but got Unknown //IL_0043: Expected O, but got Unknown //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_00d9: Expected O, but got Unknown //IL_00d4: Unknown result type (might be due to invalid IL or missing references) if (_added) { return; } _added = true; try { EnsureMaps(); new ConsoleCommand("rates", "ServerRates: status | list | cmds | get <Key> | set <Key> <value> | help", new ConsoleEvent(OnRatesConsole), false, true, true, false, true, false, new ConsoleOptionsFetcher(FetchRatesTabOptions), true, true, false); foreach (KeyValuePair<string, string> item in ShortToKey) { string key = item.Key; string value = item.Value; string text = "sr_" + key; string keyCapture = value; string shortCapture = key; new ConsoleCommand(text, "ServerRates " + value + " — sr_" + shortCapture + " [value]", (ConsoleEvent)delegate(ConsoleEventArgs args) { OnSingleRate(args, keyCapture, shortCapture); }, false, true, true, false, true, false, (ConsoleOptionsFetcher)null, false, true, false); } ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)("ServerRates: registered " + ShortToKey.Count + " rate commands (sr_* + chat !" + (Plugin.Settings?.ChatCommandPrefix?.Value ?? "!") + ").")); } } catch (Exception ex) { _added = false; ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogError((object)("ServerRates: failed to register console commands: " + ex)); } } } private static void BuildShortNameMap() { ShortToKey.Clear(); KeyToShort.Clear(); AddShort("Enabled", "enabled"); AddShort("SkillGainPercent", "skillgain"); AddShort("SkillReductionPercent", "skillloss"); AddShort("PlayerDamagePercent", "playerdmg"); AddShort("EnemyDamagePercent", "enemydmg"); AddShort("EnemySpeedSizePercent", "enemyspeed"); AddShort("EnemyLevelUpPercent", "enemystars"); AddShort("EventRatePercent", "events"); AddShort("WorldLevel", "worldlevel"); AddShort("PassiveMobs", "passivemobs"); AddShort("PlayerEvents", "playerevents"); AddShort("StaminaPercent", "stamina"); AddShort("MoveStaminaPercent", "movestamina"); AddShort("StaminaRegenPercent", "staminaregen"); AddShort("EitrPercent", "eitr"); AddShort("AdrenalinePercent", "adrenaline"); AddShort("FoodPercent", "food"); AddShort("DurabilityPercent", "durability"); AddShort("CarryWeightPercent", "carry"); AddShort("ResourceRatePercent", "resourcerate"); AddShort("CategoryGroundAmp", "groundamp"); AddShort("SnapExtraDropsToGround", "snapground"); AddShort("ExtraDropScatterForce", "scatter"); AddShort("OtherDropMultiplier", "other"); AddShort("WoodDropMultiplier", "wood"); AddShort("FineWoodDropMultiplier", "finewood"); AddShort("CoreWoodDropMultiplier", "corewood"); AddShort("SpecialWoodDropMultiplier", "specialwood"); AddShort("OreDropMultiplier", "ore"); AddShort("ScrapDropMultiplier", "scrap"); AddShort("StoneDropMultiplier", "stone"); AddShort("FlintDropMultiplier", "flint"); AddShort("CrystalDropMultiplier", "crystal"); AddShort("FuelDropMultiplier", "fuel"); AddShort("GemDropMultiplier", "gems"); AddShort("BossDropMultiplier", "boss"); AddShort("CropDropMultiplier", "crops"); AddShort("SeedDropMultiplier", "seeds"); AddShort("MushroomDropMultiplier", "mushrooms"); AddShort("BerryHoneyDropMultiplier", "berries"); AddShort("FishDropMultiplier", "fish"); AddShort("PotionDropMultiplier", "potions"); AddShort("HideDropMultiplier", "hide"); AddShort("TrophyDropMultiplier", "trophy"); AddShort("MeatDropMultiplier", "meat"); AddShort("PartsDropMultiplier", "parts"); AddShort("FeatherDropMultiplier", "feathers"); AddShort("SpecialPartsDropMultiplier", "specialparts"); AddShort("DeathKeepEquip", "keepequip"); AddShort("DeathKeepInventory", "keepinv"); AddShort("DeathDeleteItems", "deleteitems"); AddShort("DeathDeleteUnequipped", "deleteunequipped"); AddShort("DeathSkillsReset", "skillreset"); AddShort("NoBuildCost", "nobuildcost"); AddShort("NoCraftCost", "nocraftcost"); AddShort("AllPiecesUnlocked", "allpieces"); AddShort("AllRecipesUnlocked", "allrecipes"); AddShort("NoWorkbench", "noworkbench"); AddShort("WorldLevelLockedTools", "toollocks"); AddShort("NoMap", "nomap"); AddShort("NoPortals", "noportals"); AddShort("NoBossPortals", "nobossportals"); AddShort("TeleportAll", "teleportall"); AddShort("DungeonBuild", "dungeonbuild"); AddShort("NoPseudoDrops", "nopseudo"); AddShort("NoBuildingFall", "nobuildfall"); AddShort("NoHeavySnow", "noheavysnow"); AddShort("AllHeavySnow", "allheavysnow"); AddShort("Fire", "fire"); AddShort("SmelterSpeedMultiplier", "smelter"); AddShort("FermenterSpeedMultiplier", "fermenter"); AddShort("CookingSpeedMultiplier", "cooking"); AddShort("PlantGrowSpeedMultiplier", "plants"); PropertyInfo[] properties = typeof(ModConfig).GetProperties(BindingFlags.Instance | BindingFlags.Public); foreach (PropertyInfo propertyInfo in properties) { if (IsConfigEntry(propertyInfo.PropertyType) && !KeyToShort.ContainsKey(propertyInfo.Name)) { string shortName = AutoShort(propertyInfo.Name); AddShort(propertyInfo.Name, shortName); } } } private static void AddShort(string propName, string shortName) { if (ShortToKey.ContainsKey(shortName)) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("ServerRates: duplicate short name '" + shortName + "' for " + propName)); } shortName += "2"; } ShortToKey[shortName] = propName; KeyToShort[propName] = shortName; } private static string AutoShort(string propName) { string text = propName; if (text.EndsWith("DropMultiplier", StringComparison.Ordinal)) { text = text.Substring(0, text.Length - "DropMultiplier".Length); } else if (text.EndsWith("SpeedMultiplier", StringComparison.Ordinal)) { text = text.Substring(0, text.Length - "SpeedMultiplier".Length) + "speed"; } else if (text.EndsWith("Percent", StringComparison.Ordinal)) { text = text.Substring(0, text.Length - "Percent".Length); } else if (text.EndsWith("Multiplier", StringComparison.Ordinal)) { text = text.Substring(0, text.Length - "Multiplier".Length); } return text.ToLowerInvariant(); } private static List<string> FetchRatesTabOptions() { List<string> list = new List<string>(); list.Add("status"); list.Add("list"); list.Add("cmds"); list.Add("get"); list.Add("set"); list.Add("help"); list.AddRange(ShortToKey.Keys); list.AddRange(GetAllKeys()); return list; } private static string[] GetAllKeys() { if (_keyCache != null) { return _keyCache; } List<string> list = new List<string>(); PropertyInfo[] properties = typeof(ModConfig).GetProperties(BindingFlags.Instance | BindingFlags.Public); foreach (PropertyInfo propertyInfo in properties) { if (IsConfigEntry(propertyInfo.PropertyType)) { list.Add(propertyInfo.Name); } } list.Sort(StringComparer.OrdinalIgnoreCase); _keyCache = list.ToArray(); return _keyCache; } private static bool IsConfigEntry(Type t) { if (t != null && t.IsGenericType) { return t.GetGenericTypeDefinition() == typeof(ConfigEntry<>); } return false; } private static void OnSingleRate(ConsoleEventArgs args, string propName, string shortName) { if (!((Object)(object)args?.Context == (Object)null)) { Action<string> reply = delegate(string s) { RatesFeedback.Say(s, yellowHud: false); }; if (args.Length < 2) { ProcessLine("sr_" + shortName, reply); } else { ProcessLine("sr_" + shortName + " " + JoinArgsFrom(args, 1), reply); } } } private static void OnRatesConsole(ConsoleEventArgs args) { if (!((Object)(object)args?.Context == (Object)null)) { Action<string> reply = delegate(string s) { RatesFeedback.Say(s, yellowHud: false); }; if (args.Length < 2) { ProcessLine("rates", reply); } else { ProcessLine("rates " + JoinArgsFrom(args, 1), reply); } } } private static string ResolveKey(string raw) { if (ShortToKey.TryGetValue(raw, out var value)) { return value; } if (raw.StartsWith("sr_", StringComparison.OrdinalIgnoreCase) && ShortToKey.TryGetValue(raw.Substring(3), out var value2)) { return value2; } return FindProp(raw)?.Name; } private static string JoinArgsFrom(ConsoleEventArgs args, int startIndex) { if (args.Args == null || startIndex >= args.Args.Length) { if (args.Length <= startIndex) { return ""; } return args[startIndex]; } if (startIndex == args.Args.Length - 1) { return args.Args[startIndex]; } return string.Join(" ", args.Args, startIndex, args.Args.Length - startIndex); } private static void ApplySet(Action<string> reply, string propName, string value) { if (!TrySet(propName, value, out var error, out var applied)) { reply("rates set failed: " + error); return; } ConfigWatch.SuppressReloadBriefly(); if ((Object)(object)Plugin.Instance != (Object)null) { ((BaseUnityPlugin)Plugin.Instance).Config.Save(); } RateApplier.NotifyConfigReloaded(); RateApplier.ApplyGlobalKeys(); CategoryGroundAmp.LogStatus(); string value2; string text = (KeyToShort.TryGetValue(propName, out value2) ? value2 : propName); RatesFeedback.Say(FormatHudMessage(propName, applied), yellowHud: true); ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)("ServerRates command live-applied: " + propName + "=" + applied + " (sr_" + text + ")")); } } private static string FormatHudMessage(string propName, string applied) { string text = FriendlyHudLabel(propName); if (propName.EndsWith("Percent", StringComparison.Ordinal)) { return text + " " + applied + "%"; } if (propName.EndsWith("Multiplier", StringComparison.Ordinal) || propName.Equals("ExtraDropScatterForce", StringComparison.OrdinalIgnoreCase) || propName.Equals("WorldLevel", StringComparison.OrdinalIgnoreCase)) { return text + " Multiplier x" + applied; } if (!propName.EndsWith("Enabled", StringComparison.Ordinal) && !propName.Contains("Amp")) { propName.Contains("Snap"); } return text + ": " + applied; } private static string FriendlyHudLabel(string propName) { if (KeyToShort.TryGetValue(propName, out var value)) { switch (value) { case "wood": return "Wood"; case "finewood": return "Fine Wood"; case "corewood": return "Core Wood"; case "specialwood": return "Special Wood"; case "ore": return "Ore"; case "scrap": return "Scrap"; case "stone": return "Stone"; case "flint": return "Flint"; case "crystal": return "Crystal"; case "fuel": return "Fuel"; case "gems": return "Gems"; case "boss": return "Boss Mats"; case "crops": return "Crops"; case "seeds": return "Seeds"; case "mushrooms": return "Mushrooms"; case "berries": return "Berries"; case "fish": return "Fish"; case "potions": return "Potions"; case "hide": return "Hide"; case "trophy": return "Trophy"; case "meat": return "Meat"; case "parts": return "Parts"; case "feathers": return "Feathers"; case "specialparts": return "Special Parts"; case "resourcerate": return "Resource Rate"; case "skillgain": return "Skill Gain"; case "skillloss": return "Skill Loss"; case "playerdmg": return "Player Damage"; case "enemydmg": return "Enemy Damage"; case "groundamp": return "Ground Amp"; case "teleportall": return "Teleport All"; case "smelter": return "Smelter"; case "fermenter": return "Fermenter"; case "cooking": return "Cooking"; case "plants": return "Plant Grow"; case "other": return "Other Loot"; case "scatter": return "Drop Scatter"; } } string text = propName; if (text.EndsWith("DropMultiplier")) { text = text.Substring(0, text.Length - "DropMultiplier".Length); } else if (text.EndsWith("SpeedMultiplier")) { text = text.Substring(0, text.Length - "SpeedMultiplier".Length); } else if (text.EndsWith("Percent")) { text = text.Substring(0, text.Length - "Percent".Length); } else if (text.EndsWith("Multiplier")) { text = text.Substring(0, text.Length - "Multiplier".Length); } return Regex.Replace(text, "([a-z])([A-Z])", "$1 $2"); } private static void ShowYellowHud(string text) { RatesFeedback.ShowYellowHud(text); } private static void PrintHelp(Action<string> reply) { string text = Plugin.Settings?.ChatCommandPrefix?.Value ?? "!"; StringBuilder stringBuilder = new StringBuilder(); stringBuilder.AppendLine("ServerRates — chat or F5 (no admin needed):"); stringBuilder.AppendLine(" " + text + "sr_wood 9 " + text + "sr_meat 5 " + text + "sr_teleportall On"); stringBuilder.AppendLine(" " + text + "sr_resourcerate 200"); stringBuilder.AppendLine(" " + text + "sr_wood (no value = show current)"); stringBuilder.AppendLine(" rates cmds | status | list | help"); stringBuilder.AppendLine(" rates set wood 9"); stringBuilder.AppendLine("Percent: 100=vanilla | Mult: 1=vanilla | Toggle: Unchanged|On|Off"); stringBuilder.Append("Applies LIVE."); reply(stringBuilder.ToString()); } private static void PrintAllCommands(Action<string> reply) { string text = Plugin.Settings?.ChatCommandPrefix?.Value ?? "!"; List<string> list = new List<string>(); foreach (KeyValuePair<string, string> item in ShortToKey) { list.Add(text + "sr_" + item.Key + " -> " + item.Value); } list.Sort(StringComparer.OrdinalIgnoreCase); StringBuilder stringBuilder = new StringBuilder(); stringBuilder.AppendLine("ServerRates commands (" + list.Count + "):"); foreach (string item2 in list) { stringBuilder.AppendLine(item2); } reply(stringBuilder.ToString().TrimEnd(Array.Empty<char>())); } private static void PrintStatus(Action<string> reply, bool all) { if (Plugin.Settings == null) { reply("ServerRates: settings not ready"); return; } ModConfig settings = Plugin.Settings; StringBuilder stringBuilder = new StringBuilder(); stringBuilder.AppendLine("ServerRates Active=" + Plugin.Active + " Enabled=" + settings.Enabled.Value); if (!all) { stringBuilder.AppendLine("ResourceRatePercent=" + settings.ResourceRatePercent.Value + " (sr_resourcerate)"); stringBuilder.AppendLine("WoodDropMultiplier=" + settings.WoodDropMultiplier.Value + " (sr_wood)"); stringBuilder.AppendLine("MeatDropMultiplier=" + settings.MeatDropMultiplier.Value + " (sr_meat)"); stringBuilder.AppendLine("HideDropMultiplier=" + settings.HideDropMultiplier.Value + " (sr_hide)"); stringBuilder.AppendLine("OreDropMultiplier=" + settings.OreDropMultiplier.Value + " (sr_ore)"); stringBuilder.AppendLine("CategoryGroundAmp=" + settings.CategoryGroundAmp.Value + " (sr_groundamp)"); stringBuilder.Append("rates list / rates cmds for more"); reply(stringBuilder.ToString()); return; } string[] allKeys = GetAllKeys(); foreach (string key in allKeys) { if (TryGet(key, out var text, out var _)) { string value; string text2 = (KeyToShort.TryGetValue(key, out value) ? (" [sr_" + value + "]") : ""); stringBuilder.AppendLine(text + text2); } } reply(stringBuilder.ToString().TrimEnd(Array.Empty<char>())); } private static bool TryGet(string key, out string text, out string error) { text = null; error = null; if (Plugin.Settings == null) { error = "settings not ready"; return false; } PropertyInfo propertyInfo = FindProp(key); if (propertyInfo == null) { error = "unknown key '" + key + "'"; return false; } object value = propertyInfo.GetValue(Plugin.Settings); PropertyInfo propertyInfo2 = value?.GetType().GetProperty("Value"); if (propertyInfo2 == null) { error = "no Value"; return false; } text = propertyInfo.Name + "=" + FormatValue(propertyInfo2.GetValue(value, null)); return true; } private static string FormatValue(object val) { if (val == null) { return ""; } if (val is float num) { return num.ToString("0.###", CultureInfo.InvariantCulture); } if (val is bool) { if (!(bool)val) { return "false"; } return "true"; } return Convert.ToString(val, CultureInfo.InvariantCulture) ?? ""; } private static PropertyInfo FindProp(string key) { return typeof(ModConfig).GetProperty(key, BindingFlags.IgnoreCase | BindingFlags.Instance | BindingFlags.Public); } private static bool TrySet(string key, string raw, out string error, out string applied) { error = null; applied = null; if (Plugin.Settings == null) { error = "settings not ready"; return false; } PropertyInfo propertyInfo = FindProp(key); if (propertyInfo == null) { error = "unknown key '" + key + "'"; return false; } object value = propertyInfo.GetValue(Plugin.Settings); if (value == null) { error = "null entry"; return false; } Type type = value.GetType(); if (!IsConfigEntry(type)) { error = "not a ConfigEntry"; return false; } Type valueType = type.GetGenericArguments()[0]; PropertyInfo property = type.GetProperty("Value"); if (property == null) { error = "no Value"; return false; } try { object obj = ParseValue(valueType, raw, out error); if (obj == null && error != null) { return false; } property.SetValue(value, obj, null); applied = FormatValue(obj); return true; } catch (Exception ex) { error = ex.Message; return false; } } private static object ParseValue(Type valueType, string raw, out string error) { error = null; string text = (raw ?? "").Trim(); if (valueType == typeof(bool)) { if (bool.TryParse(text, out var result)) { return result; } if (text == "1" || text.Equals("on", StringComparison.OrdinalIgnoreCase) || text.Equals("yes", StringComparison.OrdinalIgnoreCase)) { return true; } if (text == "0" || text.Equals("off", StringComparison.OrdinalIgnoreCase) || text.Equals("no", StringComparison.OrdinalIgnoreCase)) { return false; } error = "bool expected (true/false/on/off)"; return null; } if (valueType == typeof(int)) { if (int.TryParse(text, NumberStyles.Integer, CultureInfo.InvariantCulture, out var result2)) { return result2; } error = "int expected"; return null; } if (valueType == typeof(float)) { if (float.TryParse(text, NumberStyles.Float, CultureInfo.InvariantCulture, out var result3)) { return result3; } error = "number expected"; return null; } if (valueType == typeof(string)) { if (text.Equals("on", StringComparison.OrdinalIgnoreCase)) { return "On"; } if (text.Equals("off", StringComparison.OrdinalIgnoreCase)) { return "Off"; } if (text.Equals("unchanged", StringComparison.OrdinalIgnoreCase)) { return "Unchanged"; } return text; } error = "unsupported type " + valueType.Name; return null; } } [HarmonyPatch(typeof(Terminal), "InitTerminal")] internal static class RatesTerminalPatch { private static void Postfix() { RatesCommands.Register(); } } internal static class RatesFeedback { [HarmonyPatch(typeof(ZNet), "RPC_RemoteCommand")] private static class RemoteCommandPatch { private static void Prefix(ZRpc rpc) { CurrentRemoteRpc = rpc; } } [HarmonyPatch(typeof(ZNet), "InternalCommand")] private static class InternalCommandPatch { private static void Prefix(ZRpc rpc) { CurrentRemoteRpc = rpc; } private static void Postfix() { CurrentRemoteRpc = null; } private static Exception Finalizer(Exception __exception) { CurrentRemoteRpc = null; return __exception; } } private static bool _guard; internal static ZRpc CurrentRemoteRpc { get; private set; } public static void Say(string msg, bool yellowHud) { if (string.IsNullOrEmpty(msg)) { return; } string[] array = SplitLines(msg); foreach (string text in array) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)text); } } if (_guard) { return; } _guard = true; try { ZRpc currentRemoteRpc = CurrentRemoteRpc; if (currentRemoteRpc != null && currentRemoteRpc.IsConnected() && (Object)(object)ZNet.instance != (Object)null) { array = SplitLines(msg); foreach (string text2 in array) { try { ZNet.instance.RemotePrint(currentRemoteRpc, text2); } catch (Exception ex) { ManualLogSource log2 = Plugin.Log; if (log2 != null) { log2.LogWarning((object)("ServerRates RemotePrint failed: " + ex.Message)); } break; } } } else if ((Object)(object)Console.instance != (Object)null) { array = SplitLines(msg); foreach (string text3 in array) { Console.instance.Print(text3); } } if (yellowHud) { ShowYellowHud(SplitLines(msg)[0]); } BroadcastChat(TrimForChat(msg)); } finally { _guard = false; } } private static string[] SplitLines(string msg) { return msg.Replace("\r\n", "\n").Replace('\r', '\n').Split(new char[1] { '\n' }, StringSplitOptions.RemoveEmptyEntries); } private static string TrimForChat(string msg) { string text = msg.Replace("\r\n", " | ").Replace('\n', '|').Replace('\r', '|'); if (text.Length <= 450) { return text; } return text.Substring(0, 447) + "..."; } public static void ShowYellowHud(string text) { if (string.IsNullOrEmpty(text) || ZRoutedRpc.instance == null) { return; } try { if ((Object)(object)MessageHud.instance != (Object)null) { MessageHud.instance.MessageAll((MessageType)2, text); return; } ZRoutedRpc.instance.InvokeRoutedRPC(0L, "ShowMessage", new object[2] { 2, text }); } catch (Exception ex) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("ServerRates HUD failed: " + ex.Message)); } } } public static void BroadcastChat(string text) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Expected O, but got Unknown //IL_0036: Unknown result type (might be due to invalid IL or missing references) if (string.IsNullOrEmpty(text) || ZRoutedRpc.instance == null) { return; } try { UserInfo val = new UserInfo { Name = "ServerRates" }; ZRoutedRpc.instance.InvokeRoutedRPC(0L, "ChatMessage", new object[4] { Vector3.zero, 1, val, text }); } catch (Exception ex) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("ServerRates chat broadcast failed: " + ex.Message)); } } } }