Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of ItemStatistics v1.2.12
plugins/ItemStatistics.dll
Decompiled 5 months ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Reflection.Emit; 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.Chef; using EntityStates.Drone.Command; using EntityStates.Drone.DroneCopycat; using EntityStates.DroneWeaponsChainGun; using EntityStates.FriendUnit; using EntityStates.GummyClone; using EntityStates.Headstompers; using EntityStates.Toolbot; using EntityStates.Treebot.TreebotFlower; using EntityStates.Treebot.Weapon; using EntityStates.VoidSurvivor.Weapon; using HG; using HG.GeneralSerializer; using HG.Reflection; using ItemStatistics; using ItemStatistics.Components; using ItemStatistics.Hooks; using ItemStatistics.Networking; using JetBrains.Annotations; using Mono.Cecil; using Mono.Cecil.Cil; 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.12.0")] [module: UnverifiableCode] namespace Dolso { internal static class log { private static readonly ManualLogSource logger = Logger.CreateLogSource(Assembly.GetExecutingAssembly().GetName().Name); [Conditional("DEBUG")] internal static void debug(object data) { logger.LogDebug(data); } 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)$"ILCursor failure, skipping: {data}\n{c}"); } internal static void LogErrorCaller(this ILCursor c, object data) { logger.LogError((object)$"ILCursor failed in {new StackFrame(1).GetMethod().Name}, skipping: {data}\n{c}"); } } internal static class HookManager { internal delegate bool ConfigEnabled<T>(T configValue); private class HookedConfig<T> { private readonly ConfigEnabled<T> enabled; private readonly IDetour detour; internal HookedConfig(ConfigEntry<T> configEntry, ConfigEnabled<T> enabled, IDetour detour) { this.enabled = enabled; this.detour = detour; if (configEntry != null) { configEntry.SettingChanged += ConfigChanged; ConfigChanged(configEntry, null); } else { detour.Apply(); } } private void ConfigChanged(object sender, EventArgs args) { if (enabled(((ConfigEntry<T>)sender).Value)) { if (!detour.IsApplied) { detour.Apply(); } } else if (detour.IsApplied) { detour.Undo(); } } } internal const BindingFlags allFlags = BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic; private static readonly ConfigEnabled<bool> boolConfigEnabled = BoolEnabled; private static ILHookConfig ilHookConfig = new ILHookConfig { ManualApply = true }; private static HookConfig onHookConfig = new HookConfig { ManualApply = true }; internal static void Hook(Type typeFrom, string fromMethod, Manipulator ilHook) { Hook(GetMethod(typeFrom, fromMethod), ilHook); } internal static void Hook(Delegate fromMethod, Manipulator ilHook) { Hook(fromMethod.Method, ilHook); } internal static void Hook(MethodBase fromMethod, Manipulator ilHook) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) try { new ILHook(fromMethod, ilHook, ref ilHookConfig).Apply(); } catch (Exception e) { e.LogHookError(fromMethod, ((Delegate)(object)ilHook).Method); } } internal static void Hook(Type typeFrom, string fromMethod, Delegate onHook) { Hook(GetMethod(typeFrom, fromMethod), onHook.Method, onHook.Target); } internal static void Hook(Delegate fromMethod, Delegate onHook) { Hook(fromMethod.Method, onHook.Method, onHook.Target); } internal static void Hook(MethodBase fromMethod, Delegate onHook) { Hook(fromMethod, onHook.Method, onHook.Target); } internal static void Hook(MethodBase fromMethod, MethodInfo onHook, object target = null) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) try { new Hook(fromMethod, onHook, target, ref onHookConfig).Apply(); } catch (Exception e) { e.LogHookError(fromMethod, onHook); } } internal static void HookConfig(this ConfigEntry<bool> configEntry, Type typeFrom, string fromMethod, Delegate hook) { configEntry.HookConfig(boolConfigEnabled, GetMethod(typeFrom, fromMethod), hook.Method, hook.Target); } internal static void HookConfig(this ConfigEntry<bool> configEntry, MethodBase fromMethod, Delegate hook) { configEntry.HookConfig(boolConfigEnabled, fromMethod, hook.Method, hook.Target); } internal static void HookConfig(this ConfigEntry<bool> configEntry, MethodBase fromMethod, MethodInfo hook) { configEntry.HookConfig(boolConfigEnabled, fromMethod, hook); } internal static void HookConfig<T>(this ConfigEntry<T> configEntry, ConfigEnabled<T> enabled, Type typeFrom, string fromMethod, Delegate hook) { configEntry.HookConfig(enabled, GetMethod(typeFrom, fromMethod), hook.Method, hook.Target); } internal static void HookConfig<T>(this ConfigEntry<T> configEntry, ConfigEnabled<T> enabled, MethodBase fromMethod, Delegate hook) { configEntry.HookConfig(enabled, fromMethod, hook.Method, hook.Target); } internal static void HookConfig<T>(this ConfigEntry<T> configEntry, ConfigEnabled<T> enabled, MethodBase fromMethod, MethodInfo hook, object target = null) { try { new HookedConfig<T>(configEntry, enabled, ManualDetour(fromMethod, hook, target)); } catch (Exception e) { e.LogHookError(fromMethod, hook); } } internal static IDetour ManualDetour(Type typeFrom, string fromMethod, Delegate hook) { return ManualDetour(GetMethod(typeFrom, fromMethod), hook.Method, hook.Target); } internal static IDetour ManualDetour(MethodBase fromMethod, Delegate hook) { return ManualDetour(fromMethod, hook.Method, hook.Target); } internal static IDetour ManualDetour(MethodBase fromMethod, MethodInfo hook, object target = null) { //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Expected O, but got Unknown //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Expected O, but got Unknown //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Expected O, but got Unknown try { ParameterInfo[] parameters = hook.GetParameters(); if (parameters.Length == 1 && parameters[0].ParameterType == typeof(ILContext)) { return (IDetour)new ILHook(fromMethod, (Manipulator)hook.CreateDelegate(typeof(Manipulator)), ref ilHookConfig); } return (IDetour)new Hook(fromMethod, hook, target, ref onHookConfig); } catch (Exception e) { e.LogHookError(fromMethod, hook); 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 a in typeFrom.GetMethods(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic) where a.Name == methodName select a).ToArray(); switch (array.Length) { case 1: return array[0]; case 0: log.error($"Failed to find method: {typeFrom}::{methodName}"); return null; default: { string text = $"{array.Length} ambiguous matches found for: {typeFrom}::{methodName}, may be incorrect"; MethodInfo[] array2 = array; for (int i = 0; i < array2.Length; i++) { text = text + "\n" + array2[i]; } log.warning(text); return array[0]; } } } 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_il = null, string[] before_on = null, string[] after_il = null, string[] after_on = null) { ilHookConfig.Before = before_il; onHookConfig.Before = before_on; ilHookConfig.After = after_il; onHookConfig.After = after_on; } internal static void LogHookError(this Exception e, MethodBase fromMethod, MethodInfo hook) { log.error((fromMethod == null) ? $"null from-method for hook: {hook.Name}\n{e}" : $"Failed to hook: {fromMethod.DeclaringType}::{fromMethod.Name} - {hook.Name}\n{e}"); } private static bool BoolEnabled(bool configValue) { return configValue; } } internal static class Utilities { internal struct AsyncHandle<T> : IDisposable { private AsyncOperationHandle<T> handle; public T result => handle.Result; public Task<T> task => handle.Task; internal AsyncHandle(AsyncOperationHandle<T> handle) { //IL_0001: 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) this.handle = handle; } public TaskAwaiter<T> GetAwaiter() { return handle.Task.GetAwaiter(); } public void Dispose() { handle.Release(); } public static implicit operator AsyncOperationHandle<T>(AsyncHandle<T> handle) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) return handle.handle; } } 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 AsyncHandle<T> GetAddressableAsync<T>(string addressable) where T : Object { //IL_0001: Unknown result type (might be due to invalid IL or missing references) return new AsyncHandle<T>(Addressables.LoadAssetAsync<T>((object)addressable)); } internal static AsyncHandle<GameObject> GetAddressableAsync(string addressable) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) return new AsyncHandle<GameObject>(Addressables.LoadAssetAsync<GameObject>((object)addressable)); } internal static void DoAddressable<T>(string addressable, Action<T> callback, bool release = false) where T : Object { //IL_0016: 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) AsyncOperationHandle<T> handle = Addressables.LoadAssetAsync<T>((object)addressable); handle.Completed += delegate(AsyncOperationHandle<T> a) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Invalid comparison between Unknown and I4 if ((int)a.Status == 1) { callback(a.Result); if (release) { handle.Release(); } } }; } internal static void DoAddressable(string addressable, Action<GameObject> callback, bool release = false) { //IL_0016: 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) AsyncOperationHandle<GameObject> handle = Addressables.LoadAssetAsync<GameObject>((object)addressable); handle.Completed += delegate(AsyncOperationHandle<GameObject> a) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Invalid comparison between Unknown and I4 if ((int)a.Status == 1) { callback(a.Result); if (release) { handle.Release(); } } }; } internal static void AddressableAddComp<TComp>(string addressable, Action<TComp> callback = null) where TComp : 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) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Invalid comparison between Unknown and I4 if ((int)a.Status == 1) { TComp obj = a.Result.AddComponent<TComp>(); callback?.Invoke(obj); } }; } 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) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Invalid comparison between Unknown and I4 if ((int)a.Status == 1 && !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 KeyboardShortcut key, bool onlyJustPressed) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_0005: 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) if (onlyJustPressed) { if (!Input.GetKeyDown(((KeyboardShortcut)(ref key)).MainKey)) { return false; } } else if (!Input.GetKey(((KeyboardShortcut)(ref key)).MainKey)) { return false; } foreach (KeyCode modifier in ((KeyboardShortcut)(ref key)).Modifiers) { if (!Input.GetKey(modifier)) { return false; } } return true; } } [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true)] [MeansImplicitUse] internal class HookAttribute : Attribute { private readonly Type typeFrom; private readonly string methodFrom; private readonly Type[] parameters; protected MethodInfo from { get { if ((object)typeFrom != null) { if (parameters != null) { return HookManager.GetMethod(typeFrom, methodFrom, parameters); } return HookManager.GetMethod(typeFrom, methodFrom); } return null; } } internal HookAttribute(Type typeFrom, string methodFrom) { this.typeFrom = typeFrom; this.methodFrom = methodFrom; } internal HookAttribute(Type typeFrom, string methodFrom, params Type[] parameters) { this.typeFrom = typeFrom; this.methodFrom = methodFrom; this.parameters = parameters; } internal HookAttribute() { } internal static void ScanAndApply() { ScanAndApply((from a in Assembly.GetExecutingAssembly().GetTypes() where a.GetCustomAttribute<HookAttribute>() != null select a).ToArray()); } internal static void ScanAndApply(params Type[] types) { for (int i = 0; i < types.Length; i++) { MethodInfo[] methods = types[i].GetMethods(BindingFlags.Static | BindingFlags.NonPublic); foreach (MethodInfo methodInfo in methods) { foreach (HookAttribute customAttribute in methodInfo.GetCustomAttributes<HookAttribute>(inherit: false)) { MethodInfo methodInfo2 = null; try { methodInfo2 = customAttribute.from; if (methodInfo2 == null && methodInfo.GetParameters().Length == 0) { methodInfo.Invoke(null, null); } else { customAttribute.Hook(methodInfo2, methodInfo); } } catch (Exception e) { e.LogHookError(methodInfo2, methodInfo); } } } } } protected virtual void Hook(MethodInfo from, MethodInfo member) { IDetour obj = HookManager.ManualDetour(from, member); if (obj != null) { obj.Apply(); } } } internal static class RiskofOptions { internal const string RooGuid = "com.rune580.riskofoptions"; internal static bool enabled => Chainloader.PluginInfos.ContainsKey("com.rune580.riskofoptions"); [MethodImpl(MethodImplOptions.NoInlining)] 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(ConfigEntryBase entry) { AddOption(entry, string.Empty, string.Empty); } [MethodImpl(MethodImplOptions.NoInlining)] internal static void AddOption(ConfigEntryBase entry, string categoryName = "", string name = "", bool restartRequired = false) { //IL_0157: Unknown result type (might be due to invalid IL or missing references) //IL_015c: Unknown result type (might be due to invalid IL or missing references) //IL_0177: Unknown result type (might be due to invalid IL or missing references) //IL_0192: 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_01b3: Expected O, but got Unknown //IL_01ae: Unknown result type (might be due to invalid IL or missing references) //IL_0129: Unknown result type (might be due to invalid IL or missing references) //IL_012e: Unknown result type (might be due to invalid IL or missing references) //IL_0139: Expected O, but got Unknown //IL_0139: Unknown result type (might be due to invalid IL or missing references) //IL_014f: Expected O, but got Unknown //IL_014a: Unknown result type (might be due to invalid IL or missing references) //IL_00f4: Unknown result type (might be due to invalid IL or missing references) //IL_00f9: Unknown result type (might be due to invalid IL or missing references) //IL_00fb: Unknown result type (might be due to invalid IL or missing references) //IL_0100: 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_01b4: Expected O, but got Unknown //IL_00df: Unknown result type (might be due to invalid IL or missing references) //IL_00e9: Expected O, but got Unknown //IL_00e4: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Expected O, but got Unknown //IL_00cf: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Expected O, but got Unknown //IL_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Expected O, but got Unknown //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Expected O, but got Unknown //IL_0090: Unknown result type (might be due to invalid IL or missing references) Type settingType = entry.SettingType; object obj; if (!(settingType == typeof(float))) { obj = ((!(settingType == typeof(string))) ? ((!(settingType == typeof(bool))) ? ((!(settingType == typeof(int))) ? ((!(settingType == typeof(Color))) ? ((!(settingType == typeof(KeyboardShortcut))) ? ((object)((!settingType.IsEnum) ? ((ChoiceOption)null) : new ChoiceOption(entry, new ChoiceConfig()))) : ((object)new KeyBindOption((ConfigEntry<KeyboardShortcut>)(object)entry, new KeyBindConfig()))) : ((object)new ColorOption((ConfigEntry<Color>)(object)entry, new ColorOptionConfig()))) : ((object)new IntFieldOption((ConfigEntry<int>)(object)entry, new IntFieldConfig()))) : ((object)new CheckBoxOption((ConfigEntry<bool>)(object)entry, new CheckBoxConfig()))) : ((object)new StringInputFieldOption((ConfigEntry<string>)(object)entry, new InputFieldConfig { submitOn = (SubmitEnum)6, lineType = (LineType)0 }))); } else if (entry.Description.AcceptableValues is AcceptableValueRange<float>) { obj = (object)new SliderOption((ConfigEntry<float>)(object)entry, new SliderConfig { min = ((AcceptableValueRange<float>)(object)entry.Description.AcceptableValues).MinValue, max = ((AcceptableValueRange<float>)(object)entry.Description.AcceptableValues).MaxValue, FormatString = "{0:f2}", description = entry.DescWithDefault("{0:f2}") }); } else { ConfigEntry<float> obj2 = (ConfigEntry<float>)(object)entry; FloatFieldConfig val = new FloatFieldConfig(); ((NumericFieldConfig<float>)val).FormatString = "{0:f2}"; ((BaseOptionConfig)val).description = entry.DescWithDefault("{0:f2}"); obj = (object)new FloatFieldOption(obj2, val); } BaseOption val2 = (BaseOption)obj; if (val2 == null) { return; } BaseOptionConfig config = val2.GetConfig(); config.category = categoryName; config.name = name; config.restartRequired = restartRequired; if (config.description == "") { config.description = entry.DescWithDefault(); } try { ModSettingsManager.AddOption(val2); } catch (Exception arg) { log.error($"AddOption {entry.Definition} failed\n{arg}"); } } [MethodImpl(MethodImplOptions.NoInlining)] internal static void AddOption(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) })); } [MethodImpl(MethodImplOptions.NoInlining)] 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_0031: Expected O, but got Unknown //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0036: 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, string format = "{0}") { return string.Format("{1}\n[Default: " + format + "]", entry.DefaultValue, entry.Description.Description); } } } namespace ItemStatistics { [StructLayout(LayoutKind.Sequential, Size = 1)] public readonly struct ChainContext : IDisposable { private static readonly List<ProcChain> chains; internal static ConstructorInfo constructor0 => typeof(ChainContext).GetConstructor(Type.EmptyTypes); internal static ConstructorInfo constructor1 => typeof(ChainContext).GetConstructor(new Type[1] { typeof(ProcChain) }); public ChainContext(ProcChain procChain) { chains.Add(CurrentContext.proc_chain = procChain); } public ChainContext() : this(default(ProcChain)) { } public void Dispose() { chains.RemoveAt(chains.Count - 1); ProcChain proc_chain; if (chains.Count <= 0) { proc_chain = default(ProcChain); } else { List<ProcChain> list = chains; proc_chain = list[list.Count - 1]; } CurrentContext.proc_chain = proc_chain; } static ChainContext() { chains = new List<ProcChain>(); Stage.onStageStartGlobal += SafetyCheck; } private static void SafetyCheck(Stage stage) { if (chains.Count != 0 || CurrentContext.proc_chain.isNotEmpty) { log.error("ChainContext has leaked chains: " + string.Join(", ", chains)); chains.Clear(); } } public override string ToString() { return "current_static_chain: " + CurrentContext.proc_chain; } } internal static class Config { internal enum ResetMode { Never, WhenNotInInventory } private static ConfigFile configFile; internal static ConfigEntry<ResetMode> resetOnStackChanged; internal static ConfigEntry<KeyboardShortcut> resetSpamKey; internal static ConfigEntry<KeyboardShortcut> resetAllKey; internal static void DoConfig(ConfigFile bepConfigFile) { //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0074: 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"); resetAllKey = configFile.Bind<KeyboardShortcut>(string.Empty, "Reset All Key", new KeyboardShortcut((KeyCode)286, (KeyCode[])(object)new KeyCode[1] { (KeyCode)306 }), "Press this key to reset all trackers in your inventory"); if (Chainloader.PluginInfos.ContainsKey("com.rune580.riskofoptions")) { DoRiskOfOptions(); } } internal static void DoRiskOfOptions() { RiskofOptions.SetSpriteDefaultIcon(); RiskofOptions.AddOption((ConfigEntryBase)(object)resetOnStackChanged); RiskofOptions.AddOption((ConfigEntryBase)(object)resetSpamKey); RiskofOptions.AddOption((ConfigEntryBase)(object)resetAllKey); } [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 readonly struct ContextData { public readonly TrackedInventory tracked_inventory; public readonly Inventory inventory; public readonly bool has_tracked_inv; public readonly bool is_not_minion; internal ContextData(TrackedInventory tracked, Inventory inventory) { tracked_inventory = tracked; this.inventory = inventory; has_tracked_inv = Object.op_Implicit((Object)(object)tracked); is_not_minion = has_tracked_inv && (Object)(object)tracked.inventory == (Object)(object)inventory; } } public static ProcChain proc_chain; public static ContextData attacker; public static ContextData victim; private static DamageInfo cached_info; private static ProcChain cached_chain; internal static ProcChain FindProcChain(DamageInfo damageInfo) { //IL_00ad: Unknown result type (might be due to invalid IL or missing references) if (damageInfo == cached_info) { return cached_chain; } cached_info = damageInfo; if (damageInfo.source_inflictor != null) { return cached_chain = damageInfo.source_inflictor.source_chain; } ProcComponent procComponent = default(ProcComponent); if (Object.op_Implicit((Object)(object)damageInfo.inflictor) && damageInfo.inflictor.TryGetComponent<ProcComponent>(ref procComponent)) { return cached_chain = procComponent.procChain; } if (((DamageTypeCombo)(ref damageInfo.damageType)).IsDamageSourceSkillBased) { if (Object.op_Implicit((Object)(object)damageInfo.attacker)) { CharacterBody component = damageInfo.attacker.GetComponent<CharacterBody>(); object obj; if (component == null) { obj = null; } else { CharacterMaster master = component.master; if (master == null) { obj = null; } else { MinionOwnership minionOwnership = master.minionOwnership; obj = ((minionOwnership != null) ? minionOwnership.ownerMaster : null); } } if (Object.op_Implicit((Object)obj)) { goto IL_00ce; } } Index index = damageInfo.damageType.damageSource; if (index.isNotNone) { return cached_chain = new ProcChain(index); } } goto IL_00ce; IL_00ce: return cached_chain = default(ProcChain); } } internal readonly struct HcContext : IDisposable { internal readonly struct IndexMultPair { internal readonly Index index; internal readonly float mult; internal IndexMultPair(Index index, float mult) { this.index = index; this.mult = mult; } } private static readonly List<HcContext> contexts = new List<HcContext>(); private static int depth; private readonly List<IndexMultPair> value; internal static List<IndexMultPair> current { get { if (depth <= 0) { return null; } return contexts[depth - 1].value; } } public HcContext() { depth++; if (depth > contexts.Count) { value = new List<IndexMultPair>(); contexts.Add(this); } else { this = contexts[depth - 1]; } } public void Dispose() { value.Clear(); depth--; } } public readonly struct HitContext : IDisposable { private readonly ChainContext chain_context; private readonly TrackedInventory attackerTrackedInventory; private readonly Inventory attackerInventory; private readonly TrackedInventory victimTrackedInventory; private readonly Inventory victimInventory; private static readonly List<HitContext> hits; public HitContext(ProcChain procChain, TrackedInventory attackerTrackedInventory, Inventory attackerInventory, TrackedInventory victimTrackedInventory, Inventory victimInventory) { chain_context = new ChainContext(procChain); this.attackerTrackedInventory = attackerTrackedInventory; this.attackerInventory = attackerInventory; this.victimTrackedInventory = victimTrackedInventory; this.victimInventory = victimInventory; CurrentContext.attacker = new CurrentContext.ContextData(attackerTrackedInventory, attackerInventory); CurrentContext.victim = new CurrentContext.ContextData(victimTrackedInventory, victimInventory); hits.Add(this); } public HitContext() : this(default(ProcChain), null, null, null, null) { } public void Dispose() { chain_context.Dispose(); hits.RemoveAt(hits.Count - 1); HitContext obj; if (hits.Count <= 0) { obj = default(HitContext); } else { List<HitContext> list = hits; obj = list[list.Count - 1]; } HitContext hitContext = obj; CurrentContext.attacker = new CurrentContext.ContextData(hitContext.attackerTrackedInventory, hitContext.attackerInventory); CurrentContext.victim = new CurrentContext.ContextData(hitContext.victimTrackedInventory, hitContext.victimInventory); } static HitContext() { hits = new List<HitContext>(); Stage.onStageStartGlobal += SafetyCheck; } private static void SafetyCheck(Stage stage) { if (hits.Count != 0 || CurrentContext.attacker.has_tracked_inv) { log.error("HitContext has leaked hits: " + string.Join(",\n", hits)); hits.Clear(); } } public override string ToString() { return string.Join(", ", chain_context, attackerTrackedInventory, attackerInventory, victimTrackedInventory, victimInventory); } } [Serializable] public struct Index : IEquatable<Index> { [SerializeField] private short _index; [SerializeField] private IndexType _type; public readonly short index => _index; public readonly IndexType type => _type; public readonly bool isNone => _type == IndexType.None; public readonly bool isNotNone => _type != IndexType.None; public Index(ItemIndex x) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) _index = (short)x; _type = IndexType.Item; } public Index(EquipmentIndex x) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) _index = (short)x; _type = IndexType.Equip; } public Index(SkillSlot x) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Expected I4, but got Unknown _index = (short)(int)x; _type = IndexType.SkillSlot; } public Index(MiscIndex x) { _index = (short)x; _type = IndexType.Misc; } public Index(BodyIndex x) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) _index = (short)x; _type = IndexType.Body; } public Index(short index, IndexType type) { _index = index; _type = type; } 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(BodyIndex index) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) 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_0038: 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: case 9: case 11: return new Index((SkillSlot)3); default: return new Index(0, IndexType.None); } } public static bool operator ==(Index a, Index b) { if (a._index == b._index) { return a._type == b._type; } return false; } public static bool operator !=(Index a, Index b) { if (a._index == b._index) { return a._type != b._type; } return true; } public readonly bool Equals(Index index) { if (_index == index._index) { return _type == index._type; } return false; } public override readonly bool Equals(object obj) { if (obj is Index) { return Equals((Index)obj); } return false; } public override readonly int GetHashCode() { return (_index & 0xFFFF) + ((int)_type << 16); } public override readonly string ToString() { //IL_0083: Unknown result type (might be due to invalid IL or missing references) switch (_type) { case IndexType.None: if (_index == 0) { return "None"; } return "None." + _index; case IndexType.Item: return ((ItemIndex)_index).Name(); case IndexType.Equip: return ((EquipmentIndex)_index).Name(); case IndexType.SkillSlot: { SkillSlot val = (SkillSlot)(sbyte)_index; return "Skill." + ((object)(SkillSlot)(ref val)).ToString(); } case IndexType.Misc: return "Misc." + (MiscIndex)_index; case IndexType.Body: return ((BodyIndex)_index).Name(); default: return $"Unknown Index {{t:{_type}, i:{_index}}}"; } } internal static void Serialize(NetworkWriter writer, Index value) { writer.Write(value._index); writer.Write((short)value._type); } internal static Index Deserialize(NetworkReader reader) { return new Index(reader.ReadInt16(), (IndexType)reader.ReadInt16()); } } public enum IndexType : short { None, Item, Equip, SkillSlot, Misc, Body } public enum MiscIndex { NeverInInventory = -1, Ignore = 0, Regen = 1, Barrier = 2, MinionDamage = 3, Shield = 4, FreezeCreditMinionBody = -2 } 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.flags != 0) { ItemStatisticsPlugin.indexToDef.Add(indexToAdd, trackedDef); } else { log.error($"Attempted to give {indexToAdd} an undefined tracker def"); } } public static void AddCombatStackTracker(Index index, BuffIndex buffIndex) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) ItemStatisticsPlugin.combatBuffsTrackers.Add((index, buffIndex)); } public static TrackedInventory GetTrackedInventory(CharacterMaster master, bool includeFromMinion) { return master.GetTrackedInventory(includeFromMinion); } public static bool TryGetTrackedInventory(CharacterMaster master, bool includeFromMinion, out TrackedInventory trackedInventory) { return master.TryGetTrackedInventory(includeFromMinion, out trackedInventory); } public static GameObject CreateNewInflictor(Index index, ProcChain parentChain = default(ProcChain)) { 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); } } [BepInPlugin("dolso.ItemStatistics", "ItemStatistics", "1.2.12")] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] public class ItemStatisticsPlugin : BaseUnityPlugin { public const string ModGuid = "dolso.ItemStatistics"; public const string Version = "1.2.12"; internal static readonly Dictionary<Index, TrackedDef> indexToDef = new Dictionary<Index, TrackedDef>(); internal static readonly List<(Index index, BuffIndex buffIndex)> combatBuffsTrackers = new List<(Index, BuffIndex)>(); 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() { Config.DoConfig(((BaseUnityPlugin)this).Config); ModifyAddressablesAsync(); Stopwatch stopwatch = Stopwatch.StartNew(); Language.collectLanguageRootFolders += CollectLanguageRootFolders; HookAttribute.ScanAndApply(); log.info($"Hooks completed in {stopwatch.Elapsed.TotalSeconds:f2}s"); } private void Update() { //IL_0005: Unknown result type (might be due to invalid IL or missing references) if (Config.resetAllKey.Value.IsKeyDown(onlyJustPressed: true)) { LocalUser firstLocalUser = LocalUserManager.GetFirstLocalUser(); if (firstLocalUser != null) { firstLocalUser.cachedMaster?.trackedInventory.CallCmdResetAllTrackers(); } } } 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>)null); 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(); Utilities.AddressableAddComp<SharedSufferingAddOn>("RoR2/DLC3/DLC3RunBehavior.prefab", (Action<SharedSufferingAddOn>)null); } catch (Exception ex) { log.error("Failed to do addressables\n" + ex); } } [InitDuringStartupPhase(/*Could not decode attribute arguments.*/)] private static void Init() { //IL_0d5e: Unknown result type (might be due to invalid IL or missing references) //IL_0d7d: Unknown result type (might be due to invalid IL or missing references) //IL_0d9c: Unknown result type (might be due to invalid IL or missing references) //IL_0dbb: Unknown result type (might be due to invalid IL or missing references) //IL_0dda: Unknown result type (might be due to invalid IL or missing references) //IL_0df9: Unknown result type (might be due to invalid IL or missing references) //IL_0e18: Unknown result type (might be due to invalid IL or missing references) //IL_0e37: Unknown result type (might be due to invalid IL or missing references) //IL_0e55: Unknown result type (might be due to invalid IL or missing references) //IL_0e7d: Unknown result type (might be due to invalid IL or missing references) //IL_0e82: 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(TrackerFlags.Heal, TrackedDef.regen_portion_tooltip)); dictionary.Add(MiscIndex.Barrier, new TrackedDef(TrackerFlags.Block, TrackedDef.barrier_blocked_tooltip)); dictionary.Add(MiscIndex.MinionDamage, new TrackedDef(TrackerFlags.Damage, TrackedDef.minion_portion_tooltip)); dictionary.Add(MiscIndex.Shield, new TrackedDef(TrackerFlags.Block, TrackedDef.shield_blocked_tooltip)); dictionary.Add(Items.Bear, TrackedDef.ArmorCountChance); dictionary.Add(Items.BearVoid, TrackedDef.ArmorCountChance); dictionary.Add(Items.Crowbar, TrackedDef.Damage); dictionary.Add(Items.ExplodeOnDeathVoid, TrackedDef.DamagePortion); dictionary.Add(Items.NearbyDamageBonus, TrackedDef.Damage); dictionary.Add(Items.FragileDamageBonus, TrackedDef.Damage); dictionary.Add(Items.FragileDamageBonusConsumed, new TrackedDef(TrackerFlags.Damage, TrackedDef.damage_tooltip)); dictionary.Add(Items.BossDamageBonus, TrackedDef.Damage); dictionary.Add(Items.CritGlasses, new TrackedDef(TrackerFlags.Damage, TrackedDef.total_crit_tooltip)); dictionary.Add(Items.CritDamage, TrackedDef.Damage); dictionary.Add(Items.DeathMark, TrackedDef.Damage); dictionary.Add(Items.CritGlassesVoid, TrackedDef.DamageChance); dictionary.Add(Items.ExecuteLowHealthElite, TrackedDef.DamagePortion); dictionary.Add(Items.OutOfCombatArmor, TrackedDef.ArmorCountChance); dictionary.Add(Items.SprintArmor, TrackedDef.ArmorChance); 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.DamagePortion); 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.DamagePortionChance); dictionary.Add(Items.ExplodeOnDeath, TrackedDef.DamagePortionChance); dictionary.Add(Items.Dagger, TrackedDef.DamagePortion); dictionary.Add(Items.Tooth, TrackedDef.Heal); dictionary.Add(Items.Bandolier, TrackedDef.Chance); dictionary.Add(Items.BonusGoldPackOnKill, TrackedDef.Gold); dictionary.Add(Items.BleedOnHitAndExplode, new TrackedDef(TrackerFlags.Damage | TrackerFlags.Attempt, TrackedDef.hit_tooltip, TrackedDef.portion_tooltip)); dictionary.Add(Items.BarrierOnKill, new TrackedDef(TrackerFlags.Heal, TrackedDef.barrier_gained_tooltip)); 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(TrackerFlags.Heal, TrackedDef.barrier_gained_tooltip)); dictionary.Add(Items.ShockNearby, TrackedDef.DamagePortion); dictionary.Add(Items.PrimarySkillShuriken, new TrackedDef(TrackerFlags.Damage | TrackerFlags.Attempt, TrackedDef.hit_tooltip, TrackedDef.portion_tooltip)); dictionary.Add(Items.StrengthenBurn, TrackedDef.Damage); dictionary.Add(Items.LaserTurbine, TrackedDef.DamagePortion); dictionary.Add(Items.CaptainDefenseMatrix, TrackedDef.Count); dictionary.Add(Items.Icicle, TrackedDef.DamagePortion); dictionary.Add(Items.NovaOnLowHealth, TrackedDef.DamagePortion); dictionary.Add(Items.ImmuneToDebuff, new TrackedDef(TrackerFlags.Heal | TrackerFlags.Success, TrackedDef.chance_tooltip, TrackedDef.barrier_gained_tooltip)); dictionary.Add(Items.NovaOnHeal, TrackedDef.DamagePortion); dictionary.Add(Items.SprintWisp, TrackedDef.DamagePortion); dictionary.Add(Items.RandomlyLunar, TrackedDef.Chance); dictionary.Add(Items.Firework, TrackedDef.DamagePortion); dictionary.Add(Items.Phasing, TrackedDef.Count); dictionary.Add(Items.FallBoots, TrackedDef.DamagePortion); dictionary.Add(Items.SiphonOnLowHealth, new TrackedDef(TrackerFlags.Damage | TrackerFlags.Heal, TrackedDef.portion_tooltip, TrackedDef.heal_tooltip)); dictionary.Add(Items.LunarSun, TrackedDef.DamagePortion); dictionary.Add(Items.Infusion, TrackedDef.Count); dictionary.Add(Items.HeadHunter, TrackedDef.Damage); dictionary.Add(Items.RoboBallBuddy, TrackedDef.DamagePortion); dictionary.Add(Items.VoidMegaCrabItem, TrackedDef.DamagePortion); dictionary.Add(Items.BeetleGland, TrackedDef.DamagePortion); dictionary.Add(Items.DroneWeapons, TrackedDef.DamagePortion); dictionary.Add(Items.GhostOnKill, TrackedDef.DamagePortion); dictionary.Add(Items.MinorConstructOnKill, TrackedDef.DamagePortion); dictionary.Add(Items.Squid, TrackedDef.DamagePortion); dictionary.Add(Items.TitanGoldDuringTP, TrackedDef.DamagePortion); dictionary.Add(Items.ExtraShrineItem, TrackedDef.Chance); dictionary.Add(Items.IncreasePrimaryDamage, TrackedDef.DamagePortion); 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.ItemDropChanceOnKill, TrackedDef.Chance); dictionary.Add(Items.BarrageOnBoss, TrackedDef.DamagePortion); dictionary.Add(Items.TeleportOnLowHealth, new TrackedDef(TrackerFlags.Damage | TrackerFlags.Success, TrackedDef.count_tooltip, TrackedDef.portion_tooltip)); 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.StackCombat); 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.AttackSpeedPerNearbyAllyOrEnemy, TrackedDef.StackHitSkill); dictionary.Add(Items.AttackSpeedOnCrit, TrackedDef.StackHitSkill); dictionary.Add(Items.DronesDropDynamite, TrackedDef.DamagePortion); dictionary.Add(Items.PowerCube, TrackedDef.Armor); dictionary.Add(Items.JumpDamageStrike, new TrackedDef(TrackerFlags.Damage | TrackerFlags.Attempt, TrackedDef.stack_combat_tooltip, TrackedDef.portion_tooltip)); dictionary.Add(Items.ShieldBooster, new TrackedDef(TrackerFlags.Block | TrackerFlags.Damage, TrackedDef.reduction_tooltip, TrackedDef.portion_tooltip)); dictionary.Add(Items.SpeedOnPickup, TrackedDef.StackCombat); dictionary.Add(Items.BarrierOnCooldown, new TrackedDef(TrackerFlags.Heal, TrackedDef.barrier_gained_tooltip)); dictionary.Add(Items.SharedSuffering, new TrackedDef(TrackerFlags.Damage, TrackedDef.sharedsuffering_tooltip)); dictionary.Add(Items.PhysicsProjectile, new TrackedDef(TrackerFlags.Damage | TrackerFlags.Success, TrackedDef.count_tooltip, TrackedDef.portion_tooltip)); dictionary.Add(Items.Duplicator, TrackedDef.Count); dictionary.Add(Items.CritAtLowerElevation, TrackedDef.StackHit); dictionary.Add(Items.WyrmOnHit, TrackedDef.DamageChance); dictionary.Add(Equipment.Saw, TrackedDef.DamagePortion); dictionary.Add(Equipment.GoldGat, TrackedDef.DamagePortion); dictionary.Add(Equipment.BFG, TrackedDef.DamagePortion); dictionary.Add(Equipment.PassiveHealing, TrackedDef.Heal); dictionary.Add(Equipment.CommandMissile, TrackedDef.DamagePortion); dictionary.Add(Equipment.Fruit, TrackedDef.Heal); dictionary.Add(Equipment.DroneBackup, TrackedDef.DamagePortion); dictionary.Add(Equipment.Lightning, TrackedDef.DamagePortion); dictionary.Add(Equipment.Recycle, new TrackedDef(TrackerFlags.Success, TrackedDef.recycled_tooltip)); dictionary.Add(Equipment.LifestealOnHit, TrackedDef.Heal); dictionary.Add(Equipment.Molotov, TrackedDef.DamagePortion); dictionary.Add(Equipment.VendingMachine, TrackedDef.Heal); dictionary.Add(Equipment.GummyClone, TrackedDef.DamagePortion); dictionary.Add(Equipment.MultiShopCard, TrackedDef.Gold); dictionary.Add(Equipment.GainArmor, TrackedDef.Armor); dictionary.Add(Equipment.Meteor, TrackedDef.DamagePortion); dictionary.Add(Equipment.BurnNearby, TrackedDef.DamagePortion); dictionary.Add(Equipment.AffixRed, TrackedDef.Damage); dictionary.Add(Equipment.AffixBlue, TrackedDef.Damage); dictionary.Add(Equipment.AffixWhite, TrackedDef.DamagePortion); dictionary.Add(Equipment.EliteAurelioniteEquipment, TrackedDef.DamagePortion); dictionary.Add(Equipment.EliteBeadEquipment, TrackedDef.DamagePortion); dictionary.Add(Equipment.Parry, TrackedDef.Chance); List<(Index index, BuffIndex buffIndex)> list = combatBuffsTrackers; list.Add((Items.WardOnLevel, Buffs.Warbanner.buffIndex)); list.Add((Items.WarCryOnMultiKill, Buffs.WarCryBuff.buffIndex)); list.Add((Items.EnergizedOnEquipmentUse, Buffs.Energized.buffIndex)); list.Add((Items.KillEliteFrenzy, Buffs.NoCooldowns.buffIndex)); list.Add((Items.MoveSpeedOnKill, Buffs.KillMoveSpeed.buffIndex)); list.Add((Items.SpeedBoostPickup, Buffs.ElusiveAntlersBuff.buffIndex)); list.Add((Items.BoostAllStats, Buffs.BoostAllStatsBuff.buffIndex)); list.Add((Items.JumpDamageStrike, Buffs.JumpDamageStrikeCharge.buffIndex)); list.Add((Items.SpeedOnPickup, Buffs.SpeedOnPickup.buffIndex)); 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/BarrageOnBoss/BossMissileProjectile.prefab", Items.BarrageOnBoss); Utilities.DoAddressable<GameObject>("RoR2/Base/BonusGoldPackOnKill/BonusMoneyPack.prefab", (Action<GameObject>)delegate(GameObject a) { ((Component)a.GetComponentInChildren<MoneyPickup>()).gameObject.AddComponent<ProcComponent>().index = Items.BonusGoldPackOnKill; }, release: false); AddProcComponent("RoR2/DLC3/Items/DronesDropDynamite/DynamiteProjectile.prefab", Items.DronesDropDynamite); AddProcComponent("RoR2/DLC3/Items/WyrmOnHit/WyrmProjectile.prefab", Items.WyrmOnHit); 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); AddMinionComponent("RoR2/DLC3/FriendUnit/FriendUnitBody.prefab", Items.PhysicsProjectile); 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; }, release: false); 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/BoostedIceBoxIceCubeProjectile.prefab", (SkillSlot)3); AddProcComponent("RoR2/DLC2/Chef/ChefGlazeProjectile.prefab", (SkillSlot)3); AddProcComponent("RoR2/DLC2/Chef/ChefGlazeProjectileUtility.prefab", (SkillSlot)2); AddProcComponent("RoR2/DLC2/Chef/ChefGlazeProjectileUtilityIgnited.prefab", (SkillSlot)3); AddProcComponent("RoR2/DLC2/Chef/ChefGlazeProjectileUtilityFrozen.prefab", (SkillSlot)3); AddProcComponent("RoR2/DLC2/Chef/ChefImpactOilBoosted.prefab", (SkillSlot)3); AddProcComponent("RoR2/DLC2/Chef/ChefImpactOilBoostedFrozen.prefab", (SkillSlot)3); AddProcComponent("RoR2/DLC3/Drone Tech/CommandJailerDroneCage.prefab", (SkillSlot)1); AddProcComponent("RoR2/DLC3/Drone Tech/HaulerThrowProjectile.prefab", (SkillSlot)1); Utilities.DoAddressable("RoR2/Base/Common/MissileProjectile.prefab", DoMissilePrefab); DoElites(); } private static void AddProcComponent(string addressable, Index index) { Utilities.AddressableAddComp<ProcComponent>(addressable, (Action<ProcComponent>)delegate(ProcComponent a) { a.index = index; }); } private static void AddMinionComponent(string addressable, Index index) { Utilities.AddressableAddComp<MinionComponent>(addressable, (Action<MinionComponent>)delegate(MinionComponent a) { a.index = index; }); } private static void DoMissilePrefab(GameObject missilePrefab) { missileLauncher = Utilities.CreatePrefab(missilePrefab, "DisposableMissileProjectile"); missileLauncher.AddComponent<ProcComponent>().index = Equipment.CommandMissile; missilePrefab.AddComponent<ProcComponent>().index = Items.Missile; } private static async void DoElites() { try { AsyncOperationHandle<GameObject>[] tasks = new AsyncOperationHandle<GameObject>[5] { Utilities.GetAddressableAsync("RoR2/Base/EliteLightning/LightningStake.prefab"), Utilities.GetAddressableAsync("RoR2/Base/Common/FireTrail.prefab"), Utilities.GetAddressableAsync("RoR2/DLC2/Elites/EliteBead/BeadProjectileTrackingBomb.prefab"), Utilities.GetAddressableAsync("RoR2/DLC2/Elites/EliteAurelionite/AffixAurelionitePreStrikeProjectile.prefab"), Utilities.GetAddressableAsync("RoR2/DLC2/Elites/EliteAurelionite/AffixAurelioniteCenterProjectile.prefab") }; await Task.WhenAll(tasks.Select((AsyncOperationHandle<GameObject> a) => a.Task)); DoDualElitePrefab(tasks[0].Result, Equipment.AffixBlue.equipmentIndex, out hhOverloading); DoDualElitePrefab(tasks[1].Result, Equipment.AffixRed.equipmentIndex, out hhFireTrail); DoDualElitePrefab(tasks[2].Result, Equipment.EliteBeadEquipment.equipmentIndex, out hhBead); DoDualElitePrefab(tasks[3].Result, Equipment.EliteAurelioniteEquipment.equipmentIndex, out hhGoldOuter); DoDualElitePrefab(tasks[4].Result, Equipment.EliteAurelioniteEquipment.equipmentIndex, out hhGoldInner); } catch (Exception data) { log.error(data); } } 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 readonly struct ProcChain : IEnumerable<Index>, IEnumerable { private readonly Index[] indexes; public Index source_index { get { Index[] array = indexes; if (array == null) { return default(Index); } return array[0]; } } public bool isEmpty => indexes == null; public bool isNotEmpty => indexes != null; public ProcChain(Index index) { indexes = new Index[1] { index }; } public ProcChain(Index index, ProcChain parent) { if (parent.indexes != null) { indexes = new Index[1 + parent.indexes.Length]; for (int i = 0; i < parent.indexes.Length; i++) { indexes[1 + i] = parent.indexes[i]; } } else { indexes = new Index[1]; } indexes[0] = index; } public override string ToString() { if (indexes == null) { return string.Empty; } string text = indexes[0].ToString(); for (int i = 1; i < indexes.Length; i++) { text = indexes[i].ToString() + " -> " + text; } return text; } public IEnumerator<Index> GetEnumerator() { return ((IEnumerable<Index>)(indexes ?? Array.Empty<Index>())).GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return (indexes ?? Array.Empty<Index>()).GetEnumerator(); } } public class SourceInflictor { public readonly ProcChain source_chain; private bool hasHit; public SourceInflictor(Index index) { source_chain = new ProcChain(index); } public SourceInflictor(Index index, ProcChain parent_chain) { source_chain = new ProcChain(index, parent_chain); } internal void OnDamageInflictedServer(DamageReport damageReport) { if (!hasHit) { hasHit = true; if (source_chain.isNotEmpty && damageReport.attackerMaster.TryGetTrackedInventory(includeFromMinion: true, out var trackedInventory)) { trackedInventory.TryAddSuccess(source_chain.source_index); } } } public override string ToString() { return source_chain.ToString(); } } public struct Tracker { private static class TooltipParser { private static readonly Regex tooltip_regex = new Regex("{([A-Z]+)\\(([A-Z]*)(\\?)?\\)}"); private unsafe static Tracker* tracker; private unsafe static Totals* totals; private static bool ignore; internal unsafe static string Parse(in Tracker tracker, in Totals totals, string[] tooltips_unformatted) { fixed (Tracker* ptr = &tracker) { fixed (Totals* ptr2 = &totals) { TooltipParser.tracker = ptr; TooltipParser.totals = ptr2; ignore = false; string text = string.Empty; foreach (string input in tooltips_unformatted) { string text2 = tooltip_regex.Replace(input, Evaluator); if (!ignore) { text = ((text.Length <= 0) ? (text + text2) : (text + "\n" + text2)); } else { ignore = false; } } return text; } } } private unsafe static string Evaluator(Match match) { var (trackedValue, num) = match.Groups[2].Value switch { "BLOCK" => ((tracker->flags & TrackerFlags.Damage) == 0) ? (tracker->v1, totals->damageTaken) : (tracker->v2, totals->damageTaken), "DAMAGE" => (tracker->v1, totals->damageDealt), "HEAL" => ((tracker->flags & TrackerFlags.Damage) == 0) ? (tracker->v1, totals->healed) : (tracker->v2, totals->healed), "GOLD" => (tracker->v1, totals->goldEarned), "COUNT" => (tracker->v2, 0f), _ => (tracker->v2, 0f), }; if (match.Groups[3].Success && trackedValue.value.i == 0) { ignore = true; return string.Empty; } return match.Groups[1].Value switch { "INCREASE" => TrackerStatics.IncreaseToString(trackedValue.value.f, num - trackedValue.total_when_set.f), "REDUCTION" => TrackerStatics.ReductionToString(trackedValue.value.f, num - trackedValue.total_when_set.f), "PORTION" => TrackerStatics.PortionToString(trackedValue.value.f, num - trackedValue.total_when_set.f), "CHANCE" => TrackerStatics.ChanceToString(trackedValue.value.i, trackedValue.total_when_set.i), "RATE" => TrackerStatics.RateToString(trackedValue.value.i, trackedValue.total_when_set.i), "COUNT" => trackedValue.value.i.ToString("n0"), "VALUE" => trackedValue.value.f.ToString("n0"), _ => "UNDEFINED:" + match.Value, }; } } private struct TrackedValue { internal num32 value; internal num32 total_when_set; } [StructLayout(LayoutKind.Explicit)] private readonly struct num32 { [FieldOffset(0)] internal readonly uint i; [FieldOffset(0)] internal readonly float f; internal num32(uint i) { f = 0f; this.i = i; } internal num32(float f) { i = 0u; this.f = f; } public static implicit operator num32(uint i) { return new num32(i); } public static implicit operator num32(float f) { return new num32(f); } public static num32 operator +(num32 num, uint i) { return new num32(num.i + i); } public static num32 operator +(num32 num, float f) { return new num32(num.f + f); } } private TrackedValue v1; private TrackedValue v2; public TrackerFlags flags; public void AddDamage(float damage) { v1.value += damage; SetDirty(); } public void AddHealing(float heal) { if ((flags & TrackerFlags.Damage) != 0) { v2.value += heal; } else { v1.value += heal; } SetDirty(); } public void AddBlocked(float blocked) { if ((flags & TrackerFlags.Damage) != 0) { v2.value += blocked; } else { v1.value += blocked; } SetDirty(); } public void AddGold(float gold) { v1.value += gold; SetDirty(); } public void AddAttempt() { v2.total_when_set += 1u; SetDirty(); } public void AddSuccess() { v2.value += 1u; SetDirty(); } public void AddSuccess(uint count) { v2.value += count; SetDirty(); } internal readonly string GetTooltip(in Totals totals, string[] tooltips_unformatted) { return TooltipParser.Parse(in this, in totals, tooltips_unformatted); } internal void Reset(in Totals totals) { v1.value = 0u; v2.value = 0u; if ((flags & TrackerFlags.Damage) != 0) { v1.total_when_set = totals.damageDealt; } else if ((flags & TrackerFlags.Gold) != 0) { v1.total_when_set = totals.goldEarned; } else if ((flags & (TrackerFlags.Block | TrackerFlags.Damage)) == TrackerFlags.Block) { v1.total_when_set = totals.damageTaken; } else if ((flags & (TrackerFlags.Damage | TrackerFlags.Heal)) == TrackerFlags.Heal) { v1.total_when_set = totals.healed; } else { v1.total_when_set = 0u; } if ((flags & (TrackerFlags.Block | TrackerFlags.Damage)) == (TrackerFlags.Block | TrackerFlags.Damage)) { v2.total_when_set = totals.damageTaken; } else if ((flags & (TrackerFlags.Damage | TrackerFlags.Heal)) == (TrackerFlags.Damage | TrackerFlags.Heal)) { v2.total_when_set = totals.healed; } else { v2.total_when_set = 0u; } if ((flags & TrackerFlags.Watch) != 0) { flags &= ~TrackerFlags.Watch; } } internal readonly void Serialize(SerializationBuffer data) { if ((flags & (TrackerFlags.Block | TrackerFlags.Damage | TrackerFlags.Gold | TrackerFlags.Heal)) != 0) { data.Add(v1.value.i); } if ((flags & (TrackerFlags.Attempt | TrackerFlags.Success)) != 0) { data.Add(v2.value.i); data.Add(v2.total_when_set.i); } else if ((int)(flags & (TrackerFlags.Block | TrackerFlags.Damage | TrackerFlags.Heal)) > 4) { data.Add(v2.value.i); } } internal void Deserialize(SerializationBuffer data) { if ((flags & (TrackerFlags.Block | TrackerFlags.Damage | TrackerFlags.Gold | TrackerFlags.Heal)) != 0) { v1.value = data.nextInt; } if ((flags & (TrackerFlags.Attempt | TrackerFlags.Success)) != 0) { v2.value = data.nextInt; v2.total_when_set = data.nextInt; } else if ((int)(flags & (TrackerFlags.Block | TrackerFlags.Damage | TrackerFlags.Heal)) > 4) { v2.value = data.nextInt; } } internal void HandleBrokenWatch(in Tracker former_watch) { AddDamage(former_watch.v1.value.f); if ((flags & TrackerFlags.Watch) == 0) { v1.total_when_set = former_watch.v1.total_when_set; flags |= TrackerFlags.Watch; } } private void SetDirty() { flags |= TrackerFlags.Dirty; } internal void UnDirty() { flags &= ~TrackerFlags.Dirty; } internal readonly bool IsDirty() { return (flags & TrackerFlags.Dirty) != 0; } internal static int CompareDamage(in Tracker a, in Tracker b, in Totals totals) { float num = a.v1.value.f / (totals.damageDealt - a.v1.total_when_set.f); float value = b.v1.value.f / (totals.damageDealt - b.v1.total_when_set.f); return num.CompareTo(value); } } [Serializable] public struct Totals { public static float allDamageDealt; public float damageDealt; public float damageTaken; public float healed; public uint goldEarned; static Totals() { Run.onRunStartGlobal += ResetGlobalDamage; } private static void ResetGlobalDamage(Run run) { allDamageDealt = 0f; } } public sealed class TrackedDef { private static readonly string tooltip_prefix = "ITEMSTATISTICS_TOOLTIPS_"; public static readonly string damage_tooltip = tooltip_prefix + "DAMAGE"; public static readonly string chance_tooltip = tooltip_prefix + "CHANCE"; public static readonly string count_tooltip = tooltip_prefix + "COUNT"; public static readonly string hit_tooltip = tooltip_prefix + "HIT"; public static readonly string heal_tooltip = tooltip_prefix + "HEAL"; public static readonly string heal_optional_tooltip = tooltip_prefix + "HEAL_OPTIONAL"; public static readonly string gold_tooltip = tooltip_prefix + "GOLD"; public static readonly string reduction_tooltip = tooltip_prefix + "REDUCTION"; public static readonly string portion_tooltip = tooltip_prefix + "DAMAGEPORTION"; public static readonly string portion_optional_tooltip = tooltip_prefix + "DAMAGEPORTION_OPTIONAL"; public static readonly string recycled_tooltip = tooltip_prefix + "RECYCLED"; public static readonly string barrier_gained_tooltip = tooltip_prefix + "BARRIERGAINED"; public static readonly string total_crit_tooltip = tooltip_prefix + "CRITDAMAGE"; public static readonly string stack_tooltip = tooltip_prefix + "STACK"; public static readonly string stack_combat_tooltip = tooltip_prefix + "STACKCOMBAT"; public static readonly string stack_hit_tooltip = tooltip_prefix + "STACKHIT"; public static readonly string stack_hit_skill_tooltip = tooltip_prefix + "STACKHITSKILL"; public static readonly string global_portion_tooltip = tooltip_prefix + "GLOBALPORTION"; public static readonly string minion_portion_tooltip = tooltip_prefix + "MINIONPORTION"; public static readonly string regen_portion_tooltip = tooltip_prefix + "REGENPORTION"; public static readonly string barrier_blocked_tooltip = tooltip_prefix + "BARRIERBLOCKED"; public static readonly string shield_blocked_tooltip = tooltip_prefix + "SHIELDBLOCKED"; public static readonly string minion_body_portion_tooltip = tooltip_prefix + "MINIONBODYPORTION"; public static readonly string sharedsuffering_tooltip = tooltip_prefix + "SHAREDSUFFERING"; public static readonly TrackedDef ArmorCount = new TrackedDef(TrackerFlags.Block | TrackerFlags.Success, count_tooltip, reduction_tooltip); public static readonly TrackedDef ArmorCountChance = new TrackedDef(TrackerFlags.Block | TrackerFlags.Attempt, count_tooltip, chance_tooltip, reduction_tooltip); public static readonly TrackedDef ArmorChance = new TrackedDef(TrackerFlags.Block | TrackerFlags.Attempt, chance_tooltip, reduction_tooltip); public static readonly TrackedDef Armor = new TrackedDef(TrackerFlags.Block, reduction_tooltip); public static readonly TrackedDef Chance = new TrackedDef(TrackerFlags.Attempt, count_tooltip, chance_tooltip); public static readonly TrackedDef Count = new TrackedDef(TrackerFlags.Success, count_tooltip); public static readonly TrackedDef DamageChance = new TrackedDef(TrackerFlags.Damage | TrackerFlags.Attempt, chance_tooltip, damage_tooltip); public static readonly TrackedDef DamagePortionChance = new TrackedDef(TrackerFlags.Damage | TrackerFlags.Attempt, chance_tooltip, portion_tooltip); public static readonly TrackedDef DamagePortion = new TrackedDef(TrackerFlags.Damage, portion_tooltip); public static readonly TrackedDef Damage = new TrackedDef(TrackerFlags.Damage, damage_tooltip); public static readonly TrackedDef Gold = new TrackedDef(TrackerFlags.Gold, gold_tooltip); public static readonly TrackedDef Heal = new TrackedDef(TrackerFlags.Heal, heal_tooltip); public static readonly TrackedDef Skill = new TrackedDef(TrackerFlags.Damage | TrackerFlags.Heal, portion_optional_tooltip, heal_optional_tooltip); public static readonly TrackedDef Stack = new TrackedDef(TrackerFlags.Attempt, stack_tooltip); public static readonly TrackedDef StackCombat = new TrackedDef(TrackerFlags.Attempt, stack_combat_tooltip); public static readonly TrackedDef StackHit = new TrackedDef(TrackerFlags.Attempt, stack_hit_tooltip); public static readonly TrackedDef StackHitSkill = new TrackedDef(TrackerFlags.Attempt, stack_hit_skill_tooltip); internal static readonly TrackedDef MinionBody = new TrackedDef(TrackerFlags.Damage, minion_body_portion_tooltip); internal readonly TrackerFlags flags; private readonly string[] tooltip_tokens; public TrackedDef(TrackerFlags flags, params string[] tooltip_tokens) { if (flags == TrackerFlags.Undefined) { throw new ArgumentException("flags must be non-zero"); } this.flags = flags; this.tooltip_tokens = tooltip_tokens ?? throw new ArgumentNullException("tooltip_tokens"); } internal string[] GetTooltipsLanguaged() { string[] array = new string[tooltip_tokens.Length]; for (int i = 0; i < array.Length; i++) { array[i] = Language.GetString(tooltip_tokens[i]); } return array; } } [Flags] public enum TrackerFlags : byte { Undefined = 0, Block = 2, Damage = 4, Gold = 8, Heal = 0x10, Attempt = 0x20, Success = 0x40, Watch = 0x80, Dirty = 1 } internal static class TrackerStatics { internal static string IncreaseToString(float value, float total) { if (total == 0f) { return "NaN"; } if (value >= 0.999999f * total) { return "Max"; } float num = ((!(value < 0f)) ? (100f / (1f - value / total) - 100f) : (100f * value / total)); return num.ToString((num < 3f) ? "f1" : "f0") + "%"; } internal static string ReductionToString(float value, float total) { if (total == 0f) { if (!(value > 0f)) { return "NaN"; } return "100%"; } if (value <= -0.999999f * total) { return "Min"; } float num = 100f - 100f / (1f + value / total); return num.ToString((num < 3f) ? "f1" : "f0") + "%"; } internal static string PortionToString(float value, float total) { if (total == 0f) { return "NaN"; } float num = 100f * value / total; return num.ToString((num < 3f) ? "f1" : "f0") + "%"; } internal static string ChanceToString(uint succedded, uint attempted) { if (attempted == 0) { return "NaN"; } float num = 100f * (float)succedded / (float)attempted; return num.ToString((num < 10f) ? "f1" : "f0") + "%"; } internal static string RateToString(uint succedded, uint attempted) { if (attempted == 0) { return "NaN"; } float num = (float)succedded / (float)attempted; return num.ToString((num <= 1f) ? "f2" : ((num < 10f) ? "f1" : "f0")); } } public static class Utils { [MethodImpl(MethodImplOptions.AggressiveInlining)] public static TrackedInventory GetTrackedInventory(this CharacterMaster master, bool includeFromMinion) { if (master == null) { return null; } if (includeFromMinion) { MinionOwnership minionOwnership = master.minionOwnership; if (((minionOwnership != null) ? minionOwnership.ownerMaster : null) != null) { return master.minionOwnership.ownerMaster.trackedInventory; } } return master.trackedInventory; } public static bool TryGetTrackedInventory(this CharacterMaster master, bool includeFromMinion, out TrackedInventory trackedInventory) { trackedInventory = master.GetTrackedInventory(includeFromMinion); return Object.op_Implicit((Object)(object)trackedInventory); } public static bool HasIndex(this Inventory inventory, Index index) { switch (index.type) { case IndexType.Item: return inventory.GetItemCountEffective((ItemIndex)index.index) > 0; case IndexType.Equip: return inventory.HasEquipment((EquipmentIndex)index.index); case IndexType.SkillSlot: return true; case IndexType.Misc: return index.index > 0; case IndexType.Body: return true; default: log.warning($"Unknown index type {index.type} for HasIndex"); return false; } } public static int GetIndexItemCount(this Inventory inventory, Index index) { //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Invalid comparison between Unknown and I4 switch (index.type) { case IndexType.Item: return inventory.GetItemCountEffective((ItemIndex)index.index); case IndexType.Equip: { int num = 0; for (int i = 0; i < inventory._equipmentStateSlots.Length; i++) { for (int j = 0; j < inventory._equipmentStateSlots[i].Length; j++) { if ((int)inventory._equipmentStateSlots[i][j].equipmentIndex == index.index) { num++; } } } return num; } case IndexType.SkillSlot: return 1; case IndexType.Misc: return (index.index > 0) ? 1 : 0; case IndexType.Body: return 1; default: log.warning($"Unknown index type {index.type} for GetIndexItemCount"); return 0; } } internal static bool HasItem(this Inventory inventory, ItemIndex item) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) return inventory.GetItemCountEffective(item) > 0; } internal static float ArmorToDamage(CharacterBody body, float damage, float subtractArmor = 0f) { if (!Object.op_Implicit((Object)(object)body)) { return 0f; } float num = body.armor + body.healthComponent.adaptiveArmorValue - subtractArmor; float num2 = ((num >= 0f) ? (1f - num / (num + 100f)) : (2f - 100f / (100f - num))); return Mathf.Max(1f, damage * num2 - (float)(5 * body.healthComponent.itemCounts.armorPlate)); } internal static float GetDamageNoOverkill(this DamageReport damageReport) { return Mathf.Min(damageReport.damageDealt, damageReport.combinedHealthBeforeDamage); } internal static string Name(this ItemIndex index) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) ItemDef itemDef = ItemCatalog.GetItemDef(index); if (itemDef != null) { return Language.GetString(itemDef.nameToken); } return "Item.null"; } internal static string Name(this EquipmentIndex index) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) EquipmentDef equipmentDef = EquipmentCatalog.GetEquipmentDef(index); if (equipmentDef != null) { return Language.GetString(equipmentDef.nameToken); } return "Equip.null"; } internal static string Name(this BodyIndex index) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Invalid comparison between Unknown and I4 CharacterBody bodyPrefabBodyComponent = BodyCatalog.GetBodyPrefabBodyComponent(index); if (bodyPrefabBodyComponent != null) { return Language.GetString(bodyPrefabBodyComponent.baseNameToken); } if ((int)index == -1) { return "Body.None"; } return "Body.null"; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsNotNullRef(this ref Tracker tracker) { return !UnsafeUtils.IsNullRef<Tracker>(ref tracker); } } } namespace ItemStatistics.Networking { internal class BlastMessage { private readonly Index source_index; internal BlastAttackDamageInfo blastAttack; internal BlastMessage(in BlastAttackDamageInfo blastAttack) { //IL_001e: 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) source_index = blastAttack.source_inflictor.source_chain.source_index; this.blastAttack = blastAttack; } internal BlastMessage(NetworkReader reader) { source_index = Index.Deserialize(reader); ((BlastAttackDamageInfo)(ref blastAttack)).Read(reader); blastAttack.source_inflictor = new SourceInflictor(source_index); } internal static void Serialize(NetworkWriter writer, BlastMessage value) { Index.Serialize(writer, value.source_index); ((BlastAttackDamageInfo)(ref value.blastAttack)).Write(writer); } internal static BlastMessage Deserialize(NetworkReader reader) { return new BlastMessage(reader); } } internal readonly struct BulletMessage { internal readonly Index source_index; internal readonly byte[] buffer; private readonly uint buffer_length; internal BulletMessage(NetworkWriter bullet_writer, BulletAttack attack) { source_index = attack.source_inflictor.source_chain.source_index; buffer = bullet_writer.m_Buffer.m_Buffer; buffer_length = bullet_writer.m_Buffer.Position; } public BulletMessage(NetworkReader reader) { source_index = Index.Deserialize(reader); buffer = reader.ReadBytesAndSize(); buffer_length = (uint)buffer.Length; } internal static void Serialize(NetworkWriter writer, BulletMessage value) { Index.Serialize(writer, value.source_index); writer.WriteBytesAndSize(value.buffer, (int)value.buffer_length); } internal static BulletMessage Deserialize(NetworkReader reader) { return new BulletMessage(reader); } } [Hook] internal static class NetworkHooks { private delegate void BlastAttack_ClientReportDamage(in BlastAttackDamageInfo blastAttack); [StructLayout(LayoutKind.Sequential, Size = 1)] internal readonly struct OverlapSourceContext : IDisposable { private static readonly Stack<Index> contexts = new Stack<Index>(); internal static bool has_value { get { if (contexts.Count > 0) { return contexts.Peek().isNotNone; } return false; } } internal static Index current => contexts.Peek(); public OverlapSourceContext(Index index) { contexts.Push(index); } public void Dispose() { contexts.Pop(); } } internal static Action<NetworkReader, Index> modified_HandleBulletDamage; internal static Action<OverlapMessage> modified_HandleOverlapAttackHits; [Hook(typeof(BlastAttack), "ClientReportDamage")] private static void NetworkMessage_On_BlastAttack_ClientReportDamage(BlastAttack_ClientReportDamage orig, in BlastAttackDamageInfo blastAttack) { if (TrackModdedUsers.isModdedServer && blastAttack.source_inflictor != null) { TrackModdedUsers.localUser.CallCmdBlastAttack(new BlastMessage(in blastAttack)); } else { orig(in blastAttack); } } [Hook] private static void GenerateBulletDealDamage() { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Expected O, but got Unknown //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Expected O, but got Unknown //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Expected O, but got Unknown //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Expected O, but got Unknown //IL_0147: Unknown result type (might be due to invalid IL or missing references) //IL_0159: Unknown result type (might be due to invalid IL or missing references) //IL_0165: Unknown result type (might be due to invalid IL or missing references) //IL_0193: Unknown result type (might be due to invalid IL or missing references) DynamicMethodDefinition val = new DynamicMethodDefinition((MethodBase)HookManager.GetMethod(typeof(BulletAttack), "HandleBulletDamage")); try { ((ParameterReference)((MethodReference)val.Definition).Parameters[0]).ParameterType = val.Module.ImportReference(typeof(NetworkReader)); ((MethodReference)val.Definition).Parameters.Add(new ParameterDefinition(val.Module.ImportReference(typeof(Index)))); typeof(DynamicMethodDefinition).GetProperty("OriginalMethod").SetValue(val, null); ILContext val2 = new ILContext(val.Definition); try { ILCursor val3 = new ILCursor(val2); while (val3.TryGotoNext(new Func<Instruction, bool>[1] { (Instruction a) => ILPatternMatchingExt.MatchLdfld<NetworkMessage>(a, "reader") })) { val3.Remove(); } val3.Index = 0; VariableDefinition infovar = ((IEnumerable<VariableDefinition>)val2.Body.Variables).First((VariableDefinition a) => ((MemberReference)((VariableReference)a).VariableType).Name == "DamageInfo"); if (!val3.TryGotoNext((MoveType)2, new Func<Instruction, bool>[1] { (Instruction a) => ILPatternMatchingExt.MatchStloc(a, ((VariableReference)infovar).Index) })) { val3.LogErrorCaller("bullet networking"); return; } val3.Emit(OpCodes.Ldloc, infovar); val3.Emit(OpCodes.Ldarg_1); val3.Emit(OpCodes.Newobj, (MethodBase)typeof(SourceInflictor).GetConstructor(new Type[1] { typeof(Index) })); val3.Emit<DamageInfo>(OpCodes.Stfld, "source_inflictor"); } finally { ((IDisposable)val2)?.Dispose(); } modified_HandleBulletDamage = Extensions.CreateDelegate<Action<NetworkReader, Index>>((MethodBase)val.Generate()); } finally { ((IDisposable)val)?.Dispose(); } } [Hook(typeof(BulletAttack), "DefaultHitCallbackImplementation")] private static void NetworkSource_IL_BulletAttack_DefaultHitCallbackImplementation(ILContext il) { //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Expected O, but got Unknown //IL_00b8: 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_00d6: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: Unknown result type (might be due to invalid IL or missing references) //IL_00f3: Unknown result type (might be due to invalid IL or missing references) //IL_0100: Unknown result type (might be due to invalid IL or missing references) //IL_0111: Unknown result type (might be due to invalid IL or missing references) //IL_0130: Unknown result type (might be due to invalid IL or missing references) SourceHooks.PassSource_IL_Attack_OnArrival<DamageInfo>(il); if (modified_HandleBulletDamage == null) { log.error("failed to generate HandleBulletDamage, skipping bullet source networking"); return; } ILCursor val = new ILCursor(il); ILLabel branch_end = null; if (!val.TryGotoNext((MoveType)2, new Func<Instruction, bool>[2] { (Instruction a) => ILPatternMatchingExt.MatchCallOrCallvirt(a, typeof(ClientScene), "get_ready"), (Instruction a) => ILPatternMatchingExt.MatchBrfalse(a, ref branch_end) }) || !val.TryGotoNext((MoveType)2, new Func<Instruction, bool>[1] { (Instruction a) => ILPatternMatchingExt.MatchCallOrCallvirt<NetworkWriter>(a, "FinishMessage") })) { val.LogErrorCaller("bullet source networking"); return; } ILLabel val2 = val.MarkLabel(); val.MoveBeforeLabels(); val.Emit<TrackModdedUsers>(OpCodes.Ldsfld, "isModdedServer"); val.Emit(OpCodes.Brfalse, (object)val2); val.Emit(OpCodes.Ldarg_0); val.Emit<BulletAttack>(OpCodes.Ldfld, "source_inflictor"); val.Emit(OpCodes.Brfalse, (object)val2); val.Emit<BulletAttack>(OpCodes.Ldsfld, "messageWriter"); val.Emit(OpCodes.Ldarg_0); val.EmitDelegate<Action<NetworkWriter, BulletAttack>>((Action<NetworkWriter, BulletAttack>)SendBulletMessage); val.Emit(OpCodes.Br, (object)branch_end); static void SendBulletMessage(NetworkWriter writer, BulletAttack attack) { TrackModdedUsers.localUser.CallCmdBulletAttack(new BulletMessage(writer, attack)); } } [Hook] private static void GenerateOverlapDealDamage() { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Expected O, but got Unknown //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Expected O, but got Unknown //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Expected O, but got Unknown //IL_0103: Unknown result type
plugins/ItemStatistics.Unsafe.dll
Decompiled 5 months agousing System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.0.0.0")] [module: UnverifiableCode] namespace ItemStatistics; public static class UnsafeUtils { public unsafe static ref TValue GetValueRefOrNullRef<TKey, TValue>(this Dictionary<TKey, TValue> dictionary, TKey key) { int num = dictionary.FindEntry(key); if (num >= 0) { return ref dictionary._entries[num].value; } return ref Unsafe.AsRef<TValue>((void*)null); } public static DictionaryRefEntries<TKey, TValue> GetRefEntries<TKey, TValue>(this Dictionary<TKey, TValue> dictionary) { return new DictionaryRefEntries<TKey, TValue>(dictionary); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public unsafe static bool IsNullRef<T>(in T value) { return Unsafe.AsPointer<T>(ref Unsafe.AsRef<T>(ref value)) == null; } } public ref struct DictionaryRefEntries<TKey, TValue> { private readonly Dictionary<TKey, TValue> dictionary; private int current; public readonly ref TKey current_key => ref dictionary._entries[current - 1].key; public readonly ref TValue current_value => ref dictionary._entries[current - 1].value; public DictionaryRefEntries(Dictionary<TKey, TValue> dictionary) { this.dictionary = dictionary; current = 0; } public bool MoveNext() { while ((uint)current < (uint)dictionary._count) { if (dictionary._entries[current++].hashCode >= 0) { return true; } } current = dictionary._count - 1; return false; } }
patchers/ItemStatisticsPatcher.dll
Decompiled 5 months 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("0.0.0.0")] public static class ItemStatisticsPatcher { private static ManualLogSource _log; private static ManualLogSource log => _log ?? (_log = Logger.CreateLogSource("ItemStatisticsPatcher")); 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 //IL_00ee: Unknown result type (might be due to invalid IL or missing references) //IL_00f8: 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")); TypeReference fieldType3 = mainModule.ImportReference((TypeReference)(object)val.MainModule.GetType("ItemStatistics.SourceInflictor")); AddField(mainModule.GetType("RoR2.CharacterMaster"), fieldType, "trackedInventory").CustomAttributes.Add(new CustomAttribute(mainModule.ImportReference((MethodBase)typeof(NonSerializedAttribute).GetConstructor(Type.EmptyTypes)))); AddField(mainModule.GetType("RoR2.DotController/DotStack"), val2, "source_chain"); AddField(mainModule.GetType("RoR2.DotController/PendingDamage"), (TypeReference)(object)val3, "pendingDotChainList"); AddField(mainModule.GetType("RoR2.DamageInfo"), fieldType3, "source_inflictor"); AddField(mainModule.GetType("RoR2.BlastAttack"), fieldType3, "source_inflictor"); AddField(mainModule.GetType("RoR2.BlastAttack/BlastAttackDamageInfo"), fieldType3, "source_inflictor"); AddField(mainModule.GetType("RoR2.BulletAttack"), fieldType3, "source_inflictor"); AddField(mainModule.GetType("RoR2.DelayBlast"), fieldType3, "source_inflictor"); AddField(mainModule.GetType("RoR2.OverlapAttack"), fieldType3, "source_inflictor"); AddField(mainModule.GetType("RoR2.Orbs.GenericDamageOrb"), fieldType3, "source_inflictor"); AddField(mainModule.GetType("RoR2.Orbs.DevilOrb"), fieldType3, "source_inflictor"); AddField(mainModule.GetType("RoR2.Orbs.BounceOrb"), fieldType3, "source_inflictor"); AddField(mainModule.GetType("RoR2.Orbs.HealOrb"), fieldType2, "source_index"); AddField(mainModule.GetType("RoR2.Orbs.LightningOrb"), fieldType3, "source_inflictor"); AddField(mainModule.GetType("RoR2.Orbs.VoidLightningOrb"), fieldType3, "source_inflictor"); AddField(mainModule.GetType("EntityStates.Drone.DroneCopycat.LaserDiscOrb"), fieldType3, "source_inflictor"); AddField(mainModule.GetType("EntityStates.Drone.Command.CommandBombardment/BombardmentOrb"), fieldType3, "source_inflictor"); AddField(mainModule.GetType("EntityStates.FrozenState"), fieldType2, "freeze_source"); AddField(mainModule.GetType("EntityStates.FrozenState"), (TypeReference)(object)mainModule.GetType("RoR2.CharacterMaster"), "freeze_master"); AddField(mainModule.GetType("RoR2.Orbs.VineOrb/SplitDebuffInformation"), val2, "source_chain"); } private static FieldDefinition AddField(TypeDefinition target, TypeReference fieldType, string fieldName) { //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Expected O, but got Unknown if (target == null || fieldType == null) { log.LogError((object)("Null types in AddField: " + ((target != null) ? ((MemberReference)target).Name : null) + "." + fieldName)); return null; } TypeDefinition val = target; TypeReference baseType; do { if (((IEnumerable<FieldDefinition>)val.Fields).Any((FieldDefinition a) => ((MemberReference)a).Name == fieldName)) { log.LogWarning((object)(((MemberReference)target).Name + "." + fieldName + " already exists")); return null; } baseType = val.BaseType; } while ((val = ((baseType != null) ? baseType.Resolve() : null)) != null); FieldDefinition val2 = new FieldDefinition(fieldName, (FieldAttributes)6, fieldType); target.Fields.Add(val2); return val2; } }