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 MobStatsUI v5.3.1
MobStatsUI.dll
Decompiled a day agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using Microsoft.CodeAnalysis; using RiskOfOptions; using RiskOfOptions.OptionConfigs; using RiskOfOptions.Options; using RoR2; using UnityEngine; using UnityEngine.Events; using UnityEngine.Networking; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyVersion("0.0.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [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 MobStatsUI { public class RageNetMsg : MessageBase { public NetworkInstanceId id; public float size; public float ms; public float atk; public float hp; public float dmg; public override void Serialize(NetworkWriter w) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) w.Write(id); w.Write(size); w.Write(ms); w.Write(atk); w.Write(hp); w.Write(dmg); } public override void Deserialize(NetworkReader r) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) id = r.ReadNetworkId(); size = r.ReadSingle(); ms = r.ReadSingle(); atk = r.ReadSingle(); hp = r.ReadSingle(); dmg = r.ReadSingle(); } } public class HelloMsg : MessageBase { public override void Serialize(NetworkWriter w) { } public override void Deserialize(NetworkReader r) { } } public class ConfigChunkMsg : MessageBase { public int ver; public int idx; public int total; public string part = ""; public override void Serialize(NetworkWriter w) { w.Write(ver); w.Write(idx); w.Write(total); w.Write(part ?? ""); } public override void Deserialize(NetworkReader r) { ver = r.ReadInt32(); idx = r.ReadInt32(); total = r.ReadInt32(); part = r.ReadString(); } } [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInPlugin("shlyapi.MobStatsUI", "MobStatsUI", "5.3.1")] public class MobStatsUIPlugin : BaseUnityPlugin { private struct Snap { public float baseMaxHealth; public float levelMaxHealth; public float baseRegen; public float levelRegen; public float baseMaxShield; public float levelMaxShield; public float baseMoveSpeed; public float levelMoveSpeed; public float baseAttackSpeed; public float levelAttackSpeed; public float baseDamage; public float levelDamage; public float baseArmor; public float baseCrit; public float baseAcceleration; public float baseJumpPower; public float levelJumpPower; public bool champion; } private class Rage { public float size; public float ms; public float atk; public float hp; public float dmg; public float born; } private class Tracked { private float orig; private float last = float.NaN; public float Get(float current, Func<float, float> f) { if (float.IsNaN(last) || !Mathf.Approximately(current, last)) { orig = current; } last = f(orig); return last; } } private class DirState { public Tracked credit = new Tracked(); public Tracked minS = new Tracked(); public Tracked maxS = new Tracked(); public Tracked minR = new Tracked(); public Tracked maxR = new Tracked(); public Tracked skip = new Tracked(); public Tracked elite = new Tracked(); public Tracked dist = new Tracked(); } private class StageRule { public ConfigEntry<float> first; public ConfigEntry<float> every; public ConfigEntry<float> max; public ConfigEntry<float> mult; } private class RunStats { public int kills; public int ragesSpawned; public int ragesKilled; public int expired; public int items; public float gold; public float xp; } [CompilerGenerated] private static class <>O { public static Action <0>__RestoreLocal; public static Action <1>__OnGameLoaded; public static Action<CharacterBody> <2>__OnBodyStart; public static Action<DamageReport> <3>__OnDeath; public static NetworkMessageDelegate <4>__OnHello; public static NetworkMessageDelegate <5>__OnRageMsg; public static NetworkMessageDelegate <6>__OnCfgMsg; } [Serializable] [CompilerGenerated] private sealed class <>c { public static readonly <>c <>9 = new <>c(); public static EventHandler <>9__118_0; public static EventHandler <>9__119_0; public static Action<Run> <>9__120_0; public static Action<Run, RunReport> <>9__120_1; public static UnityAction <>9__120_2; public static EventHandler<SettingChangedEventArgs> <>9__120_3; public static Predicate<CharacterBody> <>9__148_0; public static Func<CharacterBody, bool> <>9__152_1; public static Func<CharacterBody, bool> <>9__152_2; public static Func<CharacterBody, bool> <>9__152_0; public static Func<ConfigEntryBase, bool> <>9__156_0; public static Func<ConfigEntryBase, string> <>9__156_1; public static Func<ConfigEntryBase, bool> <>9__159_0; public static Func<CharacterBody, bool> <>9__163_0; internal void <Num>b__118_0(object s, EventArgs a) { Changed(); } internal void <Toggle>b__119_0(object s, EventArgs a) { Changed(); } internal void <Awake>b__120_0(Run run) { stats = new RunStats(); } internal void <Awake>b__120_1(Run run, RunReport report) { PrintStats(); } internal void <Awake>b__120_2() { ResetAll(); ApplyAll(); } internal void <Awake>b__120_3(object sender, SettingChangedEventArgs args) { if (!suppress) { cfgDirty = true; cfgDirtyAt = Time.unscaledTime; } } internal bool <CheckElites>b__148_0(CharacterBody b) { return !Object.op_Implicit((Object)(object)b); } internal bool <TryRage>b__152_1(CharacterBody k) { if (Object.op_Implicit((Object)(object)k) && Object.op_Implicit((Object)(object)k.healthComponent)) { return !k.healthComponent.alive; } return true; } internal bool <TryRage>b__152_2(CharacterBody k) { return !Object.op_Implicit((Object)(object)k); } internal bool <TryRage>b__152_0(CharacterBody b) { //IL_003d: Unknown result type (might be due to invalid IL or missing references) if (Object.op_Implicit((Object)(object)b) && IsEnemy(b) && Object.op_Implicit((Object)(object)b.healthComponent) && b.healthComponent.alive && !rages.ContainsKey(b) && snaps.ContainsKey(b.bodyIndex) && !b.isChampion) { if (rageElite.Value) { return b.isElite; } return true; } return false; } internal bool <SerializeSynced>b__156_0(ConfigEntryBase e) { return !localOnly.Contains(e); } internal string <SerializeSynced>b__156_1(ConfigEntryBase e) { return Uri.EscapeDataString(e.Definition.Section + "/" + e.Definition.Key) + "=" + Uri.EscapeDataString(e.GetSerializedValue()); } internal bool <ApplySynced>b__159_0(ConfigEntryBase e) { return !localOnly.Contains(e); } internal bool <CleanupRages>b__163_0(CharacterBody k) { if (Object.op_Implicit((Object)(object)k) && Object.op_Implicit((Object)(object)k.healthComponent)) { return !k.healthComponent.alive; } return true; } } public const string Guid = "shlyapi.MobStatsUI"; public const string Name = "MobStatsUI"; public const string Version = "5.3.1"; private static MobStatsUIPlugin I; private static readonly Dictionary<BodyIndex, Snap> snaps = new Dictionary<BodyIndex, Snap>(); private static readonly HashSet<BodyIndex> survivors = new HashSet<BodyIndex>(); private static readonly Dictionary<int, DirState> dirStates = new Dictionary<int, DirState>(); private static readonly Dictionary<CharacterBody, Rage> rages = new Dictionary<CharacterBody, Rage>(); private static readonly Dictionary<CharacterBody, Vector3> origScale = new Dictionary<CharacterBody, Vector3>(); private static readonly HashSet<CharacterBody> expired = new HashSet<CharacterBody>(); private static readonly HashSet<CharacterBody> eliteDone = new HashSet<CharacterBody>(); private static readonly List<ConfigEntryBase> all = new List<ConfigEntryBase>(); private static RunStats stats = new RunStats(); private static bool ready; private static bool suppress; private static bool modEnabled = true; private static int origMonsterCap = -1; private static int lastStage = -1; private static float timeFactor = 1f; private float dirTimer; private float rageTimer; private float logTimer; private static ConfigEntry<float> health; private static ConfigEntry<float> regen; private static ConfigEntry<float> shield; private static ConfigEntry<float> moveSpeed; private static ConfigEntry<float> attackSpeed; private static ConfigEntry<float> damage; private static ConfigEntry<float> accel; private static ConfigEntry<float> jump; private static ConfigEntry<float> armorAdd; private static ConfigEntry<float> critAdd; private static ConfigEntry<float> sizeMult; private static ConfigEntry<float> timeScale; private static ConfigEntry<bool> affectSurvivors; private static ConfigEntry<float> bossHealth; private static ConfigEntry<float> bossDamage; private static ConfigEntry<float> bossSpeed; private static ConfigEntry<float> bossAttack; private static ConfigEntry<float> bossGold; private static ConfigEntry<float> bossXp; private static ConfigEntry<float> bossDrops; private static ConfigEntry<float> bossWeight; private static ConfigEntry<float> eliteHealth; private static ConfigEntry<float> eliteDamage; private static ConfigEntry<float> creditMult; private static ConfigEntry<float> spawnSpeed; private static ConfigEntry<float> perSeries; private static ConfigEntry<float> capMult; private static ConfigEntry<float> eliteMult; private static ConfigEntry<float> distMult; private static ConfigEntry<float> goldMult; private static ConfigEntry<float> xpMult; private static ConfigEntry<float> goldCap; private static ConfigEntry<float> xpCap; private static ConfigEntry<float> dropChance; private static ConfigEntry<float> dropW1; private static ConfigEntry<float> dropW2; private static ConfigEntry<float> dropW3; private static ConfigEntry<bool> rageOn; private static ConfigEntry<bool> rageAnnounce; private static ConfigEntry<bool> rageElite; private static ConfigEntry<float> rageInterval; private static ConfigEntry<float> rageChance; private static ConfigEntry<float> rageMax; private static ConfigEntry<float> rageLifetime; private static ConfigEntry<float> rageHp; private static ConfigEntry<float> rageDmg; private static ConfigEntry<float> rageSMin; private static ConfigEntry<float> rageSMax; private static ConfigEntry<float> rageMMin; private static ConfigEntry<float> rageMMax; private static ConfigEntry<float> rageAMin; private static ConfigEntry<float> rageAMax; private static ConfigEntry<float> rageGold; private static ConfigEntry<float> rageXp; private static ConfigEntry<float> rageDropChance; private static ConfigEntry<float> rageDropCount; private static ConfigEntry<float> rageW1; private static ConfigEntry<float> rageW2; private static ConfigEntry<float> rageW3; private static ConfigEntry<float> shFirst; private static ConfigEntry<float> shEvery; private static ConfigEntry<float> shMax; private static StageRule stHp; private static StageRule stDmg; private static StageRule stMs; private static StageRule stAtk; private static StageRule stCredit; private static ConfigEntry<KeyboardShortcut> toggleKey; private static ConfigEntry<bool> statsOn; private static ConfigEntry<bool> debugLog; private static ConfigEntry<float> checkInterval; private const short MsgRage = 29101; private const short MsgCfg = 29102; private const short MsgHello = 29103; private static NetworkClient registeredClient; private static bool serverHandlers; private static bool helloPending; private static bool syncedActive; private static bool cfgDirty; private static float helloAt; private static float cfgDirtyAt; private static int helloSent; private static int syncVersion; private static int cfgVer = -1; private static int cfgGot; private static string[] cfgParts; private static readonly Dictionary<ConfigEntryBase, string> localBackup = new Dictionary<ConfigEntryBase, string>(); private static readonly HashSet<ConfigEntryBase> localOnly = new HashSet<ConfigEntryBase>(); private static readonly Dictionary<DirectorCard, Tracked> bossWeights = new Dictionary<DirectorCard, Tracked>(); private static string Clean(string k) { char[] array = new char[8] { '=', '\n', '\t', '\\', '"', '\'', '[', ']' }; foreach (char c in array) { k = k.Replace(c.ToString(), ""); } return k; } private static void Changed() { if (!suppress) { ApplyAll(); } } private ConfigEntry<float> Num(string section, string key, float def, string desc, float min, float max = 100000f, bool apply = true) { //IL_0017: 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_0024: Expected O, but got Unknown //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Expected O, but got Unknown //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Expected O, but got Unknown //IL_003c: Expected O, but got Unknown //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Expected O, but got Unknown ConfigEntry<float> val = ((BaseUnityPlugin)this).Config.Bind<float>(section, Clean(key), def, desc); FloatFieldConfig val2 = new FloatFieldConfig(); ((NumericFieldConfig<float>)val2).Min = min; ((NumericFieldConfig<float>)val2).Max = max; ((NumericFieldConfig<float>)val2).FormatString = "{0:0.##}"; ModSettingsManager.AddOption((BaseOption)new FloatFieldOption(val, val2)); if (apply) { val.SettingChanged += delegate { Changed(); }; } all.Add((ConfigEntryBase)(object)val); return val; } private ConfigEntry<bool> Toggle(string section, string key, bool def, string desc, bool apply = false) { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Expected O, but got Unknown ConfigEntry<bool> val = ((BaseUnityPlugin)this).Config.Bind<bool>(section, Clean(key), def, desc); ModSettingsManager.AddOption((BaseOption)new CheckBoxOption(val)); if (apply) { val.SettingChanged += delegate { Changed(); }; } all.Add((ConfigEntryBase)(object)val); return val; } private void Awake() { //IL_0ad0: Unknown result type (might be due to invalid IL or missing references) //IL_0ae9: Unknown result type (might be due to invalid IL or missing references) //IL_0af3: Expected O, but got Unknown //IL_0c03: Unknown result type (might be due to invalid IL or missing references) //IL_0c0d: Expected O, but got Unknown //IL_0bf8: Unknown result type (might be due to invalid IL or missing references) //IL_0bfd: Unknown result type (might be due to invalid IL or missing references) //IL_0c03: Expected O, but got Unknown I = this; health = Num("Mobs", "Max Health x", 1f, "Multiplier of base+per-level max health of all mobs", 0f); regen = Num("Mobs", "Regen x", 1f, "Multiplier of health regen", 0f); shield = Num("Mobs", "Max Shield x", 1f, "Multiplier of max shield", 0f); moveSpeed = Num("Mobs", "Move Speed x", 1f, "Multiplier of movement speed", 0f); attackSpeed = Num("Mobs", "Attack Speed x", 1f, "Multiplier of attack speed", 0f); damage = Num("Mobs", "Damage x", 1f, "Multiplier of damage (this is also how hard mobs hit players)", 0f); accel = Num("Mobs", "Acceleration x", 1f, "Multiplier of acceleration", 0f); jump = Num("Mobs", "Jump Power x", 1f, "Multiplier of jump power", 0f); armorAdd = Num("Mobs", "Armor +", 0f, "Flat armor added to all mobs", -1000f); critAdd = Num("Mobs", "Crit Chance +", 0f, "Flat crit chance (%) added to all mobs", 0f); sizeMult = Num("Mobs", "Size x", 1f, "Model size multiplier of all mobs (visual, host-side)", 0.1f, 50f); timeScale = Num("Mobs", "Growth per minute (%)", 0f, "Mobs get this % more health and damage for every minute of the run, on top of normal difficulty", 0f); affectSurvivors = Toggle("Mobs", "Also affect survivors", def: false, "If off, only non-survivor bodies are changed", apply: true); bossHealth = Num("Bosses", "Boss Health x", 1f, "Extra multiplier for champions/bosses (stacks with Mobs)", 0f); bossDamage = Num("Bosses", "Boss Damage x", 1f, "Extra multiplier for bosses", 0f); bossSpeed = Num("Bosses", "Boss Move Speed x", 1f, "Extra multiplier for bosses", 0f); bossAttack = Num("Bosses", "Boss Attack Speed x", 1f, "Extra multiplier for bosses", 0f); eliteHealth = Num("Elites", "Elite Health x", 1f, "Extra health multiplier for elite mobs (stacks with Mobs)", 0f); eliteDamage = Num("Elites", "Elite Damage x", 1f, "Extra damage multiplier for elite mobs (stacks with Mobs)", 0f); eliteMult = Num("Elites", "Elite chance x", 1f, "Higher = more elites (director elite bias is divided by this)", 0.01f); creditMult = Num("Spawning", "Spawn credits x", 1f, "Director gets credits faster: more / stronger mobs", 0f); spawnSpeed = Num("Spawning", "Spawn speed x", 1f, "Pauses between spawn waves are divided by this", 0.01f); perSeries = Num("Spawning", "Mobs per wave x", 1f, "Max mobs spawned in a row before the director pauses", 0.1f); capMult = Num("Spawning", "Mob cap x", 1f, "Limit of simultaneously alive monsters (default ~40)", 0.1f); distMult = Num("Spawning", "Spawn distance x", 1f, "Lower = mobs spawn closer to players, higher = farther", 0.1f, 100f); goldMult = Num("Rewards and drops", "Gold from mobs x", 1f, "Extra gold for kills. Values below 1 do nothing", 1f, 100000f, apply: false); xpMult = Num("Rewards and drops", "XP from mobs x", 1f, "Extra experience for kills. Values below 1 do nothing", 1f, 100000f, apply: false); goldCap = Num("Rewards and drops", "Max extra gold per kill (0 for no limit)", 0f, "Safety cap for the bonus gold of one kill", 0f, 100000000f, apply: false); xpCap = Num("Rewards and drops", "Max extra XP per kill (0 for no limit)", 0f, "Safety cap for the bonus experience of one kill", 0f, 100000000f, apply: false); dropChance = Num("Rewards and drops", "Item drop chance per kill (%)", 0f, "Every mob kill can drop an item", 0f, 100f, apply: false); dropW1 = Num("Rewards and drops", "Drop weight: white", 80f, "Relative chance of white items", 0f, 100000f, apply: false); dropW2 = Num("Rewards and drops", "Drop weight: green", 18f, "Relative chance of green items", 0f, 100000f, apply: false); dropW3 = Num("Rewards and drops", "Drop weight: red", 2f, "Relative chance of red items", 0f, 100000f, apply: false); bossWeight = Num("Bosses", "Boss spawn weight x", 1f, "How often the director picks bosses (champions) next to normal mobs on this stage. 2 means about twice as often. 1 means unchanged", 0f); bossGold = Num("Bosses", "Boss gold x", 1f, "Extra gold multiplier for killing bosses (champions)", 1f, 100000f, apply: false); bossXp = Num("Bosses", "Boss XP x", 1f, "Extra experience multiplier for killing bosses", 1f, 100000f, apply: false); bossDrops = Num("Bosses", "Boss extra drops", 0f, "Additional items dropped by a boss (uses the rage drop weights)", 0f, 100f, apply: false); rageOn = Toggle("Rage mob", "Enable rage mob", def: false, "Every interval a random mob becomes a rage mob"); rageAnnounce = Toggle("Rage mob", "Announce in chat", def: true, "Chat message when a rage mob appears"); rageElite = Toggle("Rage mob", "Only elites", def: true, "Only an elite mob can become the rage mob"); rageInterval = Num("Rage mob", "Interval (seconds)", 120f, "How often a rage mob is attempted", 1f, 100000f, apply: false); rageChance = Num("Rage mob", "Chance per attempt (%)", 100f, "Chance that an attempt succeeds", 0f, 100f, apply: false); rageMax = Num("Rage mob", "Max alive at once", 1f, "Limit of rage mobs on the map", 1f, 1000f, apply: false); rageLifetime = Num("Rage mob", "Lifetime (seconds, 0 for unlimited)", 90f, "The rage mob disappears without rewards after this many seconds", 0f, 100000f, apply: false); rageHp = Num("Rage mob", "Health x", 3f, "Health multiplier", 0f, 100000f, apply: false); rageDmg = Num("Rage mob", "Damage x", 1.5f, "Damage multiplier", 0f, 100000f, apply: false); rageSMin = Num("Rage mob", "Size min", 1.5f, "Random size range (min)", 0.1f, 50f, apply: false); rageSMax = Num("Rage mob", "Size max", 3f, "Random size range (max)", 0.1f, 50f, apply: false); rageMMin = Num("Rage mob", "Move speed min", 1.2f, "Random move speed multiplier (min)", 0f, 100f, apply: false); rageMMax = Num("Rage mob", "Move speed max", 2.5f, "Random move speed multiplier (max)", 0f, 100f, apply: false); rageAMin = Num("Rage mob", "Attack speed min", 1.2f, "Random attack speed multiplier (min)", 0f, 100f, apply: false); rageAMax = Num("Rage mob", "Attack speed max", 2.5f, "Random attack speed multiplier (max)", 0f, 100f, apply: false); rageGold = Num("Rage mob", "Gold x", 3f, "Extra gold multiplier for the rage mob, on top of normal", 1f, 100000f, apply: false); rageXp = Num("Rage mob", "XP x", 3f, "Extra experience multiplier for the rage mob, on top of normal", 1f, 100000f, apply: false); rageDropChance = Num("Rage mob", "Drop chance (%)", 100f, "Chance that rage mob drops items", 0f, 100f, apply: false); rageDropCount = Num("Rage mob", "Drop count", 1f, "How many items drop", 1f, 100f, apply: false); rageW1 = Num("Rage mob", "Drop weight: white", 40f, "Relative chance of white items", 0f, 100000f, apply: false); rageW2 = Num("Rage mob", "Drop weight: green", 45f, "Relative chance of green items", 0f, 100000f, apply: false); rageW3 = Num("Rage mob", "Drop weight: red", 15f, "Relative chance of red items", 0f, 100000f, apply: false); shFirst = Num("Stages", "First upgrade at stage", 5f, "The first upgrade happens when this stage starts. Stages before it are not changed", 1f, 1000f); shEvery = Num("Stages", "Upgrade every (stages)", 5f, "After the first upgrade, mobs are upgraded again every this many stages", 1f, 1000f); shMax = Num("Stages", "Max upgrades (0 for unlimited)", 0f, "Stop upgrading after this many upgrades", 0f, 1000f); stHp = MakeRule("Stages", "Health", 1.5f, "Health", apply: true); stDmg = MakeRule("Stages", "Damage", 1f, "Damage", apply: true); stMs = MakeRule("Stages", "Move speed", 1f, "Move speed", apply: true); stAtk = MakeRule("Stages", "Attack speed", 1f, "Attack speed", apply: true); stCredit = MakeRule("Stages", "Spawn credits", 1f, "Spawn credits (more credits means more mobs)", apply: false); statsOn = Toggle("General", "Run summary in chat", def: true, "Prints statistics when the run ends"); toggleKey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("General", "Toggle key", new KeyboardShortcut((KeyCode)289, Array.Empty<KeyCode>()), "Enable or disable the whole mod"); ModSettingsManager.AddOption((BaseOption)new KeyBindOption(toggleKey)); all.Add((ConfigEntryBase)(object)toggleKey); Run.onRunStartGlobal += delegate { stats = new RunStats(); }; Run.onClientGameOverGlobal += delegate { PrintStats(); }; checkInterval = Num("General", "Check interval (seconds)", 1f, "How often director settings and time growth are re-applied", 0.1f, 60f, apply: false); debugLog = Toggle("General", "Debug log", def: false, "Writes director info to the BepInEx console every 5 seconds"); localOnly.Add((ConfigEntryBase)(object)toggleKey); localOnly.Add((ConfigEntryBase)(object)debugLog); localOnly.Add((ConfigEntryBase)(object)statsOn); localOnly.Add((ConfigEntryBase)(object)checkInterval); object obj = <>c.<>9__120_2; if (obj == null) { UnityAction val = delegate { ResetAll(); ApplyAll(); }; <>c.<>9__120_2 = val; obj = (object)val; } ModSettingsManager.AddOption((BaseOption)new GenericButtonOption("Reset to vanilla", "General", "Set every setting of this mod back to the default (vanilla) value", "Reset", (UnityAction)obj)); LoadIcon(); ModSettingsManager.SetModDescription("Global multipliers for mob stats, spawning, drops, stage scaling and a rage mob (live)."); ((BaseUnityPlugin)this).Config.SettingChanged += delegate { if (!suppress) { cfgDirty = true; cfgDirtyAt = Time.unscaledTime; } }; Application.quitting += RestoreLocal; RoR2Application.onLoad = (Action)Delegate.Combine(RoR2Application.onLoad, new Action(OnGameLoaded)); } private StageRule MakeRule(string sec, string n, float mult, string what, bool apply) { return new StageRule { mult = Num(sec, n + ": x per upgrade", mult, what + " is multiplied by this at every upgrade (1.5 means +50% each time, and it stacks, 1 means no change)", 0f, 100000f, apply), first = shFirst, every = shEvery, max = shMax }; } private void LoadIcon() { //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Expected O, but got Unknown //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Unknown result type (might be due to invalid IL or missing references) try { string directoryName = Path.GetDirectoryName(((BaseUnityPlugin)this).Info.Location); string path = Path.Combine(directoryName, "icon.png"); if (!File.Exists(path)) { path = Path.Combine(Directory.GetParent(directoryName).FullName, "icon.png"); } if (!File.Exists(path)) { LogWarn("icon.png was not found next to the dll, the menu will show no picture"); return; } Texture2D val = new Texture2D(2, 2); if (ImageConversion.LoadImage(val, File.ReadAllBytes(path))) { ModSettingsManager.SetModIcon(Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0.5f))); } } catch (Exception ex) { LogWarn("Icon failed: " + ex.Message); } } private static void Say(string m) { if ((Object)(object)I != (Object)null) { ((BaseUnityPlugin)I).Logger.LogInfo((object)("[MobStatsUI] " + m)); } try { Chat.AddMessage("<color=#80ff80>[MobStatsUI] " + m + "</color>"); } catch { } } private static void LogWarn(string m) { if ((Object)(object)I != (Object)null) { ((BaseUnityPlugin)I).Logger.LogWarning((object)("[MobStatsUI] " + m)); } } private static void Broadcast(string msg) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Expected O, but got Unknown try { if (NetworkServer.active) { Chat.SendBroadcastChat((ChatMessageBase)new SimpleChatMessage { baseToken = msg }); } else { Chat.AddMessage(msg); } } catch { } } private static void ResetAll() { suppress = true; foreach (ConfigEntryBase item in all) { item.BoxedValue = item.DefaultValue; } suppress = false; } private static void OnGameLoaded() { //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) foreach (SurvivorDef allSurvivorDef in SurvivorCatalog.allSurvivorDefs) { if (!((Object)(object)allSurvivorDef == (Object)null) && !((Object)(object)allSurvivorDef.bodyPrefab == (Object)null)) { CharacterBody component = allSurvivorDef.bodyPrefab.GetComponent<CharacterBody>(); if (Object.op_Implicit((Object)(object)component)) { survivors.Add(component.bodyIndex); } } } for (int i = 0; i < BodyCatalog.bodyCount; i++) { BodyIndex val = (BodyIndex)i; CharacterBody bodyPrefabBodyComponent = BodyCatalog.GetBodyPrefabBodyComponent(val); if (Object.op_Implicit((Object)(object)bodyPrefabBodyComponent)) { snaps[val] = new Snap { baseMaxHealth = bodyPrefabBodyComponent.baseMaxHealth, levelMaxHealth = bodyPrefabBodyComponent.levelMaxHealth, baseRegen = bodyPrefabBodyComponent.baseRegen, levelRegen = bodyPrefabBodyComponent.levelRegen, baseMaxShield = bodyPrefabBodyComponent.baseMaxShield, levelMaxShield = bodyPrefabBodyComponent.levelMaxShield, baseMoveSpeed = bodyPrefabBodyComponent.baseMoveSpeed, levelMoveSpeed = bodyPrefabBodyComponent.levelMoveSpeed, baseAttackSpeed = bodyPrefabBodyComponent.baseAttackSpeed, levelAttackSpeed = bodyPrefabBodyComponent.levelAttackSpeed, baseDamage = bodyPrefabBodyComponent.baseDamage, levelDamage = bodyPrefabBodyComponent.levelDamage, baseArmor = bodyPrefabBodyComponent.baseArmor, baseCrit = bodyPrefabBodyComponent.baseCrit, baseAcceleration = bodyPrefabBodyComponent.baseAcceleration, baseJumpPower = bodyPrefabBodyComponent.baseJumpPower, levelJumpPower = bodyPrefabBodyComponent.levelJumpPower, champion = bodyPrefabBodyComponent.isChampion }; } } TeamDef teamDef = TeamCatalog.GetTeamDef((TeamIndex)2); if (teamDef != null) { origMonsterCap = teamDef.softCharacterLimit; } CharacterBody.onBodyStartGlobal += OnBodyStart; GlobalEventManager.onCharacterDeathGlobal += OnDeath; ready = true; ApplyAll(); } private static bool IsEnemy(CharacterBody b) { //IL_001d: 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_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Invalid comparison between Unknown and I4 //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Invalid comparison between Unknown and I4 if (!Object.op_Implicit((Object)(object)b) || !Object.op_Implicit((Object)(object)b.teamComponent)) { return false; } TeamIndex teamIndex = b.teamComponent.teamIndex; if ((int)teamIndex != 1) { return (int)teamIndex != -1; } return false; } private static void Set(CharacterBody b, Snap s, bool neutral, Rage rg) { if (!modEnabled) { neutral = true; rg = null; } float num = 1f; float num2 = 1f; float num3 = 1f; float num4 = 1f; float num5 = 1f; float num6 = 1f; float num7 = 1f; float num8 = 1f; float num9 = 0f; float num10 = 0f; if (!neutral) { num = health.Value * timeFactor; num2 = regen.Value; num3 = shield.Value; num4 = moveSpeed.Value; num5 = attackSpeed.Value; num6 = damage.Value * timeFactor; num7 = accel.Value; num8 = jump.Value; num9 = armorAdd.Value; num10 = critAdd.Value; if (s.champion) { num *= bossHealth.Value; num6 *= bossDamage.Value; num4 *= bossSpeed.Value; num5 *= bossAttack.Value; } if (b.isElite) { num *= eliteHealth.Value; num6 *= eliteDamage.Value; } num *= StageHp(); num6 *= StageDmg(); num4 *= StageMul(stMs); num5 *= StageMul(stAtk); } if (rg != null) { num *= rg.hp; num6 *= rg.dmg; num4 *= rg.ms; num5 *= rg.atk; } b.baseMaxHealth = s.baseMaxHealth * num; b.levelMaxHealth = s.levelMaxHealth * num; b.baseRegen = s.baseRegen * num2; b.levelRegen = s.levelRegen * num2; b.baseMaxShield = s.baseMaxShield * num3; b.levelMaxShield = s.levelMaxShield * num3; b.baseMoveSpeed = s.baseMoveSpeed * num4; b.levelMoveSpeed = s.levelMoveSpeed * num4; b.baseAttackSpeed = s.baseAttackSpeed * num5; b.levelAttackSpeed = s.levelAttackSpeed * num5; b.baseDamage = s.baseDamage * num6; b.levelDamage = s.levelDamage * num6; b.baseAcceleration = s.baseAcceleration * num7; b.baseJumpPower = s.baseJumpPower * num8; b.levelJumpPower = s.levelJumpPower * num8; b.baseArmor = s.baseArmor + num9; b.baseCrit = s.baseCrit + num10; } private static void ApplyScale(CharacterBody b, bool skip) { //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) Transform val = (Object.op_Implicit((Object)(object)b.modelLocator) ? b.modelLocator.modelTransform : null); if (Object.op_Implicit((Object)(object)val)) { if (!origScale.TryGetValue(b, out var value)) { value = val.localScale; origScale[b] = value; } float num = ((skip || !modEnabled) ? 1f : sizeMult.Value); if (modEnabled && rages.TryGetValue(b, out var value2)) { num *= value2.size; } val.localScale = value * num; } } private static void ApplyBody(CharacterBody body) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) if (Object.op_Implicit((Object)(object)body) && snaps.TryGetValue(body.bodyIndex, out var value)) { bool neutral = survivors.Contains(body.bodyIndex) && !affectSurvivors.Value; rages.TryGetValue(body, out var value2); Set(body, value, neutral, value2); if (IsEnemy(body)) { ApplyScale(body, skip: false); } body.RecalculateStats(); } } private static void ApplyAll() { //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) if (!ready) { return; } foreach (KeyValuePair<BodyIndex, Snap> snap in snaps) { CharacterBody bodyPrefabBodyComponent = BodyCatalog.GetBodyPrefabBodyComponent(snap.Key); if (Object.op_Implicit((Object)(object)bodyPrefabBodyComponent)) { bool neutral = survivors.Contains(snap.Key) && !affectSurvivors.Value; Set(bodyPrefabBodyComponent, snap.Value, neutral, null); } } CharacterBody[] array = Object.FindObjectsOfType<CharacterBody>(); for (int i = 0; i < array.Length; i++) { ApplyBody(array[i]); } TeamDef teamDef = TeamCatalog.GetTeamDef((TeamIndex)2); if (teamDef != null && origMonsterCap > 0) { teamDef.softCharacterLimit = Mathf.Max(1, Mathf.RoundToInt((float)origMonsterCap * (modEnabled ? capMult.Value : 1f))); } ApplyDirectors(); } private static bool IsBossCard(DirectorCard dc) { if (dc == null || !Object.op_Implicit((Object)(object)dc.spawnCard) || !Object.op_Implicit((Object)(object)dc.spawnCard.prefab)) { return false; } CharacterMaster component = dc.spawnCard.prefab.GetComponent<CharacterMaster>(); CharacterBody val = ((Object.op_Implicit((Object)(object)component) && Object.op_Implicit((Object)(object)component.bodyPrefab)) ? component.bodyPrefab.GetComponent<CharacterBody>() : null); if (Object.op_Implicit((Object)(object)val)) { return val.isChampion; } return false; } private static void ApplyBossWeight() { //IL_0054: 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_005b: Unknown result type (might be due to invalid IL or missing references) //IL_006e: 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) //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: Unknown result type (might be due to invalid IL or missing references) ClassicStageInfo instance = ClassicStageInfo.instance; WeightedSelection<DirectorCard> val = (((Object)(object)instance != (Object)null) ? instance.monsterSelection : null); if (val == null) { return; } float mult = (modEnabled ? Mathf.Max(0f, bossWeight.Value) : 1f); for (int i = 0; i < val.Count; i++) { ChoiceInfo<DirectorCard> choice = val.GetChoice(i); if (IsBossCard(choice.value)) { if (!bossWeights.TryGetValue(choice.value, out var value)) { value = (bossWeights[choice.value] = new Tracked()); } float num = value.Get(choice.weight, (float o) => o * mult); if (!Mathf.Approximately(num, choice.weight)) { val.ModifyChoiceWeight(i, num); } } } } private static void ApplyDirectors() { try { ApplyBossWeight(); } catch (Exception ex) { LogWarn("Boss weight failed: " + ex.Message); } bool flag = modEnabled; float cm = (flag ? (creditMult.Value * StageCredit()) : 1f); float sp = (flag ? Mathf.Max(spawnSpeed.Value, 0.01f) : 1f); float dist = (flag ? Mathf.Max(distMult.Value, 0.05f) : 1f); float ps = (flag ? perSeries.Value : 1f); float el = (flag ? Mathf.Max(eliteMult.Value, 0.01f) : 1f); CombatDirector[] array = Object.FindObjectsOfType<CombatDirector>(); foreach (CombatDirector val in array) { if (Object.op_Implicit((Object)(object)val)) { int instanceID = ((Object)val).GetInstanceID(); if (!dirStates.TryGetValue(instanceID, out var value)) { value = (dirStates[instanceID] = new DirState()); } val.creditMultiplier = value.credit.Get(val.creditMultiplier, (float o) => o * cm); val.minSeriesSpawnInterval = value.minS.Get(val.minSeriesSpawnInterval, (float o) => o / sp); val.maxSeriesSpawnInterval = value.maxS.Get(val.maxSeriesSpawnInterval, (float o) => o / sp); val.minRerollSpawnInterval = value.minR.Get(val.minRerollSpawnInterval, (float o) => o / sp); val.maxRerollSpawnInterval = value.maxR.Get(val.maxRerollSpawnInterval, (float o) => o / sp); val.maximumNumberToSpawnBeforeSkipping = Mathf.Max(1, Mathf.RoundToInt(value.skip.Get(val.maximumNumberToSpawnBeforeSkipping, (float o) => o * ps))); val.eliteBias = value.elite.Get(val.eliteBias, (float o) => o / el); val.spawnDistanceMultiplier = value.dist.Get(val.spawnDistanceMultiplier, (float o) => o * dist); } } } private static void OnBodyStart(CharacterBody body) { if (ready && Object.op_Implicit((Object)(object)body) && !((Object)(object)I == (Object)null)) { ((MonoBehaviour)I).StartCoroutine(Delayed(body)); } } private static IEnumerator Delayed(CharacterBody body) { yield return (object)new WaitForSeconds(0.25f); if (Object.op_Implicit((Object)(object)body) && IsEnemy(body)) { ApplyBody(body); } } private static void OnDeath(DamageReport r) { //IL_02f9: Unknown result type (might be due to invalid IL or missing references) //IL_0281: Unknown result type (might be due to invalid IL or missing references) //IL_032a: Unknown result type (might be due to invalid IL or missing references) //IL_0220: Unknown result type (might be due to invalid IL or missing references) if (!NetworkServer.active || !ready || !modEnabled || r == null) { return; } CharacterBody victimBody = r.victimBody; if (!Object.op_Implicit((Object)(object)victimBody) || !IsEnemy(victimBody)) { return; } if (expired.Remove(victimBody)) { rages.Remove(victimBody); stats.expired++; return; } stats.kills++; rages.TryGetValue(victimBody, out var value); bool flag = value != null; bool isChampion = victimBody.isChampion; float num = goldMult.Value * (flag ? rageGold.Value : 1f) * (isChampion ? bossGold.Value : 1f); float num2 = xpMult.Value * (flag ? rageXp.Value : 1f) * (isChampion ? bossXp.Value : 1f); if (num > 1.001f || num2 > 1.001f) { DeathRewards component = ((Component)victimBody).GetComponent<DeathRewards>(); if (Object.op_Implicit((Object)(object)component)) { float num3 = ((num > 1f) ? ((float)component.goldReward * (num - 1f)) : 0f); float num4 = ((num2 > 1f) ? ((float)component.expReward * (num2 - 1f)) : 0f); if (goldCap.Value > 0f) { num3 = Mathf.Min(num3, goldCap.Value); } if (xpCap.Value > 0f) { num4 = Mathf.Min(num4, xpCap.Value); } if (num3 >= 1f && Object.op_Implicit((Object)(object)r.attackerMaster)) { r.attackerMaster.GiveMoney((uint)num3); stats.gold += num3; } if (num4 >= 1f) { stats.xp += num4; if (Object.op_Implicit((Object)(object)r.attackerBody) && Object.op_Implicit((Object)(object)ExperienceManager.instance)) { ExperienceManager.instance.AwardExperience(victimBody.corePosition, r.attackerBody, (ulong)num4); } else if (Object.op_Implicit((Object)(object)TeamManager.instance)) { TeamManager.instance.GiveTeamExperience((TeamIndex)1, (ulong)num4); } } } } if (flag) { stats.ragesKilled++; if (Random.value * 100f < rageDropChance.Value) { for (int i = 0; i < Mathf.RoundToInt(rageDropCount.Value); i++) { DropOne(victimBody.corePosition, rageW1.Value, rageW2.Value, rageW3.Value); } } rages.Remove(victimBody); } else if (dropChance.Value > 0f && Random.value * 100f < dropChance.Value) { DropOne(victimBody.corePosition, dropW1.Value, dropW2.Value, dropW3.Value); } if (isChampion) { for (int j = 0; j < Mathf.RoundToInt(bossDrops.Value); j++) { DropOne(victimBody.corePosition, rageW1.Value, rageW2.Value, rageW3.Value); } } } private static void DropOne(Vector3 pos, float w1, float w2, float w3) { //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0065: 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_0097: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Unknown result type (might be due to invalid IL or missing references) Run instance = Run.instance; if (!Object.op_Implicit((Object)(object)instance)) { return; } float num = w1 + w2 + w3; if (!(num <= 0f)) { float num2 = Random.value * num; List<PickupIndex> list = ((num2 < w1) ? instance.availableTier1DropList : ((num2 < w1 + w2) ? instance.availableTier2DropList : instance.availableTier3DropList)); if (list != null && list.Count != 0) { PickupIndex val = list[Random.Range(0, list.Count)]; Vector3 val2 = Vector3.up * 20f + new Vector3(Random.Range(-5f, 5f), 0f, Random.Range(-5f, 5f)); PickupDropletController.CreatePickupDroplet(val, pos + Vector3.up * 1.5f, val2); stats.items++; } } } private void Update() { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) if (!ready) { return; } CheckNet(); KeyboardShortcut value = toggleKey.Value; if (((KeyboardShortcut)(ref value)).IsDown()) { modEnabled = !modEnabled; ApplyAll(); Say(modEnabled ? "Mod ENABLED" : "Mod DISABLED"); } if ((Object)(object)Run.instance == (Object)null) { timeFactor = 1f; lastStage = -1; return; } dirTimer += Time.unscaledDeltaTime; if (dirTimer >= Mathf.Max(0.1f, checkInterval.Value)) { dirTimer = 0f; ApplyDirectors(); if (debugLog.Value && (logTimer += Mathf.Max(0.1f, checkInterval.Value)) >= 5f) { logTimer = 0f; LogDebug(); } float num = 1f + timeScale.Value / 100f * (Run.instance.GetRunStopwatch() / 60f); num = Mathf.Round(num * 20f) / 20f; if (!Mathf.Approximately(num, timeFactor)) { timeFactor = num; ApplyAll(); } int num2 = StageNumber(); if (num2 != lastStage) { lastStage = num2; ApplyAll(); } if (!NetworkServer.active) { CleanupRages(); } CheckElites(); if (NetworkServer.active && modEnabled) { CheckRageLifetime(); } } if (rageOn.Value && modEnabled && NetworkServer.active) { rageTimer += Time.deltaTime; float num3 = Mathf.Max(1f, rageInterval.Value); if (rageTimer >= num3) { rageTimer = (TryRage() ? 0f : Mathf.Max(0f, num3 - 0.5f)); } } } private void LogDebug() { CombatDirector[] array = Object.FindObjectsOfType<CombatDirector>(); int count = TeamComponent.GetTeamMembers((TeamIndex)2).Count; TeamDef teamDef = TeamCatalog.GetTeamDef((TeamIndex)2); ((BaseUnityPlugin)this).Logger.LogInfo((object)$"[MobStatsUI] directors={array.Length} monstersAlive={count} cap={teamDef?.softCharacterLimit ?? (-1)}"); CombatDirector[] array2 = array; foreach (CombatDirector val in array2) { ((BaseUnityPlugin)this).Logger.LogInfo((object)$" {((Object)val).name}: credit={val.monsterCredit:0} mult={val.creditMultiplier} series={val.minSeriesSpawnInterval}-{val.maxSeriesSpawnInterval} skip={val.maximumNumberToSpawnBeforeSkipping} elite={val.eliteBias} dist={val.spawnDistanceMultiplier}"); } } private static int StageNumber() { if (!Object.op_Implicit((Object)(object)Run.instance)) { return 1; } return Run.instance.stageClearCount + 1; } private static float StageMul(StageRule r) { int num = StageNumber(); int num2 = Mathf.Max(1, Mathf.RoundToInt(r.first.Value)); if (num < num2) { return 1f; } int num3 = 1 + (num - num2) / Mathf.Max(1, Mathf.RoundToInt(r.every.Value)); int num4 = Mathf.RoundToInt(r.max.Value); if (num4 > 0) { num3 = Mathf.Min(num3, num4); } return Mathf.Pow(Mathf.Max(0f, r.mult.Value), (float)num3); } private static float StageHp() { return StageMul(stHp); } private static float StageDmg() { return StageMul(stDmg); } private static float StageCredit() { return StageMul(stCredit); } private static void CheckElites() { //IL_00cc: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: Unknown result type (might be due to invalid IL or missing references) if (!modEnabled) { return; } eliteDone.RemoveWhere((CharacterBody b) => !Object.op_Implicit((Object)(object)b)); CharacterBody[] array = Object.FindObjectsOfType<CharacterBody>(); foreach (CharacterBody val in array) { if (Object.op_Implicit((Object)(object)val) && IsEnemy(val) && val.isElite && !eliteDone.Contains(val)) { eliteDone.Add(val); HealthComponent healthComponent = val.healthComponent; bool num2 = Object.op_Implicit((Object)(object)healthComponent) && healthComponent.fullHealth > 0f && healthComponent.health / healthComponent.fullHealth > 0.99f; ApplyBody(val); if (num2 && NetworkServer.active && healthComponent.alive) { healthComponent.HealFraction(1f, default(ProcChainMask)); } } } } private static void CheckRageLifetime() { //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Unknown result type (might be due to invalid IL or missing references) if (rageLifetime.Value <= 0f) { return; } float time = Time.time; foreach (KeyValuePair<CharacterBody, Rage> item in rages.ToList()) { CharacterBody key = item.Key; if (Object.op_Implicit((Object)(object)key) && Object.op_Implicit((Object)(object)key.healthComponent) && key.healthComponent.alive && !(time - item.Value.born < rageLifetime.Value)) { expired.Add(key); key.healthComponent.Suicide((GameObject)null, (GameObject)null, default(DamageTypeCombo)); } } } private static void PrintStats() { if (statsOn.Value && NetworkServer.active) { Broadcast("<color=#80d0ff>=== MobStatsUI run summary ===</color>"); Broadcast("Kills: " + stats.kills + " | Rage mobs: " + stats.ragesSpawned + " spawned, " + stats.ragesKilled + " killed, " + stats.expired + " expired"); Broadcast("Bonus: " + stats.gold.ToString("0") + " gold, " + stats.xp.ToString("0") + " XP, " + stats.items + " items"); } } private static float Rnd(float a, float b) { return Random.Range(Mathf.Min(a, b), Mathf.Max(a, b)); } private static bool TryRage() { //IL_0203: Unknown result type (might be due to invalid IL or missing references) //IL_0209: Unknown result type (might be due to invalid IL or missing references) foreach (CharacterBody item in rages.Keys.Where((CharacterBody k) => !Object.op_Implicit((Object)(object)k) || !Object.op_Implicit((Object)(object)k.healthComponent) || !k.healthComponent.alive).ToList()) { rages.Remove(item); } foreach (CharacterBody item2 in origScale.Keys.Where((CharacterBody k) => !Object.op_Implicit((Object)(object)k)).ToList()) { origScale.Remove(item2); } if (rages.Count >= Mathf.RoundToInt(rageMax.Value)) { return true; } if (Random.value * 100f >= rageChance.Value) { return true; } List<CharacterBody> list = (from b in Object.FindObjectsOfType<CharacterBody>() where Object.op_Implicit((Object)(object)b) && IsEnemy(b) && Object.op_Implicit((Object)(object)b.healthComponent) && b.healthComponent.alive && !rages.ContainsKey(b) && snaps.ContainsKey(b.bodyIndex) && !b.isChampion && (!rageElite.Value || b.isElite) select b).ToList(); if (list.Count == 0) { return false; } CharacterBody val = list[Random.Range(0, list.Count)]; Rage rage = new Rage { size = Rnd(rageSMin.Value, rageSMax.Value), ms = Rnd(rageMMin.Value, rageMMax.Value), atk = Rnd(rageAMin.Value, rageAMax.Value), hp = rageHp.Value, dmg = rageDmg.Value, born = Time.time }; rages[val] = rage; ApplyBody(val); val.healthComponent.HealFraction(1f, default(ProcChainMask)); stats.ragesSpawned++; if (rageAnnounce.Value) { Broadcast("<color=#ff3030>A RAGE MOB has appeared!</color>"); } SendRage(val, rage); return true; } private static void CheckNet() { //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_002e: Expected O, but got Unknown //IL_00cd: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: Expected O, but got Unknown //IL_00f3: Unknown result type (might be due to invalid IL or missing references) //IL_00f8: Unknown result type (might be due to invalid IL or missing references) //IL_00fe: Expected O, but got Unknown if (NetworkServer.active) { if (!serverHandlers) { object obj = <>O.<4>__OnHello; if (obj == null) { NetworkMessageDelegate val = OnHello; <>O.<4>__OnHello = val; obj = (object)val; } NetworkServer.RegisterHandler((short)29103, (NetworkMessageDelegate)obj); serverHandlers = true; } if (syncedActive) { RestoreLocal(); } if (cfgDirty && Time.unscaledTime - cfgDirtyAt > 0.75f) { cfgDirty = false; SendConfig(null); } } else { serverHandlers = false; } if (!NetworkClient.active) { registeredClient = null; helloPending = false; if (syncedActive) { RestoreLocal(); } } else { if (NetworkClient.allClients.Count == 0) { return; } NetworkClient val2 = NetworkClient.allClients[0]; if (val2 == null) { return; } if (val2 != registeredClient) { object obj2 = <>O.<5>__OnRageMsg; if (obj2 == null) { NetworkMessageDelegate val3 = OnRageMsg; <>O.<5>__OnRageMsg = val3; obj2 = (object)val3; } val2.RegisterHandler((short)29101, (NetworkMessageDelegate)obj2); object obj3 = <>O.<6>__OnCfgMsg; if (obj3 == null) { NetworkMessageDelegate val4 = OnCfgMsg; <>O.<6>__OnCfgMsg = val4; obj3 = (object)val4; } val2.RegisterHandler((short)29102, (NetworkMessageDelegate)obj3); registeredClient = val2; helloPending = true; helloSent = 0; helloAt = 0f; } if (!helloPending || !val2.isConnected) { return; } if (helloAt <= 0f) { helloAt = Time.unscaledTime + 3f; } else if (Time.unscaledTime >= helloAt) { val2.Send((short)29103, (MessageBase)(object)new HelloMsg()); helloSent++; if (helloSent >= 2) { helloPending = false; } else { helloAt = Time.unscaledTime + 6f; } } } } private static void OnHello(NetworkMessage netMsg) { if (netMsg != null && netMsg.conn != null) { SendConfig(netMsg.conn); SendAllRages(netMsg.conn); } } private static void SendAllRages(NetworkConnection conn) { foreach (KeyValuePair<CharacterBody, Rage> item in rages.ToList()) { if (Object.op_Implicit((Object)(object)item.Key) && Object.op_Implicit((Object)(object)item.Key.healthComponent) && item.Key.healthComponent.alive) { SendRage(item.Key, item.Value, conn); } } } private static string SerializeSynced() { IEnumerable<string> values = from e in all where !localOnly.Contains(e) select Uri.EscapeDataString(e.Definition.Section + "/" + e.Definition.Key) + "=" + Uri.EscapeDataString(e.GetSerializedValue()); return string.Join("|", values); } private static void SendConfig(NetworkConnection conn) { if (!NetworkServer.active) { return; } string text = SerializeSynced(); int num = Mathf.Max(1, (text.Length + 600 - 1) / 600); int ver = ++syncVersion; for (int i = 0; i < num; i++) { int num2 = i * 600; ConfigChunkMsg configChunkMsg = new ConfigChunkMsg { ver = ver, idx = i, total = num, part = ((num2 < text.Length) ? text.Substring(num2, Mathf.Min(600, text.Length - num2)) : "") }; if (conn != null) { conn.Send((short)29102, (MessageBase)(object)configChunkMsg); } else { NetworkServer.SendToAll((short)29102, (MessageBase)(object)configChunkMsg); } } } private static void OnCfgMsg(NetworkMessage netMsg) { ConfigChunkMsg configChunkMsg = netMsg.ReadMessage<ConfigChunkMsg>(); if (NetworkServer.active || !ready) { return; } if (configChunkMsg.ver != cfgVer || cfgParts == null || cfgParts.Length != configChunkMsg.total) { cfgVer = configChunkMsg.ver; cfgParts = new string[Mathf.Max(1, configChunkMsg.total)]; cfgGot = 0; } if (configChunkMsg.idx >= 0 && configChunkMsg.idx < cfgParts.Length) { if (cfgParts[configChunkMsg.idx] == null) { cfgParts[configChunkMsg.idx] = configChunkMsg.part ?? ""; cfgGot++; } if (cfgGot >= cfgParts.Length) { string data = string.Concat(cfgParts); cfgParts = null; ApplySynced(data); } } } private static void ApplySynced(string data) { if ((Object)(object)I == (Object)null) { return; } List<ConfigEntryBase> list = all.Where((ConfigEntryBase e) => !localOnly.Contains(e)).ToList(); if (!syncedActive) { localBackup.Clear(); foreach (ConfigEntryBase item in list) { localBackup[item] = item.GetSerializedValue(); } ((BaseUnityPlugin)I).Config.SaveOnConfigSet = false; syncedActive = true; Say("Settings are now taken from the host"); } Dictionary<string, string> dictionary = new Dictionary<string, string>(); string[] array = data.Split('|'); for (int num = 0; num < array.Length; num++) { string[] array2 = array[num].Split('='); if (array2.Length == 2) { dictionary[Uri.UnescapeDataString(array2[0])] = Uri.UnescapeDataString(array2[1]); } } suppress = true; foreach (ConfigEntryBase item2 in list) { if (dictionary.TryGetValue(item2.Definition.Section + "/" + item2.Definition.Key, out var value)) { try { item2.SetSerializedValue(value); } catch { } } } suppress = false; ApplyAll(); } private static void RestoreLocal() { if (!syncedActive || (Object)(object)I == (Object)null) { return; } suppress = true; foreach (KeyValuePair<ConfigEntryBase, string> item in localBackup) { try { item.Key.SetSerializedValue(item.Value); } catch { } } suppress = false; localBackup.Clear(); syncedActive = false; ((BaseUnityPlugin)I).Config.SaveOnConfigSet = true; try { ((BaseUnityPlugin)I).Config.Save(); } catch { } if (ready) { ApplyAll(); } } private static void SendRage(CharacterBody b, Rage rg, NetworkConnection conn = null) { //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) if (!NetworkServer.active || !Object.op_Implicit((Object)(object)b)) { return; } NetworkIdentity component = ((Component)b).GetComponent<NetworkIdentity>(); if (Object.op_Implicit((Object)(object)component)) { RageNetMsg rageNetMsg = new RageNetMsg { id = component.netId, size = rg.size, ms = rg.ms, atk = rg.atk, hp = rg.hp, dmg = rg.dmg }; if (conn != null) { conn.Send((short)29101, (MessageBase)(object)rageNetMsg); } else { NetworkServer.SendToAll((short)29101, (MessageBase)(object)rageNetMsg); } } } private static void OnRageMsg(NetworkMessage netMsg) { //IL_0017: Unknown result type (might be due to invalid IL or missing references) RageNetMsg rageNetMsg = netMsg.ReadMessage<RageNetMsg>(); if (NetworkServer.active || !ready) { return; } GameObject val = ClientScene.FindLocalObject(rageNetMsg.id); if (Object.op_Implicit((Object)(object)val)) { CharacterBody component = val.GetComponent<CharacterBody>(); if (Object.op_Implicit((Object)(object)component)) { rages[component] = new Rage { size = rageNetMsg.size, ms = rageNetMsg.ms, atk = rageNetMsg.atk, hp = rageNetMsg.hp, dmg = rageNetMsg.dmg, born = Time.time }; ApplyBody(component); } } } private static void CleanupRages() { foreach (CharacterBody item in rages.Keys.Where((CharacterBody k) => !Object.op_Implicit((Object)(object)k) || !Object.op_Implicit((Object)(object)k.healthComponent) || !k.healthComponent.alive).ToList()) { rages.Remove(item); } } } }