Some mods may be broken due to the recent Alloyed Collective update.
Decompiled source of ItemStatistics v1.2.11
plugins/ItemStatistics.dll
Decompiled 4 days ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Generic; using System.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.11.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) { 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) { 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) { 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) { if (!Object.op_Implicit((Object)(object)a.Result.GetComponent<Comp>())) { a.Result.AddComponent<Comp>(); } }; } internal static void ModifyStateConfig(this EntityStateConfiguration stateConfig, string fieldName, object newValue) { SerializedField[] serializedFields = stateConfig.serializedFieldsCollection.serializedFields; for (int i = 0; i < serializedFields.Length; i++) { if (serializedFields[i].fieldName == fieldName) { Object val = (Object)((newValue is Object) ? newValue : null); if (val != null) { serializedFields[i].fieldValue.objectValue = val; } else if (newValue != null && StringSerializer.CanSerializeType(newValue.GetType())) { serializedFields[i].fieldValue.stringValue = StringSerializer.Serialize(newValue.GetType(), newValue); } else { log.error("Invalid value for SerializedField: " + newValue); } return; } } log.error("Failed to find " + fieldName + " for " + ((Object)stateConfig).name); } internal static bool IsKeyDown(this 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_owner; internal ContextData(TrackedInventory tracked, Inventory inventory) { tracked_inventory = tracked; this.inventory = inventory; has_tracked_inv = Object.op_Implicit((Object)(object)tracked); is_owner = 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_00ae: 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)obj == (Object)null)) { goto IL_00da; } } Index index = damageInfo.damageType.damageSource; return cached_chain = (index.isNotNone ? new ProcChain(index) : default(ProcChain)); } goto IL_00da; IL_00da: 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.11")] [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.11"; 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(source_chain.source_index.type != IndexType.SkillSlot, 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.total_when_set.i, trackedValue.value.i), "RATE" => TrackerStatics.RateToString(trackedValue.total_when_set.i, trackedValue.value.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 struct num32 { [FieldOffset(0)] internal uint i; [FieldOffset(0)] internal float f; public static implicit operator num32(uint i) { num32 result = default(num32); result.i = i; return result; } public static implicit operator num32(float f) { num32 result = default(num32); result.f = f; return result; } public static num32 operator +(num32 num, uint i) { num32 result = default(num32); result.i = num.i + i; return result; } public static num32 operator +(num32 num, float f) { num32 result = default(num32); result.f = num.f + f; return result; } } 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 attempted, uint succedded) { if (attempted == 0) { return "NaN"; } float num = 100f * (float)succedded / (float)attempted; return num.ToString((num < 10f) ? "f1" : "f0") + "%"; } internal static string RateToString(uint attempted, uint succedded) { 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 HasEquipment(inventory, (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 bool HasEquipment(Inventory inventory, EquipmentIndex index) { //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) for (int i = 0; i < inventory._equipmentStateSlots.Length; i++) { for (int j = 0; j < inventory._equipmentStateSlots[i].Length; j++) { if (inventory._equipmentStateSlots[i][j].equipmentIndex == index) { return true; } } } 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 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"; } } } 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 (might be due to invalid IL or missing references) //IL_0119: Unknown result type (might be due to invalid IL or missing references) DynamicMethodDefinition val = new DynamicMethodDefinition((MethodBase)HookManager.GetMethod(typeof(OverlapAttack), "HandleOverlapAttackHits")); try { ((ParameterReference)((MethodReference)val.Definition).Parameters[0]).ParameterType = val.Module.ImportReference(typeof(OverlapMessage)); typeof(DynamicMethodDefinition).GetProperty("OriginalMethod").SetValue(val, null); ILCont
plugins/ItemStatistics.Unsafe.dll
Decompiled 4 days 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.IgnoreSymbolStoreSequencePoints)] [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 4 days agousing System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Logging; using Mono.Cecil; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyVersion("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; } }