Decompiled source of ItemStatistics v1.2.1
patchers/ItemStatisticsPatcher.dll
Decompiled 2 days agousing System; 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.Logging; using Mono.Cecil; [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("1.2.0.0")] public static class ItemStatisticsPatcher { private static ManualLogSource _log; private static ManualLogSource log { get { if (_log == null) { _log = Logger.CreateLogSource("ItemStatisticsPatcher"); } return _log; } } public static IEnumerable<string> TargetDLLs => new string[1] { "RoR2.dll" }; public static void Patch(AssemblyDefinition assembly) { //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Expected O, but got Unknown ModuleDefinition mainModule = assembly.MainModule; string[] files = Directory.GetFiles(Paths.PluginPath, "ItemStatistics.dll", SearchOption.AllDirectories); if (files.Length == 0) { log.LogFatal((object)"Failed to find ItemStatistics.dll"); return; } AssemblyDefinition val = AssemblyDefinition.ReadAssembly(files[0]); TypeReference fieldType = mainModule.ImportReference((TypeReference)(object)val.MainModule.GetType("ItemStatistics.Components.TrackedInventory")); TypeReference val2 = mainModule.ImportReference((TypeReference)(object)val.MainModule.GetType("ItemStatistics.ProcChain")); GenericInstanceType val3 = new GenericInstanceType(mainModule.ImportReference(typeof(List<>))); val3.GenericArguments.Add(val2); TypeReference fieldType2 = mainModule.ImportReference((TypeReference)(object)val.MainModule.GetType("ItemStatistics.Index")); ModuleDefinition mainModule2 = AssemblyDefinition.ReadAssembly(Path.Combine(Paths.ManagedPath, "UnityEngine.CoreModule.dll")).MainModule; TypeReference fieldType3 = mainModule.ImportReference((TypeReference)(object)mainModule2.GetType("UnityEngine.GameObject")); AddField(mainModule.GetType("RoR2.CharacterMaster"), fieldType, "trackedInventory"); AddField(mainModule.GetType("RoR2.DotController/DotStack"), val2, "dotStackChain"); AddField(mainModule.GetType("RoR2.DotController/PendingDamage"), (TypeReference)(object)val3, "pendingDotChainList"); AddField(mainModule.GetType("RoR2.Orbs.GenericDamageOrb"), fieldType3, "inflictor"); AddField(mainModule.GetType("RoR2.Orbs.DevilOrb"), fieldType3, "inflictor"); AddField(mainModule.GetType("RoR2.Orbs.BounceOrb"), fieldType3, "inflictor"); AddField(mainModule.GetType("RoR2.Orbs.LunarDetonatorOrb"), fieldType3, "inflictor"); AddField(mainModule.GetType("RoR2.Orbs.HealOrb"), fieldType2, "inflictor"); AddField(mainModule.GetType("EntityStates.FrozenState"), fieldType2, "freezeInflictor"); AddField(mainModule.GetType("EntityStates.FrozenState"), (TypeReference)(object)mainModule.GetType("RoR2.CharacterMaster"), "freezeInflictorMaster"); AddField(mainModule.GetType("RoR2.Orbs.VineOrb/SplitDebuffInformation"), val2, "procChain"); } private static FieldDefinition AddField(TypeDefinition target, TypeReference fieldType, string fieldName) { //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Expected O, but got Unknown if (target == null || fieldType == null) { log.LogError((object)("Null types in AddField: " + fieldName)); return null; } if (((IEnumerable<FieldDefinition>)target.Fields).FirstOrDefault((Func<FieldDefinition, bool>)((FieldDefinition a) => ((MemberReference)a).Name == fieldName)) != null) { log.LogWarning((object)(((MemberReference)target).Name + "." + fieldName + " already exists")); return null; } FieldDefinition val = new FieldDefinition(fieldName, (FieldAttributes)6, fieldType); target.Fields.Add(val); return val; } }
plugins/ItemStatistics.dll
Decompiled 2 days ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text; using System.Text.RegularExpressions; using System.Threading.Tasks; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using Dolso; using EntityStates; using EntityStates.CaptainDefenseMatrixItem; using EntityStates.GlobalSkills.LunarDetonator; using EntityStates.GummyClone; using EntityStates.Headstompers; using EntityStates.Toolbot; using HG; using HG.GeneralSerializer; using HG.Reflection; using ItemStatistics; using ItemStatistics.Components; using ItemStatistics.Hooks; using ItemStatistics.Networking; using ItemStatistics.Trackers; using Mono.Cecil; using Mono.Cecil.Cil; using Mono.Collections.Generic; using MonoMod.Cil; using MonoMod.RuntimeDetour; using MonoMod.Utils; using Rewired.Integration.UnityUI; using RiskOfOptions; using RiskOfOptions.OptionConfigs; using RiskOfOptions.Options; using RoR2; using RoR2.Items; using RoR2.Networking; using RoR2.Orbs; using RoR2.Projectile; using RoR2.Skills; using RoR2.Stats; using RoR2.UI; using TMPro; using Unity; using UnityEngine; using UnityEngine.AddressableAssets; using UnityEngine.EventSystems; using UnityEngine.Networking; using UnityEngine.ResourceManagement.AsyncOperations; using UnityEngine.UI; [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: CompilationRelaxations(8)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: OptIn] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.2.1.0")] [module: UnverifiableCode] namespace Dolso { internal static class log { private static ManualLogSource logger; internal static void start(ManualLogSource logSource) { logger = logSource; } internal static void start(string name) { logger = Logger.CreateLogSource(name); } internal static void info(object data) { logger.LogInfo(data); } internal static void message(object data) { logger.LogMessage(data); } internal static void warning(object data) { logger.LogWarning(data); } internal static void error(object data) { logger.LogError(data); } internal static void fatal(object data) { logger.LogFatal(data); } internal static void LogError(this ILCursor c, object data) { logger.LogError((object)string.Format($"ILCursor failure, skipping: {data}\n{c}")); } internal static void LogErrorCaller(this ILCursor c, object data) { logger.LogError((object)string.Format($"ILCursor failed in {new StackFrame(1).GetMethod().Name}, skipping: {data}\n{c}")); } } internal static class HookManager { internal delegate bool ConfigEnabled<T>(T configValue); internal const BindingFlags allFlags = BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic; private static readonly ConfigEnabled<bool> boolConfigEnabled = (bool configValue) => configValue; private static ILHookConfig ilHookConfig = new ILHookConfig { ManualApply = true }; private static HookConfig onHookConfig = new HookConfig { ManualApply = true }; internal static void Hook(Type typeFrom, string methodFrom, Manipulator ilHook) { HookInternal(GetMethod(typeFrom, methodFrom), ilHook); } internal static void Hook(MethodBase methodFrom, Manipulator ilHook) { HookInternal(methodFrom, ilHook); } internal static void Hook(Delegate from, Manipulator ilHook) { HookInternal(from.Method, ilHook); } internal static void Hook(Type typeFrom, string methodFrom, Delegate onHook) { HookInternal(GetMethod(typeFrom, methodFrom), onHook.Method, onHook.Target); } internal static void Hook(MethodBase methodFrom, MethodInfo onHook) { HookInternal(methodFrom, onHook, null); } internal static void Hook(MethodBase methodFrom, Delegate onHook) { HookInternal(methodFrom, onHook.Method, onHook.Target); } internal static void Hook(Delegate from, Delegate onHook) { HookInternal(from.Method, onHook.Method, onHook.Target); } internal static void Hook(Type typeFrom, string methodFrom, Delegate onHook, object instance) { HookInternal(GetMethod(typeFrom, methodFrom), onHook.Method, instance); } internal static void Hook(MethodBase methodFrom, MethodInfo onHook, object target) { HookInternal(methodFrom, onHook, target); } private static void HookInternal(MethodBase methodFrom, Manipulator ilHook) { //IL_002c: Unknown result type (might be due to invalid IL or missing references) if (methodFrom == null) { log.error("null methodFrom for hook: " + ((Delegate)(object)ilHook).Method.Name); return; } try { new ILHook(methodFrom, ilHook, ref ilHookConfig).Apply(); } catch (Exception ex) { log.error($"Failed to apply ILHook: {methodFrom.DeclaringType}::{methodFrom.Name} - {((Delegate)(object)ilHook).Method.Name}\n{ex}"); } } private static void HookInternal(MethodBase methodFrom, MethodInfo onHook, object target) { //IL_0028: Unknown result type (might be due to invalid IL or missing references) if (methodFrom == null) { log.error("null methodFrom for hook: " + onHook.Name); return; } try { new Hook(methodFrom, onHook, target, ref onHookConfig).Apply(); } catch (Exception ex) { log.error($"Failed to apply Hook: {methodFrom.DeclaringType}::{methodFrom.Name} - {onHook.Name}\n{ex}"); } } internal static void HookConfig(this ConfigEntry<bool> configEntry, Type typeFrom, string methodFrom, Manipulator ilHook) { configEntry.HookConfigInternal(boolConfigEnabled, GetMethod(typeFrom, methodFrom), (Delegate)(object)ilHook); } internal static void HookConfig(this ConfigEntry<bool> configEntry, MethodBase methodFrom, Manipulator ilHook) { configEntry.HookConfigInternal(boolConfigEnabled, methodFrom, (Delegate)(object)ilHook); } internal static void HookConfig(this ConfigEntry<bool> configEntry, Type typeFrom, string methodFrom, Delegate onHook) { configEntry.HookConfigInternal(boolConfigEnabled, GetMethod(typeFrom, methodFrom), onHook); } internal static void HookConfig(this ConfigEntry<bool> configEntry, MethodBase methodFrom, Delegate onHook) { configEntry.HookConfigInternal(boolConfigEnabled, methodFrom, onHook); } internal static void HookConfig<T>(this ConfigEntry<T> configEntry, ConfigEnabled<T> enabled, Type typeFrom, string methodFrom, Manipulator ilHook) { configEntry.HookConfigInternal(enabled, GetMethod(typeFrom, methodFrom), (Delegate)(object)ilHook); } internal static void HookConfig<T>(this ConfigEntry<T> configEntry, ConfigEnabled<T> enabled, MethodBase methodFrom, Manipulator ilHook) { configEntry.HookConfigInternal(enabled, methodFrom, (Delegate)(object)ilHook); } internal static void HookConfig<T>(this ConfigEntry<T> configEntry, ConfigEnabled<T> enabled, Type typeFrom, string methodFrom, Delegate onHook) { configEntry.HookConfigInternal(enabled, GetMethod(typeFrom, methodFrom), onHook); } internal static void HookConfig<T>(this ConfigEntry<T> configEntry, ConfigEnabled<T> enabled, MethodBase methodFrom, Delegate onHook) { configEntry.HookConfigInternal(enabled, methodFrom, onHook); } private static void HookConfigInternal<T>(this ConfigEntry<T> configEntry, ConfigEnabled<T> enabled, MethodBase methodFrom, Delegate hook) { //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Expected O, but got Unknown try { IDetour detour = ManualDetour(methodFrom, hook); EventHandler eventHandler = delegate(object sender, EventArgs _) { UpdateHook(detour, enabled((sender as ConfigEntry<T>).Value)); }; configEntry.SettingChanged += eventHandler; eventHandler(configEntry, (EventArgs)new SettingChangedEventArgs((ConfigEntryBase)(object)configEntry)); } catch (Exception ex) { log.error($"Failed to do config hook {methodFrom.DeclaringType}::{methodFrom.Name} - {hook.Method.Name}\n{ex}"); } } private static void UpdateHook(IDetour hook, bool enabled) { if (enabled) { if (!hook.IsApplied) { hook.Apply(); } } else if (hook.IsApplied) { hook.Undo(); } } internal static IDetour ManualDetour(Type typeFrom, string methodFrom, Delegate hook) { return ManualDetour(GetMethod(typeFrom, methodFrom), hook); } internal static IDetour ManualDetour(MethodBase methodFrom, Delegate hook) { //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Expected O, but got Unknown //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Expected O, but got Unknown if (methodFrom == null) { log.error("null methodFrom for detour: " + hook.Method.Name); } else { try { Manipulator val = (Manipulator)(object)((hook is Manipulator) ? hook : null); if (val != null) { return (IDetour)new ILHook(methodFrom, val, ref ilHookConfig); } return (IDetour)new Hook(methodFrom, hook, ref onHookConfig); } catch (Exception ex) { log.error($"Failed to create detour {methodFrom.DeclaringType}::{methodFrom} - {hook.Method.Name}\n{ex}"); } } return null; } internal static MethodInfo GetMethod(Type typeFrom, string methodName) { if (typeFrom == null || methodName == null) { log.error($"Null argument in GetMethod: type={typeFrom}, name={methodName}"); return null; } MethodInfo[] array = (from predicate in typeFrom.GetMethods(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic) where predicate.Name == methodName select predicate).ToArray(); switch (array.Length) { case 1: return array[0]; case 0: log.error($"Failed to find method: {typeFrom}::{methodName}"); return null; default: { log.error($"{array.Length} ambiguous matches found for: {typeFrom}::{methodName}"); MethodInfo[] array2 = array; for (int i = 0; i < array2.Length; i++) { log.error(array2[i]); } return null; } } } internal static MethodInfo GetMethod(Type typeFrom, string methodName, params Type[] parameters) { if (typeFrom == null || methodName == null) { log.error($"Null argument in GetMethod: type={typeFrom}, name={methodName}"); return null; } MethodInfo? method = typeFrom.GetMethod(methodName, BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, null, parameters, null); if (method == null) { log.error($"Failed to find method: {typeFrom}::{methodName}_{parameters.Length}"); } return method; } internal static void SetPriority(string[] before = null, string[] after = null) { ilHookConfig.Before = before; onHookConfig.Before = before; ilHookConfig.After = after; onHookConfig.After = after; } } internal static class Utilities { private static GameObject _prefabParent; internal static GameObject CreatePrefab(GameObject gameObject, string name = null) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Expected O, but got Unknown if (!Object.op_Implicit((Object)(object)_prefabParent)) { _prefabParent = new GameObject("DolsoPrefabs"); Object.DontDestroyOnLoad((Object)(object)_prefabParent); ((Object)_prefabParent).hideFlags = (HideFlags)61; _prefabParent.SetActive(false); } GameObject val = Object.Instantiate<GameObject>(gameObject, _prefabParent.transform); if (name != null) { ((Object)val).name = name; } return val; } internal static Task<Obj> GetAddressableAsync<Obj>(string addressable) where Obj : Object { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) return Addressables.LoadAssetAsync<Obj>((object)addressable).Task; } internal static Task<GameObject> GetAddressableAsync(string addressable) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) return Addressables.LoadAssetAsync<GameObject>((object)addressable).Task; } internal static void DoAddressable<Obj>(string addressable, Action<Obj> callback) where Obj : Object { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) AsyncOperationHandle<Obj> val = Addressables.LoadAssetAsync<Obj>((object)addressable); val.Completed += delegate(AsyncOperationHandle<Obj> a) { callback(a.Result); }; } internal static void DoAddressable(string addressable, Action<GameObject> callback) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) AsyncOperationHandle<GameObject> val = Addressables.LoadAssetAsync<GameObject>((object)addressable); val.Completed += delegate(AsyncOperationHandle<GameObject> a) { callback(a.Result); }; } internal static void AddressableAddComp<Comp>(string addressable) where Comp : Component { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) AsyncOperationHandle<GameObject> val = Addressables.LoadAssetAsync<GameObject>((object)addressable); val.Completed += delegate(AsyncOperationHandle<GameObject> a) { a.Result.AddComponent<Comp>(); }; } internal static void AddressableAddComp<Comp>(string addressable, Action<Comp> callback) where Comp : Component { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) AsyncOperationHandle<GameObject> val = Addressables.LoadAssetAsync<GameObject>((object)addressable); val.Completed += delegate(AsyncOperationHandle<GameObject> a) { callback(a.Result.AddComponent<Comp>()); }; } internal static void AddressableAddCompSingle<Comp>(string addressable) where Comp : Component { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) AsyncOperationHandle<GameObject> val = Addressables.LoadAssetAsync<GameObject>((object)addressable); val.Completed += delegate(AsyncOperationHandle<GameObject> a) { if (!Object.op_Implicit((Object)(object)a.Result.GetComponent<Comp>())) { a.Result.AddComponent<Comp>(); } }; } internal static void ModifyStateConfig(this EntityStateConfiguration stateConfig, string fieldName, object newValue) { SerializedField[] serializedFields = stateConfig.serializedFieldsCollection.serializedFields; for (int i = 0; i < serializedFields.Length; i++) { if (serializedFields[i].fieldName == fieldName) { Object val = (Object)((newValue is Object) ? newValue : null); if (val != null) { serializedFields[i].fieldValue.objectValue = val; } else if (newValue != null && StringSerializer.CanSerializeType(newValue.GetType())) { serializedFields[i].fieldValue.stringValue = StringSerializer.Serialize(newValue.GetType(), newValue); } else { log.error("Invalid value for SerializedField: " + newValue); } return; } } log.error("Failed to find " + fieldName + " for " + ((Object)stateConfig).name); } internal static bool IsKeyDown(this ConfigEntry<KeyboardShortcut> key, bool onlyPressed) { //IL_0004: Unknown result type (might be due to invalid IL or missing references) //IL_0009: 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_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0038: 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_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) KeyboardShortcut value; if (onlyPressed) { value = key.Value; if (!Input.GetKeyDown(((KeyboardShortcut)(ref value)).MainKey)) { goto IL_0030; } } if (!onlyPressed) { value = key.Value; if (!Input.GetKey(((KeyboardShortcut)(ref value)).MainKey)) { goto IL_0030; } } value = key.Value; foreach (KeyCode modifier in ((KeyboardShortcut)(ref value)).Modifiers) { if (!Input.GetKey(modifier)) { return false; } } return true; IL_0030: return false; } } internal static class RiskofOptions { internal const string rooGuid = "com.rune580.riskofoptions"; internal static bool enabled => Chainloader.PluginInfos.ContainsKey("com.rune580.riskofoptions"); internal static void SetSprite(Sprite sprite) { ModSettingsManager.SetModIcon(sprite); } internal static void SetSpriteDefaultIcon() { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Expected O, but got Unknown //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) try { string fullName = new DirectoryInfo(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)).FullName; Texture2D val = new Texture2D(256, 256); if (ImageConversion.LoadImage(val, File.ReadAllBytes(Path.Combine(fullName, "icon.png")))) { ModSettingsManager.SetModIcon(Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0.5f))); } else { log.error("Failed to load icon.png"); } } catch (Exception ex) { log.error("Failed to load icon.png\n" + ex); } } internal static void AddOption<T>(ConfigEntry<T> entry) { AddOption<T>(entry, "", "", restartRequired: false); } internal static void AddOption<T>(ConfigEntry<T> entry, string categoryName = "", string name = "", bool restartRequired = false) { //IL_0146: Unknown result type (might be due to invalid IL or missing references) //IL_014b: Unknown result type (might be due to invalid IL or missing references) //IL_0156: Expected O, but got Unknown //IL_0156: Unknown result type (might be due to invalid IL or missing references) //IL_016c: Expected O, but got Unknown //IL_0167: Unknown result type (might be due to invalid IL or missing references) //IL_016d: Expected O, but got Unknown //IL_0126: Unknown result type (might be due to invalid IL or missing references) //IL_012b: Unknown result type (might be due to invalid IL or missing references) //IL_012d: Unknown result type (might be due to invalid IL or missing references) //IL_0132: Unknown result type (might be due to invalid IL or missing references) //IL_0134: Unknown result type (might be due to invalid IL or missing references) //IL_013e: Expected O, but got Unknown //IL_0139: Unknown result type (might be due to invalid IL or missing references) //IL_0114: Unknown result type (might be due to invalid IL or missing references) //IL_011e: Expected O, but got Unknown //IL_0119: Unknown result type (might be due to invalid IL or missing references) //IL_0102: Unknown result type (might be due to invalid IL or missing references) //IL_010c: Expected O, but got Unknown //IL_0107: Unknown result type (might be due to invalid IL or missing references) //IL_00f0: Unknown result type (might be due to invalid IL or missing references) //IL_00fa: Expected O, but got Unknown //IL_00f5: Unknown result type (might be due to invalid IL or missing references) //IL_00db: Unknown result type (might be due to invalid IL or missing references) //IL_00e5: Expected O, but got Unknown //IL_00e0: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: Expected O, but got Unknown //IL_00cb: Unknown result type (might be due to invalid IL or missing references) object obj; if (!(typeof(T) == typeof(float))) { obj = ((!(typeof(T) == typeof(string))) ? ((!(typeof(T) == typeof(bool))) ? ((!(typeof(T) == typeof(int))) ? ((!(typeof(T) == typeof(Color))) ? ((!(typeof(T) == typeof(KeyboardShortcut))) ? ((object)((!typeof(T).IsEnum) ? ((ChoiceOption)null) : new ChoiceOption((ConfigEntryBase)(object)entry, new ChoiceConfig()))) : ((object)new KeyBindOption(entry as ConfigEntry<KeyboardShortcut>, new KeyBindConfig()))) : ((object)new ColorOption(entry as ConfigEntry<Color>, new ColorOptionConfig()))) : ((object)new IntFieldOption(entry as ConfigEntry<int>, new IntFieldConfig()))) : ((object)new CheckBoxOption(entry as ConfigEntry<bool>, new CheckBoxConfig()))) : ((object)new StringInputFieldOption(entry as ConfigEntry<string>, new InputFieldConfig { submitOn = (SubmitEnum)6, lineType = (LineType)0 }))); } else { ConfigEntry<float> obj2 = entry as ConfigEntry<float>; FloatFieldConfig val = new FloatFieldConfig(); ((NumericFieldConfig<float>)val).FormatString = "{0:f2}"; ((BaseOptionConfig)val).description = ((ConfigEntryBase)(object)entry).DescWithDefault("{0:f2}"); obj = (object)new FloatFieldOption(obj2, val); } BaseOption val2 = (BaseOption)obj; if (val2 != null) { BaseOptionConfig config = val2.GetConfig(); config.category = categoryName; config.name = name; config.restartRequired = restartRequired; if (config.description == "") { config.description = ((ConfigEntryBase)(object)entry).DescWithDefault(); } ModSettingsManager.AddOption(val2); } } internal static void AddOption(ConfigEntry<float> entry, float min, float max, string format = "{0:f2}") { AddFloatSlider(entry, min, max, format); } internal static void AddFloatSlider(ConfigEntry<float> entry, float min, float max, string format = "{0:f2}", string categoryName = "") { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_001b: 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_0035: Expected O, but got Unknown //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Expected O, but got Unknown ModSettingsManager.AddOption((BaseOption)new SliderOption(entry, new SliderConfig { min = min, max = max, FormatString = format, category = categoryName, description = ((ConfigEntryBase)(object)entry).DescWithDefault(format) })); } internal static void AddIntSlider(ConfigEntry<int> entry, int min, int max, string categoryName = "") { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Expected O, but got Unknown //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Expected O, but got Unknown ModSettingsManager.AddOption((BaseOption)new IntSliderOption(entry, new IntSliderConfig { min = min, max = max, category = categoryName, description = ((ConfigEntryBase)(object)entry).DescWithDefault() })); } private static string DescWithDefault(this ConfigEntryBase entry) { return $"{entry.Description.Description}\n[Default: {entry.DefaultValue}]"; } private static string DescWithDefault(this ConfigEntryBase entry, string format) { return string.Format("{1}\n[Default: " + format + "]", entry.DefaultValue, entry.Description.Description); } } } namespace ItemStatistics { public readonly struct ChainContext : IDisposable { private readonly ProcChain prevProcChain; private static readonly List<ChainContext> chains; public static ConstructorInfo constructor0 => typeof(ChainContext).GetConstructor(Type.EmptyTypes); public static ConstructorInfo constructor1 => typeof(ChainContext).GetConstructor(new Type[1] { typeof(ProcChain) }); public ChainContext(ProcChain procChain) { prevProcChain = CurrentContext.procChain; chains.Add(this); CurrentContext.procChain = procChain; } public ChainContext() : this(null) { } public void Dispose() { CurrentContext.procChain = prevProcChain; chains.RemoveAt(chains.Count - 1); } static ChainContext() { chains = new List<ChainContext>(); Stage.onStageStartGlobal += SafetyCheck; } private static void SafetyCheck(Stage stage) { if (chains.Count != 0) { log.error("ChainContext has leaked chains: " + string.Join(", ", chains)); chains.Clear(); } } public override string ToString() { if (prevProcChain != null) { return prevProcChain.ToString(); } return "null chain"; } } internal static class Config { internal enum ResetMode { Never, WhenNotInInventory, EveryPickup } private static ConfigFile configFile; internal static ConfigEntry<ResetMode> resetOnStackChanged; internal static ConfigEntry<KeyboardShortcut> resetSpamKey; internal static void DoConfig(ConfigFile bepConfigFile) { //IL_003e: Unknown result type (might be due to invalid IL or missing references) configFile = bepConfigFile; resetOnStackChanged = configFile.Bind<ResetMode>(string.Empty, "Reset on Stack Changed", ResetMode.Never, "When item stack changes, should its stats automatically be reset? Can right click on item to force a reset. Warning: having this enabled will cause stats to be reset during Mithrix's item steal phase"); resetSpamKey = configFile.Bind<KeyboardShortcut>(string.Empty, "Reset Spam Key", new KeyboardShortcut((KeyCode)306, Array.Empty<KeyCode>()), "Hold this key down to easily reset icons you hover over"); if (Chainloader.PluginInfos.ContainsKey("com.rune580.riskofoptions")) { DoRiskOfOptions(); } } internal static void DoRiskOfOptions() { RiskofOptions.SetSpriteDefaultIcon(); RiskofOptions.AddOption<ResetMode>(resetOnStackChanged); RiskofOptions.AddOption<KeyboardShortcut>(resetSpamKey); } [ConCommand(/*Could not decode attribute arguments.*/)] private static void ReloadConfig(ConCommandArgs args) { configFile.Reload(); Debug.Log((object)"ItemStatistics config reloaded"); } } public static class CurrentContext { public static TrackedInventory attackerTrackedInventory; public static Inventory attackerInventory; public static TrackedInventory victimTrackedInventory; public static Inventory victimInventory; public static ProcChain procChain; private static (DamageInfo, ProcChain) cachedInfoChain; internal static ProcChain FindProcChain(DamageInfo damageInfo) { //IL_007e: Unknown result type (might be due to invalid IL or missing references) if (damageInfo == cachedInfoChain.Item1) { return cachedInfoChain.Item2; } ProcComponent procComponent = default(ProcComponent); if (Object.op_Implicit((Object)(object)damageInfo.inflictor) && damageInfo.inflictor.TryGetComponent<ProcComponent>(ref procComponent)) { cachedInfoChain = (damageInfo, procComponent.procChain); return cachedInfoChain.Item2; } if (((DamageTypeCombo)(ref damageInfo.damageType)).IsDamageSourceSkillBased && (!Object.op_Implicit((Object)(object)damageInfo.attacker) || !Object.op_Implicit((Object)(object)damageInfo.attacker.GetComponent<MinionComponent>()))) { cachedInfoChain = (damageInfo, SkillChainFromCombo(damageInfo.damageType)); return cachedInfoChain.Item2; } cachedInfoChain = (damageInfo, null); return null; } internal static ProcChain SkillChainFromCombo(DamageTypeCombo damageType) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0001: Unknown result type (might be due to invalid IL or missing references) Index index = damageType.damageSource; if (index.isNotNone) { return ProcChain.TryGetCachedSkillChain(index); } return null; } } public readonly struct HitContext : IDisposable { private readonly ProcChain prevProcChain; private readonly TrackedInventory prevAttackerTrackedInventory; private readonly Inventory prevAttackerInventory; private readonly TrackedInventory prevVictimTrackedInventory; private readonly Inventory prevVictimInventory; private static readonly List<HitContext> hits; public HitContext(ProcChain procChain, TrackedInventory attackerTrackedInventory, Inventory attackerInventory, TrackedInventory victimTrackedInventory, Inventory victimInventory) { prevProcChain = CurrentContext.procChain; prevAttackerTrackedInventory = CurrentContext.attackerTrackedInventory; prevAttackerInventory = CurrentContext.attackerInventory; prevVictimTrackedInventory = CurrentContext.victimTrackedInventory; prevVictimInventory = CurrentContext.victimInventory; hits.Add(this); CurrentContext.procChain = procChain; CurrentContext.attackerTrackedInventory = attackerTrackedInventory; CurrentContext.attackerInventory = attackerInventory; CurrentContext.victimTrackedInventory = victimTrackedInventory; CurrentContext.victimInventory = victimInventory; } public HitContext() : this(null, null, null, null, null) { } public void Dispose() { CurrentContext.procChain = prevProcChain; CurrentContext.attackerTrackedInventory = prevAttackerTrackedInventory; CurrentContext.attackerInventory = prevAttackerInventory; CurrentContext.victimTrackedInventory = prevVictimTrackedInventory; CurrentContext.victimInventory = prevVictimInventory; hits.RemoveAt(hits.Count - 1); } static HitContext() { hits = new List<HitContext>(); Stage.onStageStartGlobal += SafetyCheck; } private static void SafetyCheck(Stage stage) { if (hits.Count != 0) { log.error("HitContext has leaked hits: " + string.Join(",\n", hits)); hits.Clear(); } } public override string ToString() { return string.Join(", ", prevProcChain, prevAttackerTrackedInventory, prevAttackerInventory, prevVictimTrackedInventory, prevVictimInventory); } } [Serializable] public struct Index : IEquatable<Index> { [SerializeField] private int _value; public readonly IndexType type => (IndexType)(_value >> 16); public readonly int index => (short)_value; public readonly bool isNotNone => _value != 0; public Index(ItemIndex index) { //IL_0001: 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) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Expected I4, but got Unknown _value = (index & 0xFFFF) + 65536; } public Index(EquipmentIndex index) { //IL_0001: 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) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Expected I4, but got Unknown _value = (index & 0xFFFF) + 131072; } public Index(SkillSlot index) { //IL_0001: 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) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Expected I4, but got Unknown _value = (index & 0xFFFF) + 196608; } public Index(MiscIndex index) { _value = (int)((index & (MiscIndex)65535) + 262144); } public Index(short type, short index) { _value = (index & 0xFFFF) + (type << 16); } public static implicit operator Index(ItemIndex index) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) return new Index(index); } public static implicit operator Index(ItemDef itemDef) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) return new Index(itemDef.itemIndex); } public static implicit operator Index(EquipmentIndex index) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) return new Index(index); } public static implicit operator Index(EquipmentDef equipDef) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) return new Index(equipDef.equipmentIndex); } public static implicit operator Index(SkillSlot index) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) return new Index(index); } public static implicit operator Index(MiscIndex index) { return new Index(index); } public static implicit operator Index(DamageSource damageSource) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Expected I4, but got Unknown switch (damageSource - 1) { case 0: return new Index((SkillSlot)0); case 1: case 2: return new Index((SkillSlot)1); case 3: case 4: return new Index((SkillSlot)2); case 7: case 8: return new Index((SkillSlot)3); default: return new Index(0, 0); } } public static bool operator ==(Index a, Index b) { return a._value == b._value; } public static bool operator !=(Index a, Index b) { return a._value != b._value; } public override readonly bool Equals(object obj) { if (obj is Index) { return _value == ((Index)obj)._value; } return false; } public readonly bool Equals(Index index) { return _value == index._value; } public override readonly int GetHashCode() { return _value; } public override readonly string ToString() { //IL_0099: Unknown result type (might be due to invalid IL or missing references) switch (type) { case IndexType.None: return "None" + ((index == 0) ? "" : ("." + index)); case IndexType.Item: return Language.GetString(ItemCatalog.GetItemDef((ItemIndex)index).nameToken); case IndexType.Equip: return Language.GetString(EquipmentCatalog.GetEquipmentDef((EquipmentIndex)index).nameToken); case IndexType.SkillSlot: { SkillSlot val = (SkillSlot)(sbyte)index; return "Skill." + ((object)(SkillSlot)(ref val)).ToString(); } case IndexType.Misc: return "Misc." + (MiscIndex)index; default: return $"Unknown Index {type}.{index}"; } } internal static void Serialize(NetworkWriter writer, Index value) { writer.WritePackedUInt32((uint)value._value); } internal static Index Deserialize(NetworkReader reader) { Index result = default(Index); result._value = (int)reader.ReadPackedUInt32(); return result; } static Index() { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Expected O, but got Unknown //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Expected O, but got Unknown //IL_003d: Unknown result type (might be due to invalid IL or missing references) StringSerializer.serializationHandlers[typeof(Index)] = new SerializationHandler { serializer = new SerializerDelegate(SerializeToString), deserializer = new DeserializerDelegate(DeserializeFromString) }; } private static string SerializeToString(object obj) { Index index = (Index)obj; return $"{((int)index.type).ToString(CultureInfo.InvariantCulture)} {index.index.ToString(CultureInfo.InvariantCulture)}"; } private static object DeserializeFromString(string str) { string[] array = StringSerializer.SplitToComponents(str, typeof(Index), 2); return new Index(short.Parse(array[0], CultureInfo.InvariantCulture), short.Parse(array[1], CultureInfo.InvariantCulture)); } } public enum IndexType { None, Item, Equip, SkillSlot, Misc } public enum MiscIndex { NeverInInventory = -1, Ignore, Regen, Barrier, MinionDamage } public static class ItemStatisticsAPI { public static void AddTrackerToPrefab(GameObject prefab, Index indexToCredit) { prefab.AddComponent<ProcComponent>().index = indexToCredit; } public static void AddMinionTrackerToPrefab(GameObject prefab, Index indexToCredit) { prefab.AddComponent<MinionComponent>().index = indexToCredit; } public static void AddTrackedIndex(Index indexToAdd, TrackedDef trackedDef) { if (trackedDef != null) { ItemStatisticsPlugin.indexToDef.Add(indexToAdd, trackedDef); } else { log.error($"Attempted to give {indexToAdd} a null tracker type"); } } public static TrackedInventory GetTrackedInventory(CharacterMaster master, bool includeFromMinion) { return TrackedInventory.GetTrackedInventory(master, includeFromMinion); } public static bool TryGetTrackedInventory(CharacterMaster master, bool includeFromMinion, out TrackedInventory trackedInventory) { return TrackedInventory.TryGetTrackedInventory(master, includeFromMinion, out trackedInventory); } public static GameObject CreateNewInflictor(Index index, ProcChain parentChain = null) { return ProcComponent.CreateInflictor(index, parentChain); } public static void CreditNextHeal(Index indexToCredit) { HCHeal.healIndex = indexToCredit; } public static void CreditDamage(TrackedInventory trackedInventory, Index index, float damage) { trackedInventory.AddDamage(index, damage); } public static void CreditGold(TrackedInventory trackedInventory, Index index, float gold) { trackedInventory.AddGold(index, gold); } public static void CreditProcAttempt(TrackedInventory trackedInventory, Index index) { trackedInventory.AddAttempt(index); } public static void CreditProcSuccess(TrackedInventory trackedInventory, Index index) { trackedInventory.AddSuccess(index); } } [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInPlugin("dolso.ItemStatistics", "ItemStatistics", "1.2.1")] public class ItemStatisticsPlugin : BaseUnityPlugin { public const string ModGuid = "dolso.ItemStatistics"; public const string Version = "1.2.1"; internal static readonly Dictionary<Index, TrackedDef> indexToDef = new Dictionary<Index, TrackedDef>(); internal static GameObject missileLauncher; internal static GameObject hhOverloading; internal static GameObject hhFireTrail; internal static GameObject hhGoldOuter; internal static GameObject hhGoldInner; internal static GameObject hhBead; internal static int crocoDiseaseProjectileIndex; internal static BodyIndex falseSonCharacterBodyIndex; private void Awake() { log.start(((BaseUnityPlugin)this).Logger); Config.DoConfig(((BaseUnityPlugin)this).Config); ModifyAddressablesAsync(); Stopwatch stopwatch = Stopwatch.StartNew(); GeneralHooks.Apply(); HCDamage.Apply(); HCHeal.Apply(); GEMHooks.Apply(); ItemHooks.Apply(); OrbHooks.Apply(); DotTracking.Apply(); EquipmentHooks.Apply(); SurvivorHooks.Apply(); NetworkHooks.Apply(); FreezeHooks.Apply(); Language.collectLanguageRootFolders += CollectLanguageRootFolders; log.info($"Hooks completed in {stopwatch.Elapsed.TotalSeconds:f2}s"); } private static void ModifyAddressablesAsync() { try { Utilities.AddressableAddComp<IconBehaviour>("RoR2/Base/UI/ItemIcon.prefab", (Action<IconBehaviour>)delegate(IconBehaviour a) { a.type = IndexType.Item; }); Utilities.AddressableAddComp<IconBehaviour>("RoR2/Base/UI/ItemIconScoreboard_InGame.prefab", (Action<IconBehaviour>)delegate(IconBehaviour a) { a.type = IndexType.Item; }); Utilities.AddressableAddComp<TrackedInventory>("RoR2/Base/Core/PlayerMaster.prefab", (Action<TrackedInventory>)delegate(TrackedInventory a) { ((Component)a).GetComponent<CharacterMaster>().trackedInventory = a; }); Utilities.DoAddressable("RoR2/Base/UI/HUDSimple.prefab", delegate(GameObject hudsimple) { EquipmentIcon[] componentsInChildren = hudsimple.GetComponentsInChildren<EquipmentIcon>(); for (int i = 0; i < componentsInChildren.Length; i++) { ((Component)componentsInChildren[i]).gameObject.AddComponent<IconBehaviour>().type = IndexType.Equip; } SkillIcon[] componentsInChildren2 = hudsimple.GetComponentsInChildren<SkillIcon>(); for (int i = 0; i < componentsInChildren2.Length; i++) { ((Component)componentsInChildren2[i]).gameObject.AddComponent<IconBehaviour>().type = IndexType.SkillSlot; } }); Utilities.DoAddressable("RoR2/Base/UI/ScoreboardStrip.prefab", delegate(GameObject scoreboardStrip) { ((Component)scoreboardStrip.GetComponentInChildren<EquipmentIcon>()).gameObject.AddComponent<IconBehaviour>().type = IndexType.Equip; PlayerTooltip.CreateTooltipPrefab(scoreboardStrip); }); ToolbotStance.DoSetup(); } catch (Exception ex) { log.error("Failed to do addressables\n" + ex); } } [SystemInitializer(new Type[] { typeof(PickupCatalog), typeof(SurvivorCatalog), typeof(ProjectileCatalog) })] private static void Init() { //IL_0b89: Unknown result type (might be due to invalid IL or missing references) //IL_0b8e: Unknown result type (might be due to invalid IL or missing references) Dictionary<Index, TrackedDef> dictionary = indexToDef; dictionary.Add((SkillSlot)0, TrackedDef.Skill); dictionary.Add((SkillSlot)1, TrackedDef.Skill); dictionary.Add((SkillSlot)2, TrackedDef.Skill); dictionary.Add((SkillSlot)3, TrackedDef.Skill); dictionary.Add(MiscIndex.Regen, new TrackedDef(typeof(HealTracker), TrackedDef.regenPortionTooltip)); dictionary.Add(MiscIndex.Barrier, new TrackedDef(typeof(ArmorTracker), TrackedDef.barrierBlockedTooltip)); dictionary.Add(MiscIndex.MinionDamage, new TrackedDef(typeof(DamageTracker), TrackedDef.minionPortionTooltip)); dictionary.Add(Items.Bear, TrackedDef.ArmorCount); dictionary.Add(Items.BearVoid, TrackedDef.ArmorCount); dictionary.Add(Items.Crowbar, TrackedDef.Damage); dictionary.Add(Items.ExplodeOnDeathVoid, TrackedDef.Damage); dictionary.Add(Items.NearbyDamageBonus, TrackedDef.Damage); dictionary.Add(Items.FragileDamageBonus, TrackedDef.Damage); dictionary.Add(Items.FragileDamageBonusConsumed, new TrackedDef(typeof(WatchTracker), TrackedDef.damageTooltip)); dictionary.Add(Items.BossDamageBonus, TrackedDef.Damage); dictionary.Add(Items.CritGlasses, new TrackedDef(typeof(DamageTracker), TrackedDef.totalCritTooltip)); dictionary.Add(Items.CritDamage, TrackedDef.Damage); dictionary.Add(Items.DeathMark, TrackedDef.Damage); dictionary.Add(Items.CritGlassesVoid, TrackedDef.DamageChance); dictionary.Add(Items.ExecuteLowHealthElite, TrackedDef.Damage); dictionary.Add(Items.OutOfCombatArmor, TrackedDef.ArmorCount); dictionary.Add(Items.SprintArmor, TrackedDef.Armor); dictionary.Add(Items.ArmorPlate, TrackedDef.Armor); dictionary.Add(Items.ParentEgg, TrackedDef.Heal); dictionary.Add(Items.GoldOnHit, TrackedDef.Gold); dictionary.Add(Items.GoldOnHurt, TrackedDef.Gold); dictionary.Add(Items.Thorns, TrackedDef.Damage); dictionary.Add(Items.Seed, TrackedDef.Heal); dictionary.Add(Items.BleedOnHit, TrackedDef.DamageChance); dictionary.Add(Items.BleedOnHitVoid, TrackedDef.DamageChance); dictionary.Add(Items.SlowOnHitVoid, TrackedDef.Chance); dictionary.Add(Items.Missile, TrackedDef.DamageChance); dictionary.Add(Items.MissileVoid, TrackedDef.DamageChance); dictionary.Add(Items.ChainLightning, TrackedDef.DamageChance); dictionary.Add(Items.ChainLightningVoid, TrackedDef.DamageChance); dictionary.Add(Items.BounceNearby, TrackedDef.DamageChance); dictionary.Add(Items.StickyBomb, TrackedDef.DamageChance); dictionary.Add(Items.IceRing, TrackedDef.Damage); dictionary.Add(Items.FireRing, TrackedDef.Damage); dictionary.Add(Items.ElementalRingVoid, TrackedDef.Damage); dictionary.Add(Items.FireballsOnHit, TrackedDef.DamageChance); dictionary.Add(Items.LightningStrikeOnHit, TrackedDef.DamageChance); dictionary.Add(Items.HealOnCrit, TrackedDef.Heal); dictionary.Add(Items.Behemoth, TrackedDef.Damage); dictionary.Add(Items.IgniteOnKill, TrackedDef.DamageChance); dictionary.Add(Items.ExplodeOnDeath, TrackedDef.DamageChance); dictionary.Add(Items.Dagger, TrackedDef.Damage); dictionary.Add(Items.Tooth, TrackedDef.Heal); dictionary.Add(Items.Bandolier, TrackedDef.Chance); dictionary.Add(Items.BonusGoldPackOnKill, TrackedDef.Gold); dictionary.Add(Items.BleedOnHitAndExplode, new TrackedDef(typeof(DamageChanceTracker), TrackedDef.hit_damageTooltip)); dictionary.Add(Items.BarrierOnKill, new TrackedDef(typeof(HealTracker), TrackedDef.barrierGainedTooltip)); dictionary.Add(Items.Plant, TrackedDef.Heal); dictionary.Add(Items.Mushroom, TrackedDef.Heal); dictionary.Add(Items.MushroomVoid, TrackedDef.Heal); dictionary.Add(Items.Medkit, TrackedDef.Heal); dictionary.Add(Items.TPHealingNova, TrackedDef.Heal); dictionary.Add(Items.HealingPotionConsumed, TrackedDef.Heal); dictionary.Add(Items.BarrierOnOverHeal, new TrackedDef(typeof(HealTracker), TrackedDef.barrierGainedTooltip)); dictionary.Add(Items.ShockNearby, TrackedDef.DamagePortion); dictionary.Add(Items.PrimarySkillShuriken, new TrackedDef(typeof(DamageChanceTracker), TrackedDef.hit_damageTooltip)); dictionary.Add(Items.StrengthenBurn, TrackedDef.Damage); dictionary.Add(Items.LaserTurbine, TrackedDef.Damage); dictionary.Add(Items.CaptainDefenseMatrix, TrackedDef.Count); dictionary.Add(Items.Icicle, TrackedDef.Damage); dictionary.Add(Items.NovaOnLowHealth, TrackedDef.DamagePortion); dictionary.Add(Items.ImmuneToDebuff, new TrackedDef(typeof(HealChanceTracker), TrackedDef.chance_barrierTooltip)); dictionary.Add(Items.NovaOnHeal, TrackedDef.Damage); dictionary.Add(Items.SprintWisp, TrackedDef.DamagePortion); dictionary.Add(Items.RandomlyLunar, TrackedDef.Chance); dictionary.Add(Items.Firework, TrackedDef.Damage); dictionary.Add(Items.Phasing, TrackedDef.Count); dictionary.Add(Items.FallBoots, TrackedDef.DamagePortion); dictionary.Add(Items.SiphonOnLowHealth, TrackedDef.Heal); dictionary.Add(Items.LunarSun, TrackedDef.DamagePortion); dictionary.Add(Items.Infusion, TrackedDef.Count); dictionary.Add(Items.HeadHunter, TrackedDef.Damage); dictionary.Add(Items.RoboBallBuddy, TrackedDef.Damage); dictionary.Add(Items.VoidMegaCrabItem, TrackedDef.Damage); dictionary.Add(Items.BeetleGland, TrackedDef.Damage); dictionary.Add(Items.DroneWeapons, TrackedDef.Damage); dictionary.Add(Items.GhostOnKill, TrackedDef.Damage); dictionary.Add(Items.MinorConstructOnKill, TrackedDef.Damage); dictionary.Add(Items.Squid, TrackedDef.Damage); dictionary.Add(Items.TitanGoldDuringTP, TrackedDef.Damage); dictionary.Add(Items.ExtraShrineItem, TrackedDef.Chance); dictionary.Add(Items.IncreasePrimaryDamage, TrackedDef.Damage); dictionary.Add(Items.MeteorAttackOnHighDamage, TrackedDef.DamageChance); dictionary.Add(Items.KnockBackHitEnemies, TrackedDef.Damage); dictionary.Add(Items.StunAndPierce, TrackedDef.DamageChance); dictionary.Add(Items.LowerPricedChests, TrackedDef.Count); dictionary.Add(Items.LowerPricedChestsConsumed, TrackedDef.Count); dictionary.Add(Items.ResetChests, TrackedDef.Chance); dictionary.Add(Items.GoldOnStageStart, TrackedDef.Damage); dictionary.Add(Items.TeleportOnLowHealth, TrackedDef.Damage); dictionary.Add(Items.TriggerEnemyDebuffs, TrackedDef.Damage); dictionary.Add(Items.WardOnLevel, TrackedDef.StackCombat); dictionary.Add(Items.WarCryOnMultiKill, TrackedDef.StackCombat); dictionary.Add(Items.EnergizedOnEquipmentUse, TrackedDef.StackCombat); dictionary.Add(Items.KillEliteFrenzy, TrackedDef.StackCombat); dictionary.Add(Items.MoveSpeedOnKill, TrackedDef.StackCombat); dictionary.Add(Items.SpeedBoostPickup, TrackedDef.StackCombat); dictionary.Add(Items.BoostAllStats, TrackedDef.StackCombat); dictionary.Add(Items.SprintBonus, TrackedDef.Stack); dictionary.Add(Items.SprintOutOfCombat, TrackedDef.Stack); dictionary.Add(Items.ArmorReductionOnHit, TrackedDef.StackHit); dictionary.Add(Items.PermanentDebuffOnHit, TrackedDef.StackHit); dictionary.Add(Items.RandomDamageZone, TrackedDef.StackHit); dictionary.Add(Items.IncreaseDamageOnMultiKill, TrackedDef.StackHit); dictionary.Add(Items.LowerHealthHigherDamage, new TrackedDef(typeof(ChanceTracker), TrackedDef.stackHitSkillTooltip)); dictionary.Add(Equipment.Saw, TrackedDef.DamagePortion); dictionary.Add(Equipment.GoldGat, TrackedDef.Damage); dictionary.Add(Equipment.BFG, TrackedDef.Damage); dictionary.Add(Equipment.PassiveHealing, TrackedDef.Heal); dictionary.Add(Equipment.CommandMissile, TrackedDef.Damage); dictionary.Add(Equipment.Fruit, TrackedDef.Heal); dictionary.Add(Equipment.DroneBackup, TrackedDef.Damage); dictionary.Add(Equipment.Lightning, TrackedDef.Damage); dictionary.Add(Equipment.Recycle, new TrackedDef(typeof(CountTracker), TrackedDef.recycledTooltip)); dictionary.Add(Equipment.LifestealOnHit, TrackedDef.Heal); dictionary.Add(Equipment.Molotov, TrackedDef.Damage); dictionary.Add(Equipment.VendingMachine, TrackedDef.Heal); dictionary.Add(Equipment.GummyClone, TrackedDef.Damage); dictionary.Add(Equipment.MultiShopCard, TrackedDef.Gold); dictionary.Add(Equipment.GainArmor, TrackedDef.Armor); dictionary.Add(Equipment.Meteor, TrackedDef.Damage); dictionary.Add(Equipment.BurnNearby, TrackedDef.Damage); dictionary.Add(Equipment.AffixRed, TrackedDef.Damage); dictionary.Add(Equipment.AffixBlue, TrackedDef.Damage); dictionary.Add(Equipment.AffixWhite, TrackedDef.Damage); dictionary.Add(Equipment.EliteAurelioniteEquipment, TrackedDef.Damage); dictionary.Add(Equipment.EliteBeadEquipment, TrackedDef.Damage); ModifyPrefabs(); crocoDiseaseProjectileIndex = ProjectileCatalog.FindProjectileIndex("CrocoDiseaseProjectile"); falseSonCharacterBodyIndex = BodyCatalog.FindBodyIndex("FalseSonBody"); } private static void ModifyPrefabs() { AddProcComponent("RoR2/Base/StickyBomb/StickyBomb.prefab", Items.StickyBomb); AddProcComponent("RoR2/Base/ElementalRings/FireTornado.prefab", Items.FireRing); AddProcComponent("RoR2/DLC1/ElementalRingVoid/ElementalRingVoidBlackHole.prefab", Items.ElementalRingVoid); AddProcComponent("RoR2/Base/FireballsOnHit/FireMeatBall.prefab", Items.FireballsOnHit); AddProcComponent("RoR2/DLC1/PrimarySkillShuriken/ShurikenProjectile.prefab", Items.PrimarySkillShuriken); AddProcComponent("RoR2/Base/LaserTurbine/LaserTurbineController.prefab", Items.LaserTurbine); AddProcComponent("RoR2/Base/LaserTurbine/LaserTurbineBomb.prefab", Items.LaserTurbine); AddProcComponent("RoR2/Base/Icicle/IcicleAura.prefab", Items.Icicle); AddProcComponent("RoR2/Base/NovaOnLowHealth/VagrantNovaItemBodyAttachment.prefab", Items.NovaOnLowHealth); AddProcComponent("RoR2/Base/Firework/FireworkProjectile.prefab", Items.Firework); AddProcComponent("RoR2/DLC1/LunarSun/LunarSunProjectile.prefab", Items.LunarSun); AddProcComponent("RoR2/Base/Dagger/DaggerProjectile.prefab", Items.Dagger); AddProcComponent("RoR2/Base/BleedOnHitAndExplode/BleedOnHitAndExplodeDelay.prefab", Items.BleedOnHitAndExplode); AddProcComponent("RoR2/DLC2/Items/StunAndPierce/StunAndPierceBoomerang.prefab", Items.StunAndPierce); AddProcComponent("RoR2/DLC2/Items/GoldOnStageStart/BossMissileProjectile.prefab", Items.GoldOnStageStart); AddProcComponent("RoR2/Base/BonusGoldPackOnKill/BonusMoneyPack.prefab", Items.BonusGoldPackOnKill); AddProcComponent("RoR2/Base/Mushroom/MushroomWard.prefab", Items.Mushroom); AddProcComponent("RoR2/Base/Plant/DeskplantWard.prefab", Items.Plant); AddMinionComponent("RoR2/Base/RoboBallBuddy/RoboBallGreenBuddyBody.prefab", Items.RoboBallBuddy); AddMinionComponent("RoR2/Base/RoboBallBuddy/RoboBallRedBuddyBody.prefab", Items.RoboBallBuddy); AddMinionComponent("RoR2/DLC1/VoidJailer/VoidJailerAllyBody.prefab", Items.VoidMegaCrabItem); AddMinionComponent("RoR2/Base/Nullifier/NullifierAllyBody.prefab", Items.VoidMegaCrabItem); AddMinionComponent("RoR2/DLC1/VoidMegaCrab/VoidMegaCrabAllyBody.prefab", Items.VoidMegaCrabItem); AddMinionComponent("RoR2/Base/BeetleGland/BeetleGuardAllyBody.prefab", Items.BeetleGland); AddMinionComponent("RoR2/Base/Squid/SquidTurretBody.prefab", Items.Squid); AddMinionComponent("RoR2/DLC1/MajorAndMinorConstruct/MinorConstructOnKillBody.prefab", Items.MinorConstructOnKill); AddMinionComponent("RoR2/Base/Titan/TitanGoldBody.prefab", Items.TitanGoldDuringTP); AddMinionComponent("RoR2/Base/Drones/BackupDroneBody.prefab", Equipment.DroneBackup); Utilities.AddressableAddComp<ProjectileBehaviour>("RoR2/Base/Nullifier/NullifierDeathBombProjectile.prefab", (Action<ProjectileBehaviour>)delegate(ProjectileBehaviour a) { a.projectile = ProjectileBehaviour.Projectile.ZoeaDeath; }); Utilities.AddressableAddComp<ProjectileBehaviour>("RoR2/DLC1/VoidJailer/VoidJailerDeathBombProjectile.prefab", (Action<ProjectileBehaviour>)delegate(ProjectileBehaviour a) { a.projectile = ProjectileBehaviour.Projectile.ZoeaDeath; }); Utilities.AddressableAddComp<ProjectileBehaviour>("RoR2/DLC1/VoidMegaCrab/VoidMegaCrabDeathBombProjectile.prefab", (Action<ProjectileBehaviour>)delegate(ProjectileBehaviour a) { a.projectile = ProjectileBehaviour.Projectile.ZoeaDeathChilder; }); Utilities.AddressableAddComp<ProjectileBehaviour>("RoR2/DLC1/VoidMegaCrab/VoidMegaCrabDeathBombletsProjectile.prefab", (Action<ProjectileBehaviour>)delegate(ProjectileBehaviour a) { a.projectile = ProjectileBehaviour.Projectile.ZoeaDeath; }); AddProcComponent("RoR2/Base/Saw/Sawmerang.prefab", Equipment.Saw); AddProcComponent("RoR2/Base/GoldGat/GoldGatController.prefab", Equipment.GoldGat); AddProcComponent("RoR2/Base/BFG/BeamSphere.prefab", Equipment.BFG); AddProcComponent("RoR2/Base/Meteor/MeteorStorm.prefab", Equipment.Meteor); AddProcComponent("RoR2/DLC1/Molotov/MolotovClusterProjectile.prefab", Equipment.Molotov); AddProcComponent("RoR2/DLC1/Molotov/MolotovSingleProjectile.prefab", Equipment.Molotov); AddProcComponent("RoR2/DLC1/Molotov/MolotovProjectileDotZone.prefab", Equipment.Molotov); AddProcComponent("RoR2/Base/Mage/MageFireboltBasic.prefab", (SkillSlot)0); AddProcComponent("RoR2/Base/Mage/MageLightningboltBasic.prefab", (SkillSlot)0); AddProcComponent("RoR2/Base/Mage/MageIceBombProjectile.prefab", (SkillSlot)1); AddProcComponent("RoR2/Base/Mage/MageLightningBombProjectile.prefab", (SkillSlot)1); AddProcComponent("RoR2/Base/Mage/MageIcewallPillarProjectile.prefab", (SkillSlot)2); AddProcComponent("RoR2/Base/Merc/EvisProjectile.prefab", (SkillSlot)3); AddProcComponent("RoR2/Base/Merc/EvisOverlapProjectile.prefab", (SkillSlot)3); AddProcComponent("RoR2/Base/Commando/FMJRamping.prefab", (SkillSlot)1); AddProcComponent("RoR2/Base/Commando/CommandoGrenadeProjectile.prefab", (SkillSlot)3); AddProcComponent("RoR2/Base/Captain/CaptainAirstrikeProjectile1.prefab", (SkillSlot)2); AddProcComponent("RoR2/Base/Captain/CaptainAirstrikeAltProjectile.prefab", (SkillSlot)2); AddProcComponent("RoR2/Base/Captain/CaptainSupplyDrop, Base.prefab", (SkillSlot)3); AddProcComponent("RoR2/Base/Captain/CaptainSupplyDrop, EquipmentRestock.prefab", (SkillSlot)3); AddProcComponent("RoR2/Base/Captain/CaptainSupplyDrop, Hacking.prefab", (SkillSlot)3); AddProcComponent("RoR2/Base/Captain/CaptainSupplyDrop, Healing.prefab", (SkillSlot)3); AddProcComponent("RoR2/Base/Captain/CaptainSupplyDrop, Shocking.prefab", (SkillSlot)3); AddProcComponent("RoR2/Base/Captain/CaptainTazer.prefab", (SkillSlot)1); AddProcComponent("RoR2/Base/Huntress/HuntressArrowRain.prefab", (SkillSlot)3); AddProcComponent("RoR2/Base/Loader/LoaderYankHook.prefab", (SkillSlot)1); AddProcComponent("RoR2/Base/Loader/LoaderZapCone.prefab", (SkillSlot)2); AddProcComponent("RoR2/Base/Loader/LoaderPylon.prefab", (SkillSlot)3); AddProcComponent("RoR2/Base/Engi/EngiGrenadeProjectile.prefab", (SkillSlot)0); AddProcComponent("RoR2/Base/Engi/EngiHarpoon.prefab", (SkillSlot)2); AddMinionComponent("RoR2/Base/Engi/EngiTurretBody.prefab", (SkillSlot)3); AddMinionComponent("RoR2/Base/Engi/EngiWalkerTurretBody.prefab", (SkillSlot)3); AddProcComponent("RoR2/Base/Croco/CrocoSpit.prefab", (SkillSlot)1); AddProcComponent("RoR2/Base/Croco/CrocoLeapAcid.prefab", (SkillSlot)2); AddProcComponent("RoR2/Base/Croco/CrocoDiseaseProjectile.prefab", (SkillSlot)3); AddProcComponent("RoR2/Base/Toolbot/CryoCanisterProjectile.prefab", (SkillSlot)1); AddProcComponent("RoR2/Base/Toolbot/CryoCanisterBombletsProjectile.prefab", (SkillSlot)1); AddProcComponent("RoR2/Base/Bandit2/Bandit2ShivProjectile.prefab", (SkillSlot)1); AddProcComponent("RoR2/DLC1/Railgunner/RailgunnerPistolProjectile.prefab", (SkillSlot)0); AddProcComponent("RoR2/Base/Treebot/SyringeProjectile.prefab", (SkillSlot)0); AddProcComponent("RoR2/Base/Treebot/SyringeProjectileHealing.prefab", (SkillSlot)0); AddProcComponent("RoR2/Base/Treebot/TreebotMortar2.prefab", (SkillSlot)1); AddProcComponent("RoR2/Base/Treebot/TreebotMortarRain.prefab", (SkillSlot)1); AddProcComponent("RoR2/Base/Treebot/TreebotFlowerSeed.prefab", (SkillSlot)3); AddProcComponent("RoR2/Base/Treebot/TreebotFruitSeedProjectile.prefab", (SkillSlot)3); Utilities.DoAddressable<GameObject>("RoR2/Base/Treebot/TreebotFruitPack.prefab", (Action<GameObject>)delegate(GameObject a) { ((Component)a.GetComponentInChildren<HealthPickup>()).gameObject.AddComponent<ProcComponent>().index = (SkillSlot)3; }); AddProcComponent("RoR2/DLC1/VoidSurvivor/VoidSurvivorMegaBlasterSmallProjectile.prefab", (SkillSlot)1); AddProcComponent("RoR2/DLC1/VoidSurvivor/VoidSurvivorMegaBlasterBigProjectile.prefab", (SkillSlot)1); AddProcComponent("RoR2/DLC1/VoidSurvivor/VoidSurvivorMegaBlasterBigProjectileCorrupted.prefab", (SkillSlot)1); AddProcComponent("RoR2/Base/LunarSkillReplacements/LunarNeedleProjectile.prefab", (SkillSlot)0); AddProcComponent("RoR2/Base/LunarSkillReplacements/LunarSecondaryProjectile.prefab", (SkillSlot)1); AddProcComponent("RoR2/DLC2/Seeker/SpiritPunchProjectile.prefab", (SkillSlot)0); AddProcComponent("RoR2/DLC2/Seeker/SpiritPunchFinisherProjectile.prefab", (SkillSlot)0); AddProcComponent("RoR2/DLC2/Seeker/SoulSpiralProjectile.prefab", (SkillSlot)1); AddProcComponent("RoR2/DLC2/Seeker/UnseenHandMovingProjectile.prefab", (SkillSlot)1); AddProcComponent("RoR2/DLC2/Seeker/SojournVehicle/SojournVehicle.prefab", (SkillSlot)2); AddProcComponent("RoR2/DLC2/FalseSon/LunarSpike.prefab", (SkillSlot)1); AddProcComponent("RoR2/DLC2/Chef/ChefCleaver.prefab", (SkillSlot)0); AddProcComponent("RoR2/DLC2/Chef/ChefDiceEnhanced.prefab", (SkillSlot)3); AddProcComponent("RoR2/DLC2/Chef/BoostedSearFireballProjectile.prefab", (SkillSlot)3); AddProcComponent("RoR2/DLC2/Chef/BoostedRolyPolyProjectile.prefab", (SkillSlot)3); AddProcComponent("RoR2/DLC2/Chef/ChefGlazeProjectile.prefab", (SkillSlot)3); Utilities.DoAddressable("RoR2/Base/Common/MissileProjectile.prefab", DoMissilePrefab); DoElites(); } private static void AddProcComponent(string addressable, Index index) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) AsyncOperationHandle<GameObject> val = Addressables.LoadAssetAsync<GameObject>((object)addressable); val.Completed += delegate(AsyncOperationHandle<GameObject> a) { a.Result.AddComponent<ProcComponent>().index = index; }; } private static void AddMinionComponent(string addressable, Index index) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) AsyncOperationHandle<GameObject> val = Addressables.LoadAssetAsync<GameObject>((object)addressable); val.Completed += delegate(AsyncOperationHandle<GameObject> a) { a.Result.AddComponent<MinionComponent>().index = index; }; } private static void DoMissilePrefab(GameObject missilePrefab) { missileLauncher = Utilities.CreatePrefab(missilePrefab, "DisposableMissileProjectile"); missileLauncher.AddComponent<ProcComponent>().index = Equipment.CommandMissile; CommonAssets.missilePrefab = Utilities.CreatePrefab(missilePrefab, "ATGMissileProjectile"); CommonAssets.missilePrefab.AddComponent<ProcComponent>().index = Items.Missile; } private static async void DoElites() { Task<GameObject>[] tasks = new Task<GameObject>[5] { Utilities.GetAddressableAsync("RoR2/Base/EliteLightning/LightningStake.prefab"), Utilities.GetAddressableAsync("RoR2/Base/Common/FireTrail.prefab"), Utilities.GetAddressableAsync("RoR2/DLC2/Elites/EliteAurelionite/AffixAurelionitePreStrikeProjectile.prefab"), Utilities.GetAddressableAsync("RoR2/DLC2/Elites/EliteAurelionite/AffixAurelioniteCenterProjectile.prefab"), Utilities.GetAddressableAsync("RoR2/DLC2/Elites/EliteBead/BeadProjectileTrackingBomb.prefab") }; await Task.WhenAll(tasks); DoDualElitePrefab(tasks[0].Result, Equipment.AffixBlue.equipmentIndex, out hhOverloading); DoDualElitePrefab(tasks[1].Result, Equipment.AffixRed.equipmentIndex, out hhFireTrail); DoDualElitePrefab(tasks[2].Result, Equipment.EliteAurelioniteEquipment.equipmentIndex, out hhGoldOuter); DoDualElitePrefab(tasks[3].Result, Equipment.EliteAurelioniteEquipment.equipmentIndex, out hhGoldInner); DoDualElitePrefab(tasks[4].Result, Equipment.EliteBeadEquipment.equipmentIndex, out hhBead); } private static void DoDualElitePrefab(GameObject prefab, EquipmentIndex eliteIndex, out GameObject hhPrefab) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) prefab.AddComponent<ProcComponent>().index = eliteIndex; hhPrefab = Utilities.CreatePrefab(prefab); hhPrefab.GetComponent<ProcComponent>().index = Items.HeadHunter; } private void CollectLanguageRootFolders(List<string> list) { list.Add(Path.Combine(Path.GetDirectoryName(((BaseUnityPlugin)this).Info.Location), "Language")); } } public class ProcChain { public readonly Index index; public readonly ProcChain parent; private static readonly ProcChain[] cachedSkillChains = new ProcChain[4] { new ProcChain((SkillSlot)0), new ProcChain((SkillSlot)1), new ProcChain((SkillSlot)2), new ProcChain((SkillSlot)3) }; public ProcChain(Index index, ProcChain parent = null) { this.index = index; this.parent = parent; } public static ProcChain TryGetCachedSkillChain(Index index) { int num = index.index; if (index.type == IndexType.SkillSlot && num >= 0 && num < cachedSkillChains.Length) { return cachedSkillChains[num]; } return new ProcChain(index); } public void AddDamageToChain(TrackedInventory trackedInventory, float damage) { for (ProcChain procChain = this; procChain != null; procChain = procChain.parent) { if (trackedInventory.inventory.HasIndex(procChain.index) && trackedInventory.GetTracker(procChain.index) is IDamageTracker damageTracker) { damageTracker.AddDamage(damage); } } } public override string ToString() { string text = index.ToString(); for (ProcChain procChain = parent; procChain != null; procChain = procChain.parent) { text = procChain.index.ToString() + " -> " + text; } return text; } } [Serializable] public struct Totals { public static float allDamageDealt; public float damageDealt; public float minionDamageDealt; public float damageTaken; public float healed; public uint goldEarned; } public class TrackedDef { private static readonly string tooltipPrefix = "ITEMSTATISTICS_TOOLTIPS_"; public static readonly string damageTooltip = tooltipPrefix + "DAMAGE"; public static readonly string chanceTooltip = tooltipPrefix + "CHANCE"; public static readonly string countTooltip = tooltipPrefix + "COUNT"; public static readonly string healTooltip = tooltipPrefix + "HEAL"; public static readonly string goldTooltip = tooltipPrefix + "GOLD"; public static readonly string reductionTooltip = tooltipPrefix + "REDUCTION"; public static readonly string portionTooltip = tooltipPrefix + "DAMAGEPORTION"; public static readonly string recycledTooltip = tooltipPrefix + "RECYCLED"; public static readonly string barrierGainedTooltip = tooltipPrefix + "BARRIERGAINED"; public static readonly string totalCritTooltip = tooltipPrefix + "CRITDAMAGE"; public static readonly string stackTooltip = tooltipPrefix + "STACK"; public static readonly string stackCombatTooltip = tooltipPrefix + "STACKCOMBAT"; public static readonly string stackHitTooltip = tooltipPrefix + "STACKHIT"; public static readonly string stackHitSkillTooltip = tooltipPrefix + "STACKHITSKILL"; public static readonly string globalPortionTooltip = tooltipPrefix + "GLOBALPORTION"; public static readonly string minionPortionTooltip = tooltipPrefix + "MINIONPORTION"; public static readonly string regenPortionTooltip = tooltipPrefix + "REGENPORTION"; public static readonly string barrierBlockedTooltip = tooltipPrefix + "BARRIERBLOCKED"; public static readonly string chance_barrierTooltip = tooltipPrefix + "CHANCE_BARRIER"; public static readonly string chance_healedTooltip = tooltipPrefix + "CHANCE_HEALED"; public static readonly string chance_damageTooltip = tooltipPrefix + "CHANCE_DAMAGE"; public static readonly string hit_damageTooltip = tooltipPrefix + "HIT_DAMAGE"; public static readonly string count_chanceTooltip = tooltipPrefix + "COUNT_CHANCE"; public static readonly string reduction_countTooltip = tooltipPrefix + "REDUCTION_COUNT"; public static readonly TrackedDef ArmorCount = new TrackedDef(typeof(ArmorCountTracker), reduction_countTooltip); public static readonly TrackedDef Armor = new TrackedDef(typeof(ArmorTracker), reductionTooltip); public static readonly TrackedDef Chance = new TrackedDef(typeof(ChanceTracker), count_chanceTooltip); public static readonly TrackedDef Count = new TrackedDef(typeof(CountTracker), countTooltip); public static readonly TrackedDef DamageChance = new TrackedDef(typeof(DamageChanceTracker), chance_damageTooltip); public static readonly TrackedDef DamagePortion = new TrackedDef(typeof(DamageTracker), portionTooltip); public static readonly TrackedDef Damage = new TrackedDef(typeof(DamageTracker), damageTooltip); public static readonly TrackedDef Gold = new TrackedDef(typeof(GoldTracker), goldTooltip); public static readonly TrackedDef Heal = new TrackedDef(typeof(HealTracker), healTooltip); public static readonly TrackedDef Skill = new TrackedDef(typeof(SkillTracker), null); public static readonly TrackedDef Stack = new TrackedDef(typeof(ChanceTracker), stackTooltip); public static readonly TrackedDef StackCombat = new TrackedDef(typeof(ChanceTracker), stackCombatTooltip); public static readonly TrackedDef StackHit = new TrackedDef(typeof(ChanceTracker), stackHitTooltip); private readonly Type trackerType; private readonly string tooltipToken; public TrackedDef(Type trackerType, string tooltipToken) { if (!typeof(ITracker).IsAssignableFrom(trackerType)) { throw new ArgumentException(trackerType?.ToString() + " is not a valid tracker type"); } this.trackerType = trackerType; this.tooltipToken = tooltipToken; } public string GetTooltip(ITracker tracker, in Totals totals) { string[] tooltipArgs = tracker.GetTooltipArgs(in totals); if (tooltipArgs == null) { return ""; } if (tooltipToken == null) { return string.Concat(tooltipArgs); } string text = tooltipToken; object[] array = tooltipArgs; return Language.GetStringFormatted(text, array); } internal ITracker CreateTracker() { return (ITracker)Activator.CreateInstance(trackerType); } } } namespace ItemStatistics.Trackers { public class ArmorCountTracker : ITracker, IReductionTracker, IChanceTracker { private float globalDamageTakenWhenSet; private float damageBlocked; private uint attempted; private uint succedded; public int itemCount { get; set; } public bool dirtyBit { get; set; } public void Attempted() { log.warning("Called Attempted on ArmorChanceTracker"); } public void Succedded() { succedded++; dirtyBit = true; } public void AddBlockedDamage(float blocked) { damageBlocked += blocked; dirtyBit = true; } string[] ITracker.GetTooltipArgs(in Totals totals) { return new string[2] { TrackerStatics.ReductionToString(damageBlocked, totals.damageTaken - globalDamageTakenWhenSet), succedded.ToString() }; } void ITracker.Reset(in Totals totals) { attempted = 0u; succedded = 0u; damageBlocked = 0f; globalDamageTakenWhenSet = totals.damageTaken; } void ITracker.Serialize(SerializationBuffer data) { data.Add(attempted); data.Add(succedded); data.Add(damageBlocked); } void ITracker.Deserialize(SerializationBuffer data) { attempted = data.nextInt; succedded = data.nextInt; damageBlocked = data.nextFloat; } } public class ArmorTracker : ITracker, IReductionTracker { private float globalDamageTakenWhenSet; private float damageBlocked; public int itemCount { get; set; } public bool dirtyBit { get; set; } public void AddBlockedDamage(float blocked) { damageBlocked += blocked; dirtyBit = true; } string[] ITracker.GetTooltipArgs(in Totals totals) { return new string[2] { TrackerStatics.ReductionToString(damageBlocked, totals.damageTaken - globalDamageTakenWhenSet), TrackerStatics.PortionToString(damageBlocked, totals.damageTaken - globalDamageTakenWhenSet) }; } void ITracker.Reset(in Totals totals) { damageBlocked = 0f; globalDamageTakenWhenSet = totals.damageTaken; } void ITracker.Serialize(SerializationBuffer data) { data.Add(damageBlocked); } void ITracker.Deserialize(SerializationBuffer data) { damageBlocked = data.nextFloat; } } public class ChanceTracker : ITracker, IChanceBatchTracker, IChanceTracker { private uint attempted; private uint succedded; public int itemCount { get; set; } public bool dirtyBit { get; set; } public void Attempted() { attempted++; dirtyBit = true; } public void Succedded() { succedded++; dirtyBit = true; } public void Succedded(uint count) { succedded += count; dirtyBit = true; } string[] ITracker.GetTooltipArgs(in Totals totals) { return new string[3] { succedded.ToString("n0"), TrackerStatics.ChanceToString(attempted, succedded), TrackerStatics.RateToString(attempted, succedded) }; } void ITracker.Reset(in Totals totals) { attempted = 0u; succedded = 0u; } void ITracker.Serialize(SerializationBuffer data) { data.Add(attempted); data.Add(succedded); } void ITracker.Deserialize(SerializationBuffer data) { attempted = data.nextInt; succedded = data.nextInt; } } public class CountTracker : ITracker, IChanceBatchTracker, IChanceTracker { private uint succedded; public int itemCount { get; set; } public bool dirtyBit { get; set; } public void Attempted() { log.warning("Called Attempted on CountTracker"); } public void Succedded() { succedded++; dirtyBit = true; } public void Succedded(uint count) { succedded += count; dirtyBit = true; } string[] ITracker.GetTooltipArgs(in Totals totals) { return new string[1] { succedded.ToString("n0") }; } void ITracker.Reset(in Totals totals) { succedded = 0u; } void ITracker.Serialize(SerializationBuffer data) { data.Add(succedded); } void ITracker.Deserialize(SerializationBuffer data) { succedded = data.nextInt; } } public class DamageChanceTracker : ITracker, IChanceTracker, IDamageTracker { private uint attempted; private uint succedded; private float globalDamageWhenSet; private float itemDamage; public int itemCount { get; set; } public bool dirtyBit { get; set; } public void Attempted() { attempted++; dirtyBit = true; } public void Succedded() { succedded++; dirtyBit = true; } public void AddDamage(float damage) { itemDamage += damage; dirtyBit = true; } string[] ITracker.GetTooltipArgs(in Totals totals) { return new string[2] { TrackerStatics.ChanceToString(attempted, succedded), TrackerStatics.IncreaseToString(itemDamage, totals.damageDealt - globalDamageWhenSet) }; } void ITracker.Reset(in Totals totals) { attempted = 0u; succedded = 0u; itemDamage = 0f; globalDamageWhenSet = totals.damageDealt; } void ITracker.Serialize(SerializationBuffer data) { data.Add(attempted); data.Add(succedded); data.Add(itemDamage); } void ITracker.Deserialize(SerializationBuffer data) { attempted = data.nextInt; succedded = data.nextInt; itemDamage = data.nextFloat; } } public class DamageTracker : ITracker, IDamageTracker { internal float globalDamageWhenSet; internal float itemDamage; public int itemCount { get; set; } public bool dirtyBit { get; set; } public void AddDamage(float damage) { itemDamage += damage; dirtyBit = true; } string[] ITracker.GetTooltipArgs(in Totals totals) { return new string[2] { TrackerStatics.IncreaseToString(itemDamage, totals.damageDealt - globalDamageWhenSet), TrackerStatics.PortionToString(itemDamage, totals.damageDealt - globalDamageWhenSet) }; } public virtual void Reset(in Totals totals) { itemDamage = 0f; globalDamageWhenSet = totals.damageDealt; } public virtual void Serialize(SerializationBuffer data) { data.Add(itemDamage); } public virtual void Deserialize(SerializationBuffer data) { itemDamage = data.nextFloat; } } public class GoldTracker : ITracker, IGoldTracker { private float globalEarnedWhenSet; private float itemEarned; public int itemCount { get; set; } public bool dirtyBit { get; set; } public void AddGold(float gold) { itemEarned += gold; dirtyBit = true; } string[] ITracker.GetTooltipArgs(in Totals totals) { return new string[1] { TrackerStatics.IncreaseToString(itemEarned, (float)totals.goldEarned - globalEarnedWhenSet) }; } void ITracker.Reset(in Totals totals) { itemEarned = 0f; globalEarnedWhenSet = totals.goldEarned; } void ITracker.Serialize(SerializationBuffer data) { data.Add(itemEarned); } void ITracker.Deserialize(SerializationBuffer data) { itemEarned = data.nextFloat; } } public class HealChanceTracker : ITracker, IChanceTracker, IHealTracker { private uint attempted; private uint succedded; private float itemHealed; private float globalHealedWhenSet; public int itemCount { get; set; } public bool dirtyBit { get; set; } public void Attempted() { attempted++; dirtyBit = true; } public void Succedded() { succedded++; dirtyBit = true; } public void AddHealing(float heal) { itemHealed += heal; dirtyBit = true; } string[] ITracker.GetTooltipArgs(in Totals totals) { return new string[3] { TrackerStatics.ChanceToString(attempted, succedded), TrackerStatics.PortionToString(itemHealed, totals.healed - globalHealedWhenSet), itemHealed.ToString("n0") }; } void ITracker.Reset(in Totals totals) { attempted = 0u; succedded = 0u; itemHealed = 0f; globalHealedWhenSet = totals.healed; } void ITracker.Serialize(SerializationBuffer data) { data.Add(attempted); data.Add(succedded); data.Add(itemHealed); } void ITracker.Deserialize(SerializationBuffer data) { attempted = data.nextInt; succedded = data.nextInt; itemHealed = data.nextFloat; } } public class HealTracker : ITracker, IHealTracker { private float itemHealed; private float globalHealedWhenSet; public int itemCount { get; set; } public bool dirtyBit { get; set; } public void AddHealing(float heal) { itemHealed += heal; dirtyBit = true; } string[] ITracker.GetTooltipArgs(in Totals totals) { return new string[2] { TrackerStatics.PortionToString(itemHealed, totals.healed - globalHealedWhenSet), itemHealed.ToString("n0") }; } void ITracker.Reset(in Totals totals) { itemHealed = 0f; globalHealedWhenSet = totals.healed; } void ITracker.Serialize(SerializationBuffer data) { data.Add(itemHealed); } void ITracker.Deserialize(SerializationBuffer data) { itemHealed = data.nextFloat; } } public interface IChanceTracker { void Attempted(); void Succedded(); } public interface IChanceBatchTracker : IChanceTracker { void Succedded(uint count); } public interface IDamageTracker { void AddDamage(float damage); } public interface IHealTracker { void AddHealing(float heal); } public interface IReductionTracker { void AddBlockedDamage(float blocked); } public interface IGoldTracker { void AddGold(float gold); } public interface ITracker { int itemCount { get; set; } bool dirtyBit { get; set; } string[] GetTooltipArgs(in Totals totals); void Reset(in Totals totals); void Serialize(SerializationBuffer data); void Deserialize(SerializationBuffer data); } public class SkillTracker : ITracker, IDamageTracker, IHealTracker { private float itemDamage; private float itemHealed; private float globalDamageWhenSet; private float globalHealedWhenSet; public int itemCount { get; set; } public bool dirtyBit { get; set; } public void AddDamage(float damage) { itemDamage += damage; dirtyBit = true; } public void AddHealing(float heal) { itemHealed += heal; dirtyBit = true; } string[] ITracker.GetTooltipArgs(in Totals totals) { bool flag = itemDamage != 0f; bool flag2 = itemHealed != 0f; string text = null; if (flag) { text = Language.GetStringFormatted(TrackedDef.portionTooltip, new object[2] { null, TrackerStatics.PortionToString(itemDamage, totals.damageDealt - globalDamageWhenSet) }); } if (flag2) { if (flag) { text += "\n"; } text += Language.GetStringFormatted(TrackedDef.healTooltip, new object[2] { TrackerStatics.PortionToString(itemHealed, totals.healed - globalHealedWhenSet), null }); } if (text != null) { return new string[1] { text }; } return null; } void ITracker.Reset(in Totals totals) { itemDamage = 0f; itemHealed = 0f; globalDamageWhenSet = totals.damageDealt; globalHealedWhenSet = totals.healed; } void ITracker.Serialize(SerializationBuffer data) { data.Add(itemDamage); data.Add(itemHealed); } void ITracker.Deserialize(SerializationBuffer data) { itemDamage = data.nextFloat; itemHealed = data.nextFloat; } } public static class TrackerStatics { public static string IncreaseToString(float localNum, float totalNum) { if (totalNum == 0f) { return "NaN"; } if (localNum >= 0.999999f * totalNum) { return "Max"; } if (localNum < 0f) { return (100f * localNum / totalNum).ToString("f0") + "%"; } return (100f / (1f - localNum / totalNum) - 100f).ToString("f0") + "%"; } public static string ChanceToString(uint attempted, uint succedded) { if (attempted == 0) { return "NaN"; } float num = 100f * (float)succedded / (float)attempted; return num.ToString((num < 10f) ? "f1" : "f0") + "%"; } public static string ReductionToString(float localNum, float totalNum) { if (totalNum == 0f) { if (!(localNum > 0f)) { return "NaN"; } return "100%"; } if (localNum <= -0.999999f * totalNum) { return "Min"; } return (100f - 100f / (1f + localNum / totalNum)).ToString("f0") + "%"; } public static string PortionToString(float localNum, float totalNum) { if (totalNum == 0f) { return "NaN"; } return (100f * localNum / totalNum).ToString("f0") + "%"; } public static string RateToString(uint attempted, uint succedded) { if (attempted == 0) { return "NaN"; } return ((float)succedded / (float)attempted).ToString("f1"); } internal static void LogInvalid(Index index, ITracker tracker, string requiredTracker, [CallerMemberName] string caller = "") { log.error($"Invalid call '{caller}' on {index} ({tracker}). Has to be a {requiredTracker} tracker"); } } public class WatchTracker : DamageTracker { private bool globalset; public void AddBrokenDamage(DamageTracker notBrokenWatchTracker) { AddDamage(notBrokenWatchTracker.itemDamage); if (!globalset) { globalDamageWhenSet = notBrokenWatchTracker.globalDamageWhenSet; globalset = true; } } public override void Reset(in Totals totals) { base.Reset(in totals); globalset = false; } public override void Serialize(SerializationBuffer data) { base.Serialize(data); data.Add(globalDamageWhenSet); } public override void Deserialize(SerializationBuffer data) { base.Deserialize(data); globalDamageWhenSet = data.nextFloat; } } } namespace ItemStatistics.Networking { public class BlastMessage { private Index inflictorIndex; internal BlastAttackDamageInfo blastAttack; public BlastMessage() { } public BlastMessage(in BlastAttackDamageInfo blastAttack, Index inflictorIndex) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) this.inflictorIndex = inflictorIndex; this.blastAttack = blastAttack; } internal static void Serialize(NetworkWriter writer, BlastMessage value) { Index.Serialize(writer, value.inflictorIndex); ((BlastAttackDamageInfo)(ref value.blastAttack)).Write(writer); } internal static BlastMessage Deserialize(NetworkReader reader) { BlastMessage blastMessage = new BlastMessage(); blastMessage.inflictorIndex = Index.Deserialize(reader); ((BlastAttackDamageInfo)(ref blastMessage.blastAttack)).Read(reader); blastMessage.blastAttack.inflictor = ProcComponent.CreateInflictor(blastMessage.inflictorIndex); return blastMessage; } } internal static class NetworkHooks { private delegate void BlastAttack_ClientReportDamage(in BlastAttackDamageInfo blastAttack); private static Index inflictorIndex; private static bool shouldClientSendMessage { get { if (TrackModdedUsers.isModdedServer) { return inflictorIndex.isNotNone; } return false; } } internal static void Apply() { //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Expected O, but got Unknown HookManager.Hook(MethodBase.GetMethodFromHandle((RuntimeMethodHandle)/*OpCode not supported: LdMemberToken*/), (Delegate)new <>A{00000018}<BlastAttack_ClientReportDamage, BlastAttackDamageInfo>(NetworkMessage_On_BlastAttack_ClientReportDamage)); HookManager.Hook(MethodBase.GetMethodFromHandle((RuntimeMethodHandle)/*OpCode not supported: LdMemberToken*/), new Manipulator(HeadStompers_IL_HeadstompersFall_DoStompExplosionAuthority)); } private static void NetworkMessage_On_BlastAttack_ClientReportDamage(BlastAttack_ClientReportDamage orig, in BlastAttackDamageInfo blastAttack) { if (!shouldClientSendMessage) { orig(in blastAttack); } else if (Object.op_Implicit((Object)(object)blastAttack.hitHealthComponent)) { TrackModdedUsers.localUser.CallCmdBlastAttack(new BlastMessage(in blastAttack, inflictorIndex)); } } private static void HeadStompers_IL_HeadstompersFall_DoStompExplosionAuthority(ILContext il) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Expected O, but got Unknown //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Unknown result type (might be due to invalid IL or missing references) ILCursor val = new ILCursor(il); if (val.TryGotoNext(new Func<Instruction, bool>[1] { (Instruction a) => ILPatternMatchingExt.MatchStfld<BlastAttack>(a, "inflictor") })) { val.Emit(OpCodes.Pop); val.Emit(OpCodes.Ldarg_0); val.EmitDelegate<Func<HeadstompersFall, GameObject>>((Func<HeadstompersFall, GameObject>)delegate { //IL_001d: Unknown result type (might be due to invalid IL or missing references) if (NetworkServer.active) { return ProcComponent.CreateInflictor(Items.FallBoots); } inflictorIndex = Items.FallBoots.itemIndex; return null; }); if (val.TryGotoNext((MoveType)2, new Func<Instruction, bool>[1] { (Instruction a) => ILPatternMatchingExt.MatchCallOrCallvirt(a, typeof(BlastAttack), "Fire") })) { val.Emit(OpCodes.Ldsflda, typeof(NetworkHooks).GetField("inflictorIndex", BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic)); val.Emit(OpCodes.Initobj, typeof(Index)); return; } } val.LogErrorCaller("Headstompers"); } } public class SerializationBuffer : IEnumerable<Index>, IEnumerable { [StructLayout(LayoutKind.Explicit)] private struct IntFloat { [FieldOffset(0)] private float floatValue; [FieldOffset(0)] private uint intValue; internal static float IntToFloat(uint value) { IntFloat intFloat = default(IntFloat); intFloat.intValue = value; return intFloat.floatValue; } internal static uint FloatToInt(float value) { IntFloat intFloat = default(IntFloat); intFloat.floatValue = value; return intFloat.intValue; } } private static readonly SerializationBuffer staticBuffer = new SerializationBuffer(4u, 4u); private Index[] indexes; private uint[] bits; private uint indexSize; private uint bitsSize; private uint bitPos; public uint nextInt => bits[bitPos++]; public float nextFloat => IntFloat.IntToFloat(nextInt); public bool hasSomething => indexSize != 0; public void Add(float num) { Add(IntFloat.FloatToInt(num)); } public void Add(uint num) { uint num2 = bitsSize + 1; if (num2 >= bits.Length) { int num3 = ((bits.Length == 0) ? 4 : (2 * bits.Length)); if (num3 < num2) { num3 = (int)num2; } Array.Resize(ref bits, num3); } bits[bitsSize] = num; bitsSize = num2; } internal void Add(Index index) { uint num = indexSize + 1; if (num >= indexes.Length) { int num2 = ((indexes.Length == 0) ? 4 : (2 * indexes.Length)); if (num2 < num) { num2 = (int)num; } Array.Resize(ref indexes, num2); } indexes[indexSize] = index; indexSize = num; } internal static void Serialize(NetworkWriter writer, SerializationBuffer value) { writer.WritePackedUInt32(value.indexSize); writer.WritePackedUInt32(value.bitsSize); for (uint num = 0u; num < value.indexSize; num++) { Index.Serialize(writer, value.indexes[num]); } for (uint num2 = 0u; num2 < value.bitsSize; num2++) { writer.WritePackedUInt32(value.bits[num2]); } } internal static SerializationBuffer Deserialize(NetworkReader reader) { SerializationBuffer serializationBuffer = staticBuffer; serializationBuffer.Clear(); uint num = reader.ReadPackedUInt32(); uint num2 = reader.ReadPackedUInt32(); for (uint num3 = 0u; num3 < num; num3++) { serializationBuffer.Add(Index.Deserialize(reader)); } for (uint num4 = 0u; num4 < num2; num4++) { serializationBuffer.Add(reader.ReadPackedUInt32()); } return serializationBuffer; } internal void Clear() { indexSize = 0u; bitsSize = 0u; bitPos = 0u; } internal static SerializationBuffer GetBuffer() { return staticBuffer; } public IEnumerator<Index> GetEnumerator() { int i = 0; while (i < indexSize) { yield return indexes[i]; int num = i + 1; i = num; } } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } private SerializationBuffer(uint initialIndexCapacity, uint initialBitsCapacity) { indexes = new Index[initialIndexCapacity]; bits = new uint[initialBitsCapacity]; } } } namespace ItemStatistics.Hooks { public static class DotTracking { internal static List<ProcChain> dotChainListParameter; private static ProcChain dotChainParameter; private static MethodInfo modifiedGetDotStackTotalDurationForIndex; internal static void Apply() { //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Expected O, but got Unknown //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Expected O, but got Unknown HookManager.Hook(MethodBase.GetMethodFromHandle((RuntimeMethodHandle)/*OpCode not supported: LdMemberToken*/), (Delegate)new Action<Action<DotController, DotStack>, DotController, DotStack>(AddTree_On_DotController_OnDotStackAddedServer)); HookManager.Hook(MethodBase.GetMethodFromHandle((RuntimeMethodHandle)/*OpCode not supported: LdMemberToken*/), new Manipulator(Passer_IL_DotController_EvaluateDotStacksForType)); HookManager.Hook(MethodBase.GetMethodFromHandle((RuntimeMethodHandle)/*OpCode not supported: LdMemberToken*/), new Manipulator(CollectProcChain_IL_DotController_AddPendingDamageEntry)); HookManager.Hook(MethodBase.GetMethodFromHandle((RuntimeMethodHandle)/*OpCode not supported: LdMemberToken*/), (Delegate)new Action<Action<DotStack>, DotStack>(On_DotStack_Reset)); HookManager.Hook(MethodBase.GetMethodFromHandle((RuntimeMethodHandle)/*OpCode not supported: LdMemberToken*/), (Delegate)new Action<Action<PendingDamage>, PendingDamage>(On_PendingDamage_Reset)); DoNoxious(); } private static void AddTree_On_DotController_OnDotStackAddedServer(Action<DotController, DotStack> orig, DotController self, DotStack dotStack) { orig(self, dotStack); if (CurrentContext.procChain != null) { dotStack.dotStackChain = CurrentContext.procChain; } } private static void Passer_IL_DotController_EvaluateDotStacksForType(ILContext il) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Expected O, but got Unknown //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: Unknown result type (might be due to invalid IL or missing references) //IL_011e: Unknown result type (might be due to invalid IL or missing references) //IL_012a: Unknown result type (might be due to invalid IL or missing references) //IL_014a: Unknown result type (might be due to invalid IL or missing references) //IL_019d: Unknown result type (might be due to invalid IL or missing references) //IL_01a9: Unknown result type (might be due to invalid IL or missing references) ILCursor val = new ILCursor(il); if (val.TryGotoNext(new Func<Instruction, bool>[1] { (Instruction a) => ILPatternMatchingExt.MatchLdfld<DotStack>(a, "timer") })) { val.Emit(OpCodes.Dup); val.Emit(OpCodes.Ldfld, typeof(DotStack).GetField("dotStackChain")); val.Emit(OpCodes.Stsfld, typeof(DotTracking).GetField("dotChainParameter", BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic)); if (val.TryGotoNext((MoveType)2, new Func<Instruction, bool>[1] { (Instruction a) => ILPatternMatchingExt.MatchCallOrCallvirt<DotController>(a, "AddPendingDamageEntry") })) { val.Emit(OpCodes.Ldnull); val.Emit(OpCodes.Stsfld, typeof(DotTracking).GetField("dotChainParameter", BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic)); if (val.TryGotoNext(new Func<Instruction, bool>[1] { (Instruction a) => ILPatternMatchingExt.MatchLdfld<PendingDamage>(a, "totalDamage") })) { val.Emit(OpCodes.Dup); val.Emit(OpCodes.Ldfld, typeof(PendingDamage).GetField("pendingDotChainList")); val.Emit(OpCodes.Stsfld, typeof(DotTracking).GetField("dotChainListParameter", BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic)); if (val.TryGotoNext((MoveType)2, new Func<Instruction, bool>[1] { (Instruction a) => ILPatternMatchingExt.MatchCallOrCallvirt<HealthComponent>(a, "TakeDamage") })) { val.Emit(OpCodes.Ldnull); val.Emit(OpCodes.Stsfld, typeof(DotTracking).GetField("dotChainListParameter", BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic)); return; } } } } val.LogErrorCaller(""); } private static void CollectProcChain_IL_DotController_AddPendingDamageEntry(ILContext il) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Expected O, but got Unknown //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_0091: 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_013a: Unknown result type (might be due to invalid IL or missing references) ILCursor val = new ILCursor(il); int iIndex = 1; ILCursor[] array = default(ILCursor[]); val.FindNext(ref array, new Func<Instruction, bool>[2] { (Instruction a) => ILPatternMatchingExt.MatchLdloc(a, ref iIndex), (Instruction a) => ILPatternMatchingExt.MatchLdcI4(a, 1) }); if (val.TryGotoNext(new Func<Instruction, bool>[1] { (Instruction a) => ILPatternMatchingExt.MatchStfld<PendingDamage>(a, "totalDamage") })) { val.Emit(OpCodes.Ldarg, 0); val.Emit(OpCodes.Ldloc, iIndex); val.Emit<List<PendingDamage>>(OpCodes.Callvirt, "get_Item"); val.EmitDelegate<Action<PendingDamage>>((Action<PendingDamage>)delegate(PendingDamage pending) { if (dotChainParameter != null) { pending.pendingDotChainList.Add(dotChainParameter); } }); } else { val.LogErrorCaller("1"); } MethodReference val2 = default(MethodReference); if (val.TryGotoNext((MoveType)2, new Func<Instruction, bool>[2] { (Instruction a) => ILPatternMatchingExt.MatchLdsfld<DotController>(a, "pendingDamagePool"), (Instruction a) => ILPatternMatchingExt.MatchCallOrCallvirt(a, ref val2) })) { val.Emit(OpCodes.Dup); val.EmitDelegate<Action<PendingDamage>>((Action<PendingDamage>)delegate(PendingDamage pending) { List<ProcChain> list = (pending.pendingDotChainList = CollectionPool<ProcChain, List<ProcChain>>.RentCollection()); if (dotChainParameter != null) { list.Add(dotChainParameter); } }); } else { val.LogErrorCaller("2"); } } private static void On_DotStack_Reset(Action<DotStack> orig, DotStack self) { orig(self); self.dotStackChain = null; } private static void On_PendingDamage_Reset(Action<PendingDamage> orig, PendingDamage self) { orig(self); List<ProcChain> pendingDotChainList = self.pendingDotChainList; if (pendingDotChainList != null) { CollectionPool<ProcChain, List<ProcChain>>.ReturnCollection(pendingDotChainList); } self.pendingDotChainList = null; } private static void DoNoxious() { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Expected O, but got Unknown //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Expected O, but got Unknown //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Expected O, but got Unknown //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Expected O, but got Unknown //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Expected O, but got Unknown //IL_007e: 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) //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: Unknown result type (might be due to invalid IL or missing references) //IL_00e5: Unknown result type (might be due to invalid IL or missing references) //IL_00f1: Unknown result type (might be due to invalid IL or missing references) //IL_00fe: Unknown result type (might be due to invalid IL or missing references) //IL_010f: Unknown result type (might be due to invalid IL or missing references) //IL_011b: Unknown result type (might be due to invalid IL or missing references) //IL_0149: Unknown result type (might be due to invalid IL or missing references) //IL_0153: Expected O, but got Unknown //IL_0164: Unknown result type (might be due to invalid IL or missing references) //IL_016e: Expected O, but got Unknown try { DynamicMethodDefinition val = new DynamicMethodDefinition((MethodBase)HookManager.GetMethod(typeof(DotController), "GetDotStackTotalDurationForIndex")); ((MethodReference)val.Definition).Parameters.Add(new ParameterDefinition("procChain", (ParameterAttributes)2, (TypeReference)new ByReferenceType(val.Module.ImportReference(typeof(ProcChain))))); typeof(DynamicMethodDefinition).GetProperty("OriginalMethod").SetValue(val, null); ILContext val2 = new ILContext(val.Definition); ILCursor val3 = new ILCursor(val2); val3.Emit(OpCodes.Ldarg_3); val3.Emit(OpCodes.Ldnull); val3.Emit(OpCodes.Stind_Ref); VariableDefinition val4 = val3.AddNewVariable<DotStack>(); val3.GotoNext(new Func<Instruction, bool>[1] { (Instruction a) => ILPatternMatchingExt.MatchLdfld<DotStack>(a, "totalDuration") }); val3.Emit(OpCodes.Stloc, val4); val3.Emit(OpCodes.Ldarg_3); val3.Emit(OpCodes.Ldloc, val4); val3.Emit<DotStack>(OpCodes.Ldfld, "dotStackChain"); val3.Emit(OpCodes.Stind_Ref); val3.Emit(OpCodes.Ldloc, val4); val2.Dispose(); modifiedGetDotStackTotalDurationForIndex = val.Generate(); HookManager.Hook(MethodBase.GetMethodFromHandle((RuntimeMethodHandle)/*OpCode not supported: LdMemberToken*/), new Manipulator(GetChain_IL_CharacterBody_TriggerEnemyDebuffs)); HookManager.Hook(MethodBase.GetMethodFromHandle((RuntimeMethodHandle)/*OpCode not supported: LdMemberToken*/), new Manipulator(ApplyChain_IL_VineOrb_OnArrival)); } catch (Exception ex) { log.error("Failed Noxious Thorn\n" + ex); } } private static void GetChain_IL_CharacterBody_TriggerEnemyDebuffs(ILContext il) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Expected O, but got Unknown //IL_0042: Unknown result type (might be due to invalid IL or missing