Decompiled source of BugreenBindingsSelected v11.14.0
BepInEx/plugins/BugreenBindingsSelected/BugreenBindingsSelected.dll
Decompiled 5 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.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Text; using BepInEx; using BepInEx.Logging; using HarmonyLib; using TrinketAndBindingFramework; using UnityEngine; using UnityEngine.AddressableAssets; using UnityEngine.AddressableAssets.ResourceLocators; using UnityEngine.Rendering; using UnityEngine.ResourceManagement.AsyncOperations; using UnityEngine.SceneManagement; using UnityEngine.UI; [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: CompilationRelaxations(8)] [assembly: AssemblyVersion("0.0.0.0")] namespace BugreenBindings; internal static class AssetService { private static MethodInfo _getPerk; private static MethodInfo _getItem; private static MethodInfo _getPrefab; private static MethodInfo _getTrinket; private static MethodInfo _getSprite; internal static bool Resolve() { if (_getPerk != null || _getItem != null || _getPrefab != null) { return true; } Type type = AccessTools.TypeByName("CL_AssetManager"); if (type == null) { WKLog.Warn("AssetService: CL_AssetManager not found."); return false; } _getPerk = type.GetMethod("GetPerkAsset", BindingFlags.Static | BindingFlags.Public); _getItem = type.GetMethod("GetItemObjectPrefab", BindingFlags.Static | BindingFlags.Public); _getPrefab = type.GetMethod("GetAssetGameObject", BindingFlags.Static | BindingFlags.Public); _getTrinket = type.GetMethod("GetTrinketAsset", BindingFlags.Static | BindingFlags.Public); _getSprite = type.GetMethod("GetSpriteAsset", BindingFlags.Static | BindingFlags.Public); WKLog.Info("AssetService: perk=" + (_getPerk != null) + " item=" + (_getItem != null) + " prefab=" + (_getPrefab != null) + " trinket=" + (_getTrinket != null)); if (!(_getPerk != null) && !(_getItem != null)) { return _getPrefab != null; } return true; } internal static GameObject GetPrefab(string name) { object obj = Invoke(_getPrefab, name); return (GameObject)((obj is GameObject) ? obj : null); } internal static Object GetItem(string name) { object obj = Invoke(_getItem, name); return (Object)((obj is Object) ? obj : null); } internal static Object GetPerk(string name) { object obj = Invoke(_getPerk, name); return (Object)((obj is Object) ? obj : null); } internal static Sprite GetSprite(string name) { object obj = Invoke(_getSprite, name); return (Sprite)((obj is Sprite) ? obj : null); } private static object Invoke(MethodInfo method, string name) { if (method == null || !Resolve()) { return null; } try { ParameterInfo[] parameters = method.GetParameters(); object[] array = new object[parameters.Length]; for (int i = 0; i < parameters.Length; i++) { if (parameters[i].ParameterType == typeof(string)) { array[i] = ((i == parameters.Length - 1) ? name : string.Empty); } else { array[i] = (parameters[i].ParameterType.IsValueType ? Activator.CreateInstance(parameters[i].ParameterType) : null); } } return method.Invoke(null, array); } catch (Exception ex) { WKLog.Warn("AssetService: " + method.Name + "(" + name + ") failed: " + ex.Message); return null; } } } internal class BackflipEffect : MonoBehaviour { private const float Duration = 0.55f; internal static BackflipEffect Instance; private ENT_Player _player; private Transform _cam; private bool _running; private float _start; private float _applied; private void Awake() { Instance = this; } internal void Begin(ENT_Player player) { _player = player; _cam = null; _running = false; _applied = 0f; if (!((Object)(object)player == (Object)null)) { FieldInfo field = typeof(ENT_Player).GetField("camTransform", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (field != null) { ref Transform cam = ref _cam; object? value = field.GetValue(player); cam = (Transform)((value is Transform) ? value : null); } WKLog.Info("Backflip: camera = " + (((Object)(object)_cam == (Object)null) ? "<none>" : ((Object)_cam).name)); } } internal void End() { Finish(); _player = null; } internal void TryStart() { if (!_running && !((Object)(object)_cam == (Object)null) && BindingState.IsActive("bugreen_backflip")) { _running = true; _start = Time.unscaledTime; _applied = 0f; } } private void Finish() { _running = false; _applied = 0f; } internal void ApplyFlip() { //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) if (_running && !((Object)(object)_cam == (Object)null)) { float num = (Time.unscaledTime - _start) / 0.55f; if (num >= 1f) { _running = false; _applied = 0f; return; } float num2 = num * num * (3f - 2f * num); float num3 = -360f * num2; _cam.rotation *= Quaternion.Euler(num3, 0f, 0f); _applied = num3; } } internal static void Apply(Harmony harmony) { //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Expected O, but got Unknown //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Expected O, but got Unknown try { MethodInfo methodInfo = AccessTools.Method("ENT_Player:Jump", (Type[])null, (Type[])null); if (methodInfo != null) { MethodInfo method = typeof(BackflipEffect).GetMethod("AfterJump", BindingFlags.Static | BindingFlags.NonPublic); harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(method), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); WKLog.Info("Backflip: patched ENT_Player.Jump."); } else { WKLog.Warn("Backflip: ENT_Player.Jump not found."); } MethodInfo methodInfo2 = AccessTools.Method("CL_CameraControl:LateUpdate", (Type[])null, (Type[])null); if (methodInfo2 != null) { MethodInfo method2 = typeof(BackflipEffect).GetMethod("AfterCameraUpdate", BindingFlags.Static | BindingFlags.NonPublic); harmony.Patch((MethodBase)methodInfo2, (HarmonyMethod)null, new HarmonyMethod(method2), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); WKLog.Info("Backflip: patched CL_CameraControl.LateUpdate."); } else { WKLog.Warn("Backflip: CL_CameraControl.LateUpdate not found."); } } catch (Exception ex) { WKLog.Warn("Backflip patch failed: " + ex.Message); } } private static void AfterJump() { if ((Object)(object)Instance != (Object)null) { Instance.TryStart(); } } private static void AfterCameraUpdate() { if ((Object)(object)Instance != (Object)null) { Instance.ApplyFlip(); } } } internal static class BadSupplyPatch { private class Saved { internal object Buff; internal bool HasBuff; internal List<object> Secondary = new List<object>(); internal object SecondaryList; internal float HealOriginal; internal bool HasHeal; } private static readonly Random Rng = new Random(); private static readonly Dictionary<object, Saved> Pending = new Dictionary<object, Saved>(); internal static void Apply(Harmony harmony) { //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Expected O, but got Unknown //IL_0066: Expected O, but got Unknown try { MethodInfo methodInfo = AccessTools.Method("HandItem_Buff:Use", (Type[])null, (Type[])null); if (methodInfo == null) { WKLog.Warn("BadSupply: HandItem_Buff.Use not found."); return; } MethodInfo method = typeof(BadSupplyPatch).GetMethod("BeforeUse", BindingFlags.Static | BindingFlags.NonPublic); MethodInfo method2 = typeof(BadSupplyPatch).GetMethod("AfterUse", BindingFlags.Static | BindingFlags.NonPublic); harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(method), new HarmonyMethod(method2), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); WKLog.Info("BadSupply: patched HandItem_Buff.Use."); } catch (Exception ex) { WKLog.Warn("BadSupply patch failed: " + ex.Message); } } private static void BeforeUse(object __instance) { if (!BindingState.IsActive("bugreen_bad_supply") || __instance == null) { return; } try { float num = (float)Rng.NextDouble(); bool flag = num < 0.2f; float num2 = (flag ? 0f : ((float)(0.3 + Rng.NextDouble() * 1.2))); float timeFactor = (flag ? 0.05f : ((float)(0.3 + Rng.NextDouble() * 1.5))); Saved saved = new Saved(); FieldInfo fieldInfo = Field(__instance, "healAmount", typeof(float)); if (fieldInfo != null) { float num3 = (float)fieldInfo.GetValue(__instance); if (num3 > 0f) { saved.HasHeal = true; saved.HealOriginal = num3; fieldInfo.SetValue(__instance, num3 * num2); } } FieldInfo fieldInfo2 = Field(__instance, "buff", null); if (fieldInfo2 != null) { object value = fieldInfo2.GetValue(__instance); if (value != null) { object obj = CopyContainer(value, num2, timeFactor); if (obj != null) { saved.HasBuff = true; saved.Buff = value; fieldInfo2.SetValue(__instance, obj); } } } FieldInfo fieldInfo3 = Field(__instance, "secondaryBuffs", null); if (fieldInfo3 != null && fieldInfo3.GetValue(__instance) is IList { Count: >0 } list && Activator.CreateInstance(fieldInfo3.FieldType) is IList list2) { for (int i = 0; i < list.Count; i++) { object obj2 = CopyContainer(list[i], num2, timeFactor); list2.Add(obj2 ?? list[i]); saved.Secondary.Add(list[i]); } saved.SecondaryList = list; fieldInfo3.SetValue(__instance, list2); } Pending[__instance] = saved; WKLog.Info("Bad Supply: effect x" + num2.ToString("0.00") + ", duration x" + timeFactor.ToString("0.00") + (flag ? " (no effect)" : "") + "."); } catch (Exception ex) { WKLog.Warn("BadSupply prefix failed: " + ex.Message); } } private static void AfterUse(object __instance) { if (__instance == null || !Pending.TryGetValue(__instance, out var value)) { return; } Pending.Remove(__instance); try { if (value.HasHeal) { FieldInfo fieldInfo = Field(__instance, "healAmount", typeof(float)); if (fieldInfo != null) { fieldInfo.SetValue(__instance, value.HealOriginal); } } if (value.HasBuff) { FieldInfo fieldInfo2 = Field(__instance, "buff", null); if (fieldInfo2 != null) { fieldInfo2.SetValue(__instance, value.Buff); } } if (value.SecondaryList != null) { FieldInfo fieldInfo3 = Field(__instance, "secondaryBuffs", null); if (fieldInfo3 != null) { fieldInfo3.SetValue(__instance, value.SecondaryList); } } } catch { } } private static object CopyContainer(object container, float factor, float timeFactor) { try { MethodInfo method = container.GetType().GetMethod("CopyBuffContainer", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (method == null) { return null; } object obj = method.Invoke(container, null); if (obj == null) { return null; } FieldInfo fieldInfo = Field(obj, "buffTime", typeof(float)); if (fieldInfo != null) { fieldInfo.SetValue(obj, (float)fieldInfo.GetValue(obj) * timeFactor); } FieldInfo fieldInfo2 = Field(obj, "buffs", null); IList list = ((fieldInfo2 == null) ? null : (fieldInfo2.GetValue(obj) as IList)); if (list != null) { for (int i = 0; i < list.Count; i++) { object obj2 = list[i]; if (obj2 != null) { Scale(obj2, "maxAmount", factor); Scale(obj2, "amount", factor); } } } return obj; } catch (Exception ex) { WKLog.Warn("BadSupply: container copy failed: " + ex.Message); return null; } } private static void Scale(object target, string fieldName, float factor) { FieldInfo fieldInfo = Field(target, fieldName, typeof(float)); if (fieldInfo != null) { fieldInfo.SetValue(target, (float)fieldInfo.GetValue(target) * factor); } } private static FieldInfo Field(object instance, string name, Type expected) { if (instance == null) { return null; } FieldInfo field = instance.GetType().GetField(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (field == null) { return null; } if (!(expected == null) && !(field.FieldType == expected)) { return null; } return field; } } internal static class BalancedDietEffect { internal static void Apply(Harmony harmony) { //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Expected O, but got Unknown //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Expected O, but got Unknown try { MethodInfo methodInfo = AccessTools.Method("PerkModule_HungerMeter:Initialize", (Type[])null, (Type[])null); if (methodInfo != null) { MethodInfo method = typeof(BalancedDietEffect).GetMethod("AfterInitialize", BindingFlags.Static | BindingFlags.NonPublic); harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(method), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } else { WKLog.Warn("Balanced Diet: PerkModule_HungerMeter.Initialize not found."); } MethodInfo methodInfo2 = AccessTools.Method("PerkModule_HungerMeter:OnConsume", (Type[])null, (Type[])null); if (methodInfo2 != null) { MethodInfo method2 = typeof(BalancedDietEffect).GetMethod("BeforeConsume", BindingFlags.Static | BindingFlags.NonPublic); harmony.Patch((MethodBase)methodInfo2, new HarmonyMethod(method2), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } else { WKLog.Warn("Balanced Diet: PerkModule_HungerMeter.OnConsume not found."); } WKLog.Info("Balanced Diet: hunger accepts only food bar, milk and fruit."); } catch (Exception ex) { WKLog.Warn("Balanced Diet patch failed: " + ex.Message); } } private static void AfterInitialize(object __instance) { try { if (!BindingState.IsActive("bugreen_balanced_diet") || __instance == null) { return; } FieldInfo field = __instance.GetType().GetField("consumeBuffIDs", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); IList list = ((field == null) ? null : (field.GetValue(__instance) as IList)); if (list == null) { return; } int num = 0; for (int num2 = list.Count - 1; num2 >= 0; num2--) { string type = list[num2] as string; if (!Allowed(type)) { list.RemoveAt(num2); num++; } } WKLog.Info("Balanced Diet: hunger consume list filtered, removed " + num + " type(s)."); } catch (Exception ex) { WKLog.Warn("Balanced Diet filter failed: " + ex.Message); } } private static bool BeforeConsume(string type) { if (!BindingState.IsActive("bugreen_balanced_diet")) { return true; } if (Allowed(type)) { return true; } WKLog.Info("Balanced Diet: refused hunger restore from '" + type + "'."); return false; } private static bool Allowed(string type) { if (string.IsNullOrEmpty(type)) { return false; } string text = type.ToLowerInvariant(); if (!text.Contains("food") && !text.Contains("milk")) { return text.Contains("fruit"); } return true; } } internal static class BindingDefs { public static readonly BindingDef[] All = new BindingDef[11] { new BindingDef("bugreen_old_bones", "Old Bones", "You cannot move that fast than before.", "", "- reduces your walking/running speed when grounded by -25%\n- reduces your jump height by -15%\n+ increases your climbing speed by 10%", 1.5f, "Binding_Icon_Old_Bones.png"), new BindingDef("bugreen_one_hand", "One Hand", "You have only one hand now.", "Now I see which hand you always use for gooning.", "- Having only one hand now.\n+ Increases stamina by 30%\n+ Increases climbing speed by 20%", 3f, "Binding_Icon_Onehand.png"), new BindingDef("bugreen_timeflies", "Timeflies", "Timespeed go faster by 20%.", "The timepiece must be broken.", "- Timespeed go faster by 20%", 3f, "Binding_Icon_Timeflies.png"), new BindingDef("bugreen_take_a_slice", "Take A Slice", "You cannot choose sharing food with who.", "IT SMELLS TOO.", "- Reduces all abilities and buffs by -10%\n- Increases all Mass forms when consume a food item by 1%", 1.75f, "Binding_Icon_Take_A_Slice.png"), new BindingDef("bugreen_darkness", "Darkness", "Electricity in Superstructure went off.", "Hope you do not fear the dark.", "- Removes lights from electric devices\n+ Get a flashlight", 1.4f, "Binding_Icon_Darkness.png"), new BindingDef("bugreen_pacifism", "Pacifism", "No weapons and tools.", "", "No weapons and tools.", 1.25f, "Binding_Icon_Pacifism.png"), new BindingDef("bugreen_fragile", "Fragile", "-60% player health.", "Watch your steps.", "- Reduces player health by -60%\n- Treat the Grubs well", 2.5f, "Binding_Icon_Fragile.png"), new BindingDef("bugreen_gold_rush", "Gold Rush", "No valuable roaches.", "Having a million expects you.", "No valuable roaches.", 1.1f, "Binding_Icon_Gold_Rush.png"), new BindingDef("bugreen_echo", "Echo", "All denizens are invisible.", "Watch your steps.", "- All denizens are invisible\n+ sounds from denizens are louder\n+ Get a scanner", 4f, "Binding_Icon_Echo.png"), new BindingDef("bugreen_delusions", "Delusions", "You lost the ability to recognize things.", "FOR A RHOST CHICKEN.", "cannot recognize items.", 1.75f, "Binding_Icon_Delusions.png"), new BindingDef("bugreen_light_from_the_violet", "Light From The Violet", "Close your eyes when the lights on.", "You can cover your eyes. But always useless.", "Close your eyes when the lights on.\n- Light from above will burn your eyes\n- Reduces your walking/running speed by -70% when look up", 2.5f, "Binding_Icon_Light_From_The_Violet.png") }; } internal static class BindingState { private static readonly HashSet<string> ActiveIds = new HashSet<string>(StringComparer.OrdinalIgnoreCase); private static readonly HashSet<string> ActiveTitles = new HashSet<string>(StringComparer.OrdinalIgnoreCase); private static readonly Dictionary<string, string> TitleById = new Dictionary<string, string>(); private static MethodInfo _isSelected; private static bool _registryQueryFailed; internal static int ActiveCount => ActiveIds.Count + ActiveTitles.Count; internal static void Init() { for (int i = 0; i < BindingDefs.All.Length; i++) { BindingDef bindingDef = BindingDefs.All[i]; TitleById[bindingDef.Id] = bindingDef.Title; } ResolveRegistry(); } private static void ResolveRegistry() { try { _isSelected = typeof(TrinketRegistry).GetMethod("IsSelected", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); WKLog.Info("BindingState: TrinketRegistry.IsSelected = " + (_isSelected != null)); } catch (Exception ex) { WKLog.Warn("BindingState: registry lookup failed: " + ex.Message); } } internal static void RefreshFromPicker(object __instance) { if (__instance != null) { ActiveTitles.Clear(); _registryQueryFailed = false; QueryById(__instance); QueryByTitle(__instance); WKLog.Info("Selected bindings: " + Describe()); } } private static void QueryById(object picker) { if (_isSelected == null) { ResolveRegistry(); } if (_isSelected == null) { return; } for (int i = 0; i < BindingDefs.All.Length; i++) { BindingDef bindingDef = BindingDefs.All[i]; try { object obj = _isSelected.Invoke(null, new object[2] { picker, bindingDef.Id }); if (obj is bool && (bool)obj) { ActiveIds.Add(bindingDef.Id); } } catch (Exception ex) { if (!_registryQueryFailed) { _registryQueryFailed = true; WKLog.Warn("BindingState: IsSelected(" + bindingDef.Id + ") failed: " + ex.Message); } } } } private static void QueryByTitle(object picker) { try { FieldInfo field = picker.GetType().GetField("selectedTrinkets", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (field == null || !(field.GetValue(picker) is IEnumerable enumerable)) { return; } foreach (object item in enumerable) { string text = ReadTitle(item); if (!string.IsNullOrEmpty(text)) { ActiveTitles.Add(text); } } } catch (Exception ex) { WKLog.Warn("BindingState: title fallback failed: " + ex.Message); } } private static string ReadTitle(object trinket) { if (trinket == null) { return null; } FieldInfo field = trinket.GetType().GetField("title", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (field != null) { object value = field.GetValue(trinket); if (value is string) { return (string)value; } } Object val = (Object)((trinket is Object) ? trinket : null); if (!(val != (Object)null)) { return null; } return val.name; } internal static void SetIds(IEnumerable<string> ids) { HashSet<string> hashSet = new HashSet<string>(StringComparer.OrdinalIgnoreCase); if (ids != null) { foreach (string id in ids) { if (!string.IsNullOrEmpty(id)) { hashSet.Add(id); } } } bool flag = hashSet.Count != ActiveIds.Count; if (!flag) { foreach (string item in hashSet) { if (!ActiveIds.Contains(item)) { flag = true; break; } } } ActiveIds.Clear(); foreach (string item2 in hashSet) { ActiveIds.Add(item2); } if (flag) { WKLog.Info("BindingState: selection now has " + ActiveIds.Count + " id(s): " + Describe() + "."); } } internal static bool IsActive(string id) { if (ActiveIds.Contains(id)) { return true; } if (TitleById.TryGetValue(id, out var value)) { return ActiveTitles.Contains(value); } return false; } internal static string Describe() { if (ActiveIds.Count > 0) { return "ids: " + string.Join(", ", new List<string>(ActiveIds).ToArray()); } if (ActiveTitles.Count > 0) { return "titles: " + string.Join(", ", new List<string>(ActiveTitles).ToArray()); } return "(none)"; } } internal static class BuffAudit { private static readonly string[] Ids = new string[14] { "addSpeed", "addGroundedSpeed", "addJump", "addClimb", "addStamina", "addStaminaRegen", "divideStamina", "addGripStrength", "damageResist", "addGravity", "addReach", "slowTime", "freezing", "massSpeedMult" }; internal static void LogRunBuffs(ENT_Player player) { if ((Object)(object)player == (Object)null) { return; } try { StringBuilder stringBuilder = new StringBuilder(); for (int i = 0; i < Ids.Length; i++) { float num = BuffService.Read((GameEntity)(object)player, Ids[i]); if (!float.IsNaN(num) && !(Math.Abs(num) < 0.0001f)) { if (stringBuilder.Length > 0) { stringBuilder.Append(", "); } stringBuilder.Append(Ids[i]).Append("=").Append(num.ToString("0.###")); } } WKLog.Info("Buff audit: " + ((stringBuilder.Length == 0) ? "(no binding buffs)" : stringBuilder.ToString()) + "."); } catch (Exception ex) { WKLog.Warn("Buff audit failed: " + ex.Message); } } } internal static class BuffIds { public const string AddSpeed = "addSpeed"; public const string AddGroundedSpeed = "addGroundedSpeed"; public const string DivideSpeed = "divideSpeed"; public const string AddSlow = "addSlow"; public const string AddJump = "addJump"; public const string AddJumpBoost = "addJumpBoost"; public const string AddExtraJumps = "addExtraJumps"; public const string AddClimb = "addClimb"; public const string AddGravity = "addGravity"; public const string AddReach = "addReach"; public const string AddStamina = "addStamina"; public const string AddStaminaRegen = "addStaminaRegen"; public const string DivideStamina = "divideStamina"; public const string AddGripStrength = "addGripStrength"; public const string LimitGripStrength = "limitGripStrength"; public const string GripResist = "gripResist"; public const string DamageResist = "damageResist"; public const string MassSpeedMult = "massSpeedMult"; public const string SlowTime = "slowTime"; public const string Freezing = "freezing"; } internal static class BuffService { private static Type _containerType; private static Type _buffType; private static FieldInfo _curBuffsField; private static FieldInfo _containerBuffs; private static FieldInfo _containerId; private static FieldInfo _containerDesc; private static FieldInfo _containerTime; private static FieldInfo _containerLoseOverTime; private static FieldInfo _containerMultiplier; private static FieldInfo _buffId; private static FieldInfo _buffAmount; private static FieldInfo _buffMax; private static MethodInfo _addBuff; private static MethodInfo _removeById; internal static bool Resolve() { if (_addBuff != null) { return true; } _containerType = AccessTools.TypeByName("BuffContainer"); if (_containerType != null) { _buffType = _containerType.GetNestedType("Buff", BindingFlags.Public | BindingFlags.NonPublic); } _curBuffsField = FindField(typeof(GameEntity), "curBuffs"); if (_containerType == null || _buffType == null || _curBuffsField == null) { WKLog.Warn("BuffService: types not resolved (container=" + (_containerType != null) + ", buff=" + (_buffType != null) + ", curBuffs=" + (_curBuffsField != null) + ")."); return false; } _containerBuffs = Field(_containerType, "buffs"); _containerId = Field(_containerType, "id"); _containerDesc = Field(_containerType, "desc"); _containerTime = Field(_containerType, "buffTime"); _containerLoseOverTime = Field(_containerType, "loseOverTime"); _containerMultiplier = Field(_containerType, "multiplier"); _buffId = Field(_buffType, "id"); _buffAmount = Field(_buffType, "amount"); _buffMax = Field(_buffType, "maxAmount"); Type fieldType = _curBuffsField.FieldType; _addBuff = fieldType.GetMethod("AddOrResetBuff", new Type[1] { _containerType }) ?? fieldType.GetMethod("AddBuff", new Type[1] { _containerType }); _removeById = fieldType.GetMethod("RemoveBuffContainer", new Type[1] { typeof(string) }); WKLog.Info("BuffService: ready (add=" + (_addBuff != null) + ", remove=" + (_removeById != null) + ")."); return _addBuff != null; } internal static void Apply(GameEntity entityTarget, string containerId, string[] ids, float[] amounts, float duration) { if ((Object)(object)entityTarget == (Object)null || !Resolve()) { return; } try { object value = _curBuffsField.GetValue(entityTarget); if (value == null) { return; } object obj = Activator.CreateInstance(_containerType); Set(obj, _containerId, containerId); Set(obj, _containerDesc, "Bugreen binding"); Set(obj, _containerTime, duration); Set(obj, _containerLoseOverTime, false); Set(obj, _containerMultiplier, 1f); IList list = _containerBuffs.GetValue(obj) as IList; if (list == null) { list = Activator.CreateInstance(_containerBuffs.FieldType) as IList; _containerBuffs.SetValue(obj, list); } StringBuilder stringBuilder = new StringBuilder(); for (int i = 0; i < ids.Length && i < amounts.Length; i++) { object obj2 = Activator.CreateInstance(_buffType); Set(obj2, _buffId, ids[i]); Set(obj2, _buffAmount, amounts[i]); Set(obj2, _buffMax, amounts[i]); list.Add(obj2); if (i > 0) { stringBuilder.Append(", "); } stringBuilder.Append(ids[i]).Append('=').Append(amounts[i]); } if (_removeById != null) { _removeById.Invoke(value, new object[1] { containerId }); } _addBuff.Invoke(value, new object[1] { obj }); WKLog.Info(string.Concat("Buff: ", containerId, " [", stringBuilder, "] for ", duration, "s.")); float num = ReadBack(value, (ids.Length > 0) ? ids[0] : null); WKLog.Info("Buff verify: " + containerId + " -> GetBuff(" + ((ids.Length > 0) ? ids[0] : "?") + ") = " + num + "."); } catch (Exception ex) { WKLog.Warn("BuffService apply failed: " + ex.Message); } } internal static float Read(GameEntity target, string id) { if ((Object)(object)target == (Object)null || !Resolve()) { return float.NaN; } try { object value = _curBuffsField.GetValue(target); return ReadBack(value, id); } catch { return float.NaN; } } private static float ReadBack(object entityBuff, string id) { if (entityBuff == null || string.IsNullOrEmpty(id)) { return float.NaN; } try { MethodInfo method = entityBuff.GetType().GetMethod("GetBuff", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[1] { typeof(string) }, null); if (method == null) { return float.NaN; } return (float)method.Invoke(entityBuff, new object[1] { id }); } catch { return float.NaN; } } internal static void Remove(GameEntity entityTarget, string containerId) { try { if (!((Object)(object)entityTarget == (Object)null) && Resolve() && !(_removeById == null)) { object value = _curBuffsField.GetValue(entityTarget); if (value != null) { _removeById.Invoke(value, new object[1] { containerId }); WKLog.Info("Buff: removed " + containerId); } } } catch { } } private static FieldInfo Field(Type type, string name) { return type.GetField(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); } private static FieldInfo FindField(Type type, string name) { Type type2 = type; while (type2 != null) { FieldInfo field = type2.GetField(name, BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (field != null) { return field; } type2 = type2.BaseType; } return null; } private static void Set(object target, FieldInfo field, object value) { if (target != null && field != null && value != null && field.FieldType.IsInstanceOfType(value)) { field.SetValue(target, value); } } } internal static class ClimbSpeedPatch { internal static void Apply(Harmony harmony) { //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Expected O, but got Unknown try { MethodInfo methodInfo = null; int num = 0; Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); foreach (Assembly assembly in assemblies) { if (assembly.IsDynamic) { continue; } Type[] types; try { types = assembly.GetTypes(); } catch { continue; } for (int j = 0; j < types.Length; j++) { MethodInfo[] methods; try { methods = types[j].GetMethods(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); } catch { continue; } foreach (MethodInfo methodInfo2 in methods) { if (!(methodInfo2.Name != "GetClimbMult") && !(methodInfo2.ReturnType != typeof(float))) { num++; if (!(methodInfo != null)) { MethodInfo method = typeof(ClimbSpeedPatch).GetMethod("Postfix", BindingFlags.Static | BindingFlags.NonPublic); harmony.Patch((MethodBase)methodInfo2, (HarmonyMethod)null, new HarmonyMethod(method), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); methodInfo = methodInfo2; } } } } } if (methodInfo == null) { WKLog.Warn("GetClimbMult not found; Old Bones climb bonus disabled."); return; } WKLog.Info("Patched climb multiplier: " + methodInfo.DeclaringType.FullName + "." + methodInfo.Name + " (candidates: " + num + ")"); } catch (Exception ex) { WKLog.Warn("ClimbSpeedPatch failed: " + ex.Message); } } private static void Postfix(ref float __result) { if (VioletOrb.ClimbPenalty) { __result *= 0.3f; } } } internal class CounterDisplay : MonoBehaviour { private Component _counter; private PropertyInfo _textProperty; private string _bindingId; internal void Setup(Component counter, string bindingId) { _counter = counter; _bindingId = bindingId; if ((Object)(object)counter != (Object)null) { _textProperty = ((object)counter).GetType().GetProperty("text"); } UpdateText(); } private void Update() { UpdateText(); } private void UpdateText() { if ((Object)(object)_counter == (Object)null || _textProperty == null || (Object)(object)RunTimers.Instance == (Object)null) { return; } float num = ((_bindingId == "bugreen_candle_queen") ? RunTimers.Instance.CandleTimer : RunTimers.Instance.DeathTimer); if (num < 0f) { return; } int num2 = Mathf.Max(0, Mathf.CeilToInt(num)); string value = (num2 / 60).ToString("00") + ":" + (num2 % 60).ToString("00"); try { _textProperty.SetValue(_counter, value, null); } catch { } } } internal static class CounterPatch { internal static void Apply(Harmony harmony) { //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Expected O, but got Unknown try { MethodInfo methodInfo = AccessTools.Method("Perk:GetPerkModuleCounterText", (Type[])null, (Type[])null); if (methodInfo == null) { WKLog.Warn("Counter: Perk.GetPerkModuleCounterText not found."); return; } MethodInfo method = typeof(CounterPatch).GetMethod("AfterGet", BindingFlags.Static | BindingFlags.NonPublic); harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(method), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); WKLog.Info("Counter: patched Perk.GetPerkModuleCounterText."); } catch (Exception ex) { WKLog.Warn("Counter patch failed: " + ex.Message); } } private static void AfterGet(object __instance, ref string __result) { try { if (__instance == null || (Object)(object)RunTimers.Instance == (Object)null) { return; } string text = ReadId(__instance); float num; if (text == "bugreen_candle_queen") { num = RunTimers.Instance.CandleTimer; } else { if (!(text == "bugreen_the_day_we_died")) { return; } num = RunTimers.Instance.DeathTimer; } if (!(num < 0f)) { int num2 = (int)Math.Ceiling(num); if (num2 < 0) { num2 = 0; } string text2 = (num2 / 60).ToString("00") + ":" + (num2 % 60).ToString("00"); __result = "<color=#FF4040>" + text2 + "</color>"; } } catch (Exception ex) { WKLog.Warn("Counter value failed: " + ex.Message); } } private static string ReadId(object perk) { FieldInfo field = perk.GetType().GetField("id", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (!(field == null)) { return field.GetValue(perk) as string; } return null; } } internal class DarknessEffect : MonoBehaviour { internal static DarknessEffect Instance; private GameObject _flashlightObject; private bool _active; private Color _originalAmbient; private float _originalAmbientIntensity; private float _originalReflection; private AmbientMode _originalAmbientMode; private Light _originalSun; private LightmapData[] _originalLightmaps; private int _originalPixelLights = 4; private float _nextScan; private Light[] _lights; private Type _lampType; private float _nextRefresh; private bool _lampScanNeeded = true; internal bool Active => _active; private void Awake() { Instance = this; } internal void Begin(ENT_Player player) { //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) if (_active || !BindingState.IsActive("bugreen_darkness")) { return; } try { _active = true; _originalAmbient = RenderSettings.ambientLight; _originalAmbientIntensity = RenderSettings.ambientIntensity; _originalReflection = RenderSettings.reflectionIntensity; _originalAmbientMode = RenderSettings.ambientMode; _originalSun = RenderSettings.sun; _originalLightmaps = LightmapSettings.lightmaps; RenderSettings.ambientMode = (AmbientMode)3; RenderSettings.ambientLight = Color.black; RenderSettings.ambientIntensity = 0f; RenderSettings.reflectionIntensity = 0f; RenderSettings.sun = null; LightmapSettings.lightmaps = (LightmapData[])(object)new LightmapData[0]; try { _originalPixelLights = QualitySettings.pixelLightCount; QualitySettings.pixelLightCount = Mathf.Max(8, _originalPixelLights); } catch { } AttachFlashlight(); _lights = null; _lampScanNeeded = true; EnforceLighting(); WKLog.Info("Darkness: lightmaps cleared (" + ((_originalLightmaps != null) ? _originalLightmaps.Length : 0) + "), sun removed, scene lights disabled, custom flashlight attached."); } catch (Exception ex) { WKLog.Warn("Darkness failed: " + ex.Message); } } private static bool IsPlayerOrCameraOwned(Transform transform) { //IL_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_00d3: Unknown result type (might be due to invalid IL or missing references) //IL_00d5: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: Unknown result type (might be due to invalid IL or missing references) //IL_00e4: Unknown result type (might be due to invalid IL or missing references) //IL_00e9: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)transform == (Object)null) { return false; } ENT_Player player = ENT_Player.GetPlayer(); if ((Object)(object)player != (Object)null) { if (transform.IsChildOf(((Component)player).transform)) { return true; } Transform[] array = (Transform[])(object)new Transform[4] { ReadTransform(player, "camTransform"), ReadTransform(player, "inventoryHandRoot"), ReadTransform(player, "camRoot"), ReadTransform(player, "effectsRoot") }; for (int i = 0; i < array.Length; i++) { if ((Object)(object)array[i] != (Object)null && transform.IsChildOf(array[i])) { return true; } } } Camera[] allCameras = Camera.allCameras; for (int j = 0; j < allCameras.Length; j++) { if ((Object)(object)allCameras[j] != (Object)null && transform.IsChildOf(((Component)allCameras[j]).transform)) { return true; } } Vector3 val = PlayerPosition(); if (val != Vector3.zero && Vector3.Distance(transform.position, val) < 3f) { return true; } Transform val2 = transform; while ((Object)(object)val2 != (Object)null) { string text = ((Object)((Component)val2).gameObject).name.ToLowerInvariant(); if (text.Contains("flashlight") || text.Contains("headlamp") || text.Contains("lantern") || text.Contains("handitem") || text.Contains("hand_light") || text.Contains("bugreenflashlight")) { return true; } val2 = val2.parent; } return false; } private static Vector3 PlayerPosition() { //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) ENT_Player player = ENT_Player.GetPlayer(); if ((Object)(object)player == (Object)null) { return Vector3.zero; } Transform val = ReadTransform(player, "camTransform"); if (!((Object)(object)val != (Object)null)) { return ((Component)player).transform.position; } return val.position; } private static Transform ReadTransform(ENT_Player player, string fieldName) { FieldInfo field = typeof(ENT_Player).GetField(fieldName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (field == null) { return null; } object value = field.GetValue(player); Component val = (Component)((value is Component) ? value : null); if ((Object)(object)val != (Object)null) { return val.transform; } return (Transform)((value is Transform) ? value : null); } private void AttachFlashlight() { //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Expected O, but got Unknown //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Unknown result type (might be due to invalid IL or missing references) //IL_0112: Unknown result type (might be due to invalid IL or missing references) //IL_0172: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_flashlightObject != (Object)null) { return; } Transform val = null; ENT_Player player = ENT_Player.GetPlayer(); if ((Object)(object)player != (Object)null) { FieldInfo field = typeof(ENT_Player).GetField("camTransform", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (field != null) { object? value = field.GetValue(player); val = (Transform)((value is Transform) ? value : null); } } if ((Object)(object)val == (Object)null) { Camera main = Camera.main; if ((Object)(object)main == (Object)null) { return; } val = ((Component)main).transform; } _flashlightObject = new GameObject("BugreenFlashlight"); _flashlightObject.transform.SetParent(val, false); _flashlightObject.transform.localPosition = new Vector3(0.08f, -0.08f, 0.15f); _flashlightObject.transform.localRotation = Quaternion.identity; Light val2 = _flashlightObject.AddComponent<Light>(); val2.type = (LightType)0; val2.range = 100f; val2.spotAngle = 80f; val2.intensity = 8f; val2.color = new Color(1f, 0.97f, 0.9f); val2.shadows = (LightShadows)0; val2.renderMode = (LightRenderMode)1; ((Behaviour)val2).enabled = true; Light val3 = _flashlightObject.AddComponent<Light>(); val3.type = (LightType)2; val3.range = 8f; val3.intensity = 2f; val3.color = new Color(1f, 0.95f, 0.85f); val3.shadows = (LightShadows)0; val3.renderMode = (LightRenderMode)1; ((Behaviour)val3).enabled = true; WKLog.Info("Darkness: custom flashlight attached to " + ((Object)val).name + "."); } private void DisableLights() { //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Invalid comparison between Unknown and I4 //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Invalid comparison between Unknown and I4 //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Invalid comparison between Unknown and I4 if (_lights == null || Time.unscaledTime >= _nextRefresh) { _nextRefresh = Time.unscaledTime + 5f; _lights = Object.FindObjectsOfType<Light>(); } int num = 0; for (int i = 0; i < _lights.Length; i++) { Light val = _lights[i]; if (!((Object)(object)val == (Object)null) && ((Behaviour)val).enabled && !((Object)(object)((Component)val).gameObject == (Object)(object)_flashlightObject) && !IsPlayerOrCameraOwned(((Component)val).transform) && ((int)val.type == 1 || (int)val.type == 2 || (int)val.type == 0 || (int)val.type == 3)) { ((Behaviour)val).enabled = false; num++; } } if (_lampScanNeeded) { ScanLampsOnce(); } if (num > 0) { WKLog.Info("Darkness: disabled " + num + " newly enabled light(s)."); } } private void ScanLampsOnce() { _lampScanNeeded = false; try { _lampType = AccessTools.TypeByName("CL_Lamp"); if (_lampType == null) { return; } Object[] array = Object.FindObjectsOfType(_lampType); int num = 0; foreach (Object obj in array) { Component val = (Component)(object)((obj is Component) ? obj : null); if (!((Object)(object)val == (Object)null) && !IsPlayerOrCameraOwned(val.transform)) { SetField(val, _lampType, "lampActive", false); SetField(val, _lampType, "intensity", 0f); SetField(val, _lampType, "emissiveMult", 0f); num++; } } WKLog.Info("Darkness: switched off " + num + " active lamp(s)."); } catch (Exception ex) { WKLog.Warn("Darkness lamps failed: " + ex.Message); } } private static void SetField(object target, Type type, string name, object value) { FieldInfo field = type.GetField(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (field != null && value != null && field.FieldType.IsInstanceOfType(value)) { field.SetValue(target, value); } } private void EnforceLighting() { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) try { RenderSettings.ambientMode = (AmbientMode)3; RenderSettings.ambientLight = Color.black; RenderSettings.ambientIntensity = 0f; RenderSettings.reflectionIntensity = 0f; RenderSettings.sun = null; RenderSettings.fog = false; RenderSettings.fogDensity = 0f; RenderSettings.fogColor = Color.black; if (LightmapSettings.lightmaps.Length > 0) { LightmapSettings.lightmaps = (LightmapData[])(object)new LightmapData[0]; } Camera main = Camera.main; if ((Object)(object)main != (Object)null) { main.clearFlags = (CameraClearFlags)2; main.backgroundColor = Color.black; } DisableLights(); } catch (Exception ex) { WKLog.Warn("Darkness enforce failed: " + ex.Message); } } internal static void EnforceFromPatch() { if ((Object)(object)Instance != (Object)null && Instance.Active) { Instance._lights = null; Instance._lampScanNeeded = true; Instance.EnforceLighting(); } } internal static void ZeroLampFromPatch(Component lamp) { if (!((Object)(object)Instance == (Object)null) && Instance.Active && !((Object)(object)lamp == (Object)null) && !IsPlayerOrCameraOwned(lamp.transform)) { SetField(lamp, ((object)lamp).GetType(), "lampActive", false); SetField(lamp, ((object)lamp).GetType(), "intensity", 0f); SetField(lamp, ((object)lamp).GetType(), "emissiveMult", 0f); } } private void Update() { if (!_active) { return; } try { if (Time.unscaledTime >= _nextScan) { _nextScan = Time.unscaledTime + 0.5f; EnforceLighting(); } if ((Object)(object)_flashlightObject == (Object)null) { AttachFlashlight(); return; } Light component = _flashlightObject.GetComponent<Light>(); if ((Object)(object)component != (Object)null && !((Behaviour)component).enabled) { ((Behaviour)component).enabled = true; } } catch (Exception ex) { WKLog.Warn("Darkness update failed: " + ex.Message); _active = false; } } internal void End() { //IL_0008: 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) _active = false; try { RenderSettings.ambientMode = _originalAmbientMode; RenderSettings.ambientLight = _originalAmbient; RenderSettings.ambientIntensity = _originalAmbientIntensity; RenderSettings.reflectionIntensity = _originalReflection; RenderSettings.sun = _originalSun; if (_originalLightmaps != null && _originalLightmaps.Length > 0) { LightmapSettings.lightmaps = _originalLightmaps; } try { QualitySettings.pixelLightCount = _originalPixelLights; } catch { } } catch { } if ((Object)(object)_flashlightObject != (Object)null) { Object.Destroy((Object)(object)_flashlightObject); _flashlightObject = null; } } } internal static class DarknessPatches { internal static void Apply(Harmony harmony) { TryPatch("CL_Lamp:OnEnable", "AfterLampEnable"); TryPatch("M_Level:OnSpawn", "AfterLevelSpawn"); } private static void TryPatch(string target, string postfixName) { //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Expected O, but got Unknown //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Expected O, but got Unknown try { MethodInfo methodInfo = AccessTools.Method(target, (Type[])null, (Type[])null); if (methodInfo == null) { WKLog.Warn("Darkness: " + target + " not found."); return; } MethodInfo method = typeof(DarknessPatches).GetMethod(postfixName, BindingFlags.Static | BindingFlags.NonPublic); if (!(method == null)) { Harmony val = new Harmony("bugreen.bindings.selected.darkness"); val.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(method), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); WKLog.Info("Darkness: patched " + target + "."); } } catch (Exception ex) { WKLog.Warn("Darkness patch " + target + " failed: " + ex.Message); } } private static void AfterLampEnable(object __instance) { Component val = (Component)((__instance is Component) ? __instance : null); if ((Object)(object)val != (Object)null) { DarknessEffect.ZeroLampFromPatch(val); } } private static void AfterLevelSpawn() { DarknessEffect.EnforceFromPatch(); } } internal class DelusionsEffect : MonoBehaviour { private class ItemVisual { internal Sprite Sprite; internal Item_Object Asset; internal HandItem HandItem; internal Item_Object Drop; } private class Snap { internal readonly List<Sprite> Sprites = new List<Sprite>(); internal readonly List<Texture> Textures = new List<Texture>(); internal readonly List<Mesh> Meshes = new List<Mesh>(); } private class Visual { internal string Key; internal GameObject Root; internal readonly List<Renderer> Renderers = new List<Renderer>(); internal readonly List<SpriteRenderer> Sprites = new List<SpriteRenderer>(); internal readonly List<Renderer> Meshes = new List<Renderer>(); internal readonly List<MeshFilter> Filters = new List<MeshFilter>(); internal readonly List<Collider> Colliders = new List<Collider>(); } internal static DelusionsEffect Instance; private static readonly string[][] Groups = new string[15][] { new string[4] { "roach_gold", "roach_lemon", "roach_platinum", "roach_flying_ruby" }, new string[2] { "roach_platinum_navmesh", "roach_gold_navmesh" }, new string[7] { "rebarrope_holiday", "rebarrope", "rebar_holiday", "rebar_explosive", "rebar_bone", "rebar", "artifact_rebar_return" }, new string[5] { "artifact_evaglove", "artifact_rapier", "artifact_remote", "artifact_translocator", "artifact_timepiece" }, new string[2] { "blinkeye", "blinkeye_marionette" }, new string[6] { "beans", "beans_periphery", "candycauldron", "cocoa_full", "milk", "wine" }, new string[9] { "bandage", "rhostone", "food_cookie", "food_bar", "food_fruit", "food_meat", "injector", "inoculator", "pillbottle" }, new string[4] { "handgun", "handgun_debug", "flaregun", "cryogun" }, new string[3] { "sluggrub_christmas", "sluggrub_sam", "sluggrub" }, new string[2] { "10mm_ammo", "flaregun_ammo" }, new string[7] { "floppy_t1", "floppy_lost", "floppy_t1_notes", "floppy_t1_randomitem", "floppy_t2", "floppy_t3", "floppy_variant" }, new string[14] { "trinket_base", "trinket_beta", "trinket_calmingbuddy", "trinket_chalk", "trinket_carabiner", "trinket_climbingshoes", "trinket_employeeid", "trinket_headlamp", "trinket_helmet", "trinket_massdamper", "trinket_moonrock", "trinket_nugget", "trinket_photoofhome", "temp" }, new string[5] { "candycauldron_empty", "beans_eaten", "cocoa_empty", "milk_empty", "wine_empty" }, new string[4] { "grapplepiton", "piton", "piton_holiday", "autopiton" }, new string[2] { "flashlight", "entityscanner" } }; private bool _active; private float _next; private int _passes; private static bool _runActive; private static readonly Dictionary<Item, ItemVisual> Originals = new Dictionary<Item, ItemVisual>(); private static readonly FieldInfo AssetField = FieldOf("itemAsset"); private static readonly FieldInfo HandField = FieldOf("handItemAsset"); private static readonly FieldInfo DropField = FieldOf("dropObject"); private static bool _loggedExample; private float _nextPass; private static readonly Dictionary<GameObject, Snap> Snapshots = new Dictionary<GameObject, Snap>(); private static HashSet<string>[] _groupKeys; private static readonly Dictionary<int, List<Item_Object>> PrefabsByGroup = new Dictionary<int, List<Item_Object>>(); private static bool _preloaded; private static readonly Dictionary<string, bool> LoggedNoChange = new Dictionary<string, bool>(StringComparer.OrdinalIgnoreCase); private static bool _loggedDbType; internal static bool ActiveForHooks { get { if (!_runActive) { return BindingState.IsActive("bugreen_delusions"); } return true; } } private void Awake() { Instance = this; } internal static void ForceActive() { _runActive = true; } internal static void ResetRun() { _runActive = false; RestoreItemData(); } internal void Begin(ENT_Player player) { _active = BindingState.IsActive("bugreen_delusions") || _runActive; _next = 0f; _passes = 0; if (_active) { PreloadAllGroups(); SwapItemData(); } } internal void End() { _active = false; RestoreItemData(); } private static FieldInfo FieldOf(string name) { return typeof(Item).GetField(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); } private static ItemVisual Snapshot(Item item) { ItemVisual itemVisual = new ItemVisual(); if (item == null) { return itemVisual; } itemVisual.Sprite = item.normalSprite; itemVisual.Asset = (Item_Object)((AssetField == null) ? null : /*isinst with value type is only supported in some contexts*/); itemVisual.HandItem = (HandItem)((HandField == null) ? null : /*isinst with value type is only supported in some contexts*/); itemVisual.Drop = (Item_Object)((DropField == null) ? null : /*isinst with value type is only supported in some contexts*/); return itemVisual; } internal static void SwapItemData() { int num = 0; int num2 = 0; for (int i = 0; i < Groups.Length; i++) { List<Item_Object> list = GroupPrefabs(i); if (list.Count < 2) { continue; } List<Item> list2 = new List<Item>(); HashSet<string> hashSet = new HashSet<string>(StringComparer.OrdinalIgnoreCase); for (int j = 0; j < list.Count; j++) { Item_Object val = list[j]; if (!((Object)(object)val == (Object)null) && val.itemData != null) { string text = Key(ItemName(val)); if (!string.IsNullOrEmpty(text) && hashSet.Add(text)) { list2.Add(val.itemData); } } } if (list2.Count < 2) { continue; } num2++; int num3 = 0; List<Visual> list3 = new List<Visual>(); for (int k = 0; k < list2.Count; k++) { Visual visual = new Visual(); visual.Key = Key(ItemName(list2[k])); list3.Add(visual); } int[] array = Derange(list3); List<ItemVisual> list4 = new List<ItemVisual>(); for (int l = 0; l < list2.Count; l++) { list4.Add(Snapshot(list2[l])); } for (int m = 0; m < list2.Count; m++) { Item val2 = list2[m]; if (val2 == null) { continue; } ItemVisual itemVisual = list4[m]; if (!Originals.ContainsKey(val2)) { Originals[val2] = itemVisual; } bool flag = false; for (int n = 0; n < list2.Count; n++) { int num4 = (array[m] + n) % list2.Count; if (num4 != m && Assign(val2, list4[num4], itemVisual)) { flag = true; if (!_loggedExample) { _loggedExample = true; WKLog.Info("Delusions: example '" + Key(ItemName(val2)) + "' now uses the visuals of '" + Key(ItemName(list2[num4])) + "'."); } break; } } if (flag) { num++; num3++; } } if (num3 != 0) { continue; } StringBuilder stringBuilder = new StringBuilder(); for (int num5 = 0; num5 < list2.Count; num5++) { if (stringBuilder.Length > 0) { stringBuilder.Append(", "); } stringBuilder.Append(Key(ItemName(list2[num5]))); } WKLog.Warn(string.Concat("Delusions: group ", i, " has ", list2.Count, " item(s) but no visual difference [", stringBuilder, "] (they share the same model prefabs).")); } WKLog.Info("Delusions: item visuals swapped for " + num + " item type(s) in " + num2 + " group(s)."); if (num != 0) { return; } StringBuilder stringBuilder2 = new StringBuilder(); for (int num6 = 0; num6 < Groups.Length; num6++) { if (stringBuilder2.Length > 0) { stringBuilder2.Append(", "); } stringBuilder2.Append("g").Append(num6).Append(":") .Append(GroupPrefabs(num6).Count); } WKLog.Warn(string.Concat("Delusions: nothing swapped (prefab counts [", stringBuilder2, "], database=", (VanillaAssets.Items() == null) ? "null" : "ok", ").")); } private static bool Assign(Item target, ItemVisual donor, ItemVisual original) { if (target == null || donor == null) { return false; } bool result = false; if ((Object)(object)donor.Sprite != (Object)null) { target.normalSprite = donor.Sprite; if (original != null && (Object)(object)target.normalSprite != (Object)(object)original.Sprite) { result = true; } } if (AssetField != null && (Object)(object)donor.Asset != (Object)null) { AssetField.SetValue(target, donor.Asset); if (original != null && !object.ReferenceEquals(donor.Asset, original.Asset)) { result = true; } } if (HandField != null && (Object)(object)donor.HandItem != (Object)null) { HandField.SetValue(target, donor.HandItem); if (original != null && !object.ReferenceEquals(donor.HandItem, original.HandItem)) { result = true; } } if (DropField != null && (Object)(object)donor.Drop != (Object)null) { DropField.SetValue(target, donor.Drop); if (original != null && !object.ReferenceEquals(donor.Drop, original.Drop)) { result = true; } } return result; } internal static void RestoreItemData() { foreach (KeyValuePair<Item, ItemVisual> original in Originals) { Item key = original.Key; ItemVisual value = original.Value; if (key != null && value != null) { if ((Object)(object)value.Sprite != (Object)null) { key.normalSprite = value.Sprite; } if (AssetField != null) { AssetField.SetValue(key, value.Asset); } if (HandField != null) { HandField.SetValue(key, value.HandItem); } if (DropField != null) { DropField.SetValue(key, value.Drop); } } } Originals.Clear(); } internal static void RequestPass() { if (!((Object)(object)Instance == (Object)null) && Instance._active) { Instance._passes = 0; Instance._nextPass = 0f; } } private void Update() { if (!_active || _passes >= 3 || Time.unscaledTime < _nextPass) { return; } _nextPass = Time.unscaledTime + ((_passes == 0) ? 4f : 15f); _passes++; try { Shuffle(); } catch (Exception ex) { WKLog.Warn("Delusions failed: " + ex.Message); _active = false; } } private void Shuffle() { List<Visual> list = CollectScene(); CaptureSnapshots(list); if (_passes == 1) { StringBuilder stringBuilder = new StringBuilder(); for (int i = 0; i < list.Count && i < 60; i++) { if (stringBuilder.Length > 0) { stringBuilder.Append(", "); } stringBuilder.Append(list[i].Key); } WKLog.Info(string.Concat("Delusions: scene keys (", list.Count, "): ", stringBuilder, ".")); } int num = 0; int num2 = 0; int num3 = 0; StringBuilder stringBuilder2 = new StringBuilder(); for (int j = 0; j < Groups.Length; j++) { HashSet<string> hashSet = GroupKeys()[j]; List<Visual> list2 = new List<Visual>(); for (int k = 0; k < list.Count; k++) { if (hashSet.Contains(list[k].Key)) { list2.Add(list[k]); } } if (list2.Count >= 2 && DistinctKeys(list2) >= 2) { num2++; num3 += list2.Count; if (stringBuilder2.Length > 0) { stringBuilder2.Append(", "); } stringBuilder2.Append("g").Append(j).Append(":") .Append(list2.Count); int[] array = Derange(list2); for (int l = 0; l < list2.Count; l++) { Visual visual = list2[array[l]]; Snap donor = Snapshots[visual.Root]; num += ApplyModel(list2[l], donor, visual); } } } WKLog.Info(string.Concat("Delusions: ", num3, " item(s) in ", num2, " group(s) [", stringBuilder2, "], replaced ", num, " model part(s).")); } private static void CaptureSnapshots(List<Visual> scene) { for (int i = 0; i < scene.Count; i++) { Visual visual = scene[i]; if ((Object)(object)visual.Root == (Object)null || Snapshots.ContainsKey(visual.Root)) { continue; } Snap snap = new Snap(); for (int j = 0; j < visual.Sprites.Count; j++) { if ((Object)(object)visual.Sprites[j] != (Object)null && (Object)(object)visual.Sprites[j].sprite != (Object)null) { snap.Sprites.Add(visual.Sprites[j].sprite); } } for (int k = 0; k < visual.Meshes.Count; k++) { Renderer val = visual.Meshes[k]; if ((Object)(object)val != (Object)null && (Object)(object)val.sharedMaterial != (Object)null && (Object)(object)val.sharedMaterial.mainTexture != (Object)null) { snap.Textures.Add(val.sharedMaterial.mainTexture); } } for (int l = 0; l < visual.Filters.Count; l++) { if ((Object)(object)visual.Filters[l] != (Object)null && (Object)(object)visual.Filters[l].sharedMesh != (Object)null) { snap.Meshes.Add(visual.Filters[l].sharedMesh); } } Snapshots[visual.Root] = snap; } } private static HashSet<string>[] GroupKeys() { if (_groupKeys != null) { return _groupKeys; } _groupKeys = new HashSet<string>[Groups.Length]; for (int i = 0; i < Groups.Length; i++) { HashSet<string> hashSet = new HashSet<string>(StringComparer.OrdinalIgnoreCase); for (int j = 0; j < Groups[i].Length; j++) { string text = Key(Groups[i][j]); if (!string.IsNullOrEmpty(text)) { hashSet.Add(text); } } _groupKeys[i] = hashSet; } return _groupKeys; } private static int DistinctKeys(List<Visual> members) { HashSet<string> hashSet = new HashSet<string>(StringComparer.OrdinalIgnoreCase); for (int i = 0; i < members.Count; i++) { hashSet.Add(members[i].Key); } return hashSet.Count; } private static int[] Derange(List<Visual> members) { int count = members.Count; int[] array = new int[count]; for (int i = 0; i < 32; i++) { for (int j = 0; j < count; j++) { array[j] = j; } for (int num = count - 1; num > 0; num--) { int num2 = Random.Range(0, num + 1); int num3 = array[num]; array[num] = array[num2]; array[num2] = num3; } bool flag = true; for (int k = 0; k < count; k++) { if (string.Equals(members[k].Key, members[array[k]].Key, StringComparison.OrdinalIgnoreCase)) { flag = false; break; } } if (flag) { return array; } } for (int l = 0; l < count; l++) { int num4 = l; for (int m = 1; m <= count; m++) { int num5 = (l + m) % count; if (!string.Equals(members[l].Key, members[num5].Key, StringComparison.OrdinalIgnoreCase)) { num4 = num5; break; } } array[l] = num4; } return array; } private static int ApplyModel(Visual target, Snap donor, Visual donorVisual) { int num = 0; for (int i = 0; i < target.Sprites.Count; i++) { SpriteRenderer val = target.Sprites[i]; if (!((Object)(object)val == (Object)null) && donor.Sprites.Count != 0) { Sprite val2 = donor.Sprites[i % donor.Sprites.Count]; if (!((Object)(object)val2 == (Object)null)) { val.sprite = val2; num++; } } } for (int j = 0; j < target.Meshes.Count; j++) { Renderer val3 = target.Meshes[j]; if ((Object)(object)val3 == (Object)null || donor.Textures.Count == 0) { continue; } Texture val4 = donor.Textures[j % donor.Textures.Count]; if ((Object)(object)val4 == (Object)null) { continue; } Material material = val3.material; if ((Object)(object)material == (Object)null) { continue; } try { material.mainTexture = val4; if (material.HasProperty("_BaseMap")) { material.SetTexture("_BaseMap", val4); } if (material.HasProperty("_MainTex")) { material.SetTexture("_MainTex", val4); } num++; } catch { } } for (int k = 0; k < target.Filters.Count; k++) { MeshFilter val5 = target.Filters[k]; if (!((Object)(object)val5 == (Object)null) && donor.Meshes.Count != 0) { Mesh val6 = donor.Meshes[k % donor.Meshes.Count]; if ((Object)(object)val6 != (Object)null) { val5.sharedMesh = val6; num++; } } } return num + CopyColliders(target, donorVisual); } private static int CopyColliders(Visual target, Visual source) { int num = 0; for (int i = 0; i < target.Colliders.Count; i++) { Collider val = target.Colliders[i]; if (!((Object)(object)val == (Object)null) && source.Colliders.Count != 0) { Collider val2 = source.Colliders[i % source.Colliders.Count]; if (!((Object)(object)val2 == (Object)null) && CopyGeometry(val, val2)) { num++; } } } for (int j = target.Colliders.Count; j < source.Colliders.Count; j++) { Collider val3 = source.Colliders[j]; if ((Object)(object)val3 == (Object)null || (Object)(object)target.Root == (Object)null) { continue; } try { Component obj = target.Root.AddComponent(((object)val3).GetType()); Collider val4 = (Collider)(object)((obj is Collider) ? obj : null); if ((Object)(object)val4 != (Object)null && CopyGeometry(val4, val3)) { num++; } } catch { } } return num; } private static bool CopyGeometry(Collider target, Collider donor) { //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)target == (Object)null || (Object)(object)donor == (Object)null || ((object)target).GetType() != ((object)donor).GetType()) { return false; } try { BoxCollider val = (BoxCollider)(object)((target is BoxCollider) ? target : null); BoxCollider val2 = (BoxCollider)(object)((donor is BoxCollider) ? donor : null); if ((Object)(object)val != (Object)null && (Object)(object)val2 != (Object)null) { val.center = val2.center; val.size = val2.size; ((Collider)val).isTrigger = ((Collider)val2).isTrigger; return true; } SphereCollider val3 = (SphereCollider)(object)((target is SphereCollider) ? target : null); SphereCollider val4 = (SphereCollider)(object)((donor is SphereCollider) ? donor : null); if ((Object)(object)val3 != (Object)null && (Object)(object)val4 != (Object)null) { val3.center = val4.center; val3.radius = val4.radius; ((Collider)val3).isTrigger = ((Collider)val4).isTrigger; return true; } CapsuleCollider val5 = (CapsuleCollider)(object)((target is CapsuleCollider) ? target : null); CapsuleCollider val6 = (CapsuleCollider)(object)((donor is CapsuleCollider) ? donor : null); if ((Object)(object)val5 != (Object)null && (Object)(object)val6 != (Object)null) { val5.center = val6.center; val5.radius = val6.radius; val5.height = val6.height; val5.direction = val6.direction; ((Collider)val5).isTrigger = ((Collider)val6).isTrigger; return true; } MeshCollider val7 = (MeshCollider)(object)((target is MeshCollider) ? target : null); MeshCollider val8 = (MeshCollider)(object)((donor is MeshCollider) ? donor : null); if ((Object)(object)val7 != (Object)null && (Object)(object)val8 != (Object)null) { val7.sharedMesh = val8.sharedMesh; val7.convex = val8.convex; ((Collider)val7).isTrigger = ((Collider)val8).isTrigger; return true; } } catch { } return false; } internal static void PreloadAllGroups() { int num = 0; int num2 = 0; StringBuilder stringBuilder = new StringBuilder(); for (int i = 0; i < Groups.Length; i++) { List<Item_Object> list = GroupPrefabs(i); if (list.Count != 0) { num++; num2 += list.Count; if (stringBuilder.Length > 0) { stringBuilder.Append(", "); } stringBuilder.Append("g").Append(i).Append(":") .Append(list.Count); for (int j = 0; j < list.Count; j++) { TouchAssets(list[j]); } } } _preloaded = num2 > 0; if (num2 == 0) { IList list2 = null; try { list2 = VanillaAssets.Items(); } catch { } WKLog.Warn("Delusions: preload found 0 prefabs (item database = " + ((list2 == null) ? "null" : list2.Count.ToString()) + ")."); } else { WKLog.Info(string.Concat("Delusions: preloaded ", num2, " item prefab(s) in ", num, " group(s) [", stringBuilder, "].")); } } private static Item_Object AsItemObject(object entry) { if (entry == null) { return null; } Item_Object val = (Item_Object)((entry is Item_Object) ? entry : null); if ((Object)(object)val != (Object)null) { return val; } GameObject val2 = (GameObject)((entry is GameObject) ? entry : null); if ((Object)(object)val2 == (Object)null) { Component val3 = (Component)((entry is Component) ? entry : null); if ((Object)(object)val3 != (Object)null) { val2 = val3.gameObject; } } if ((Object)(object)val2 == (Object)null) { return null; } if (!_loggedDbType) { _loggedDbType = true; WKLog.Info("Delusions: item database entries are GameObjects (e.g. " + ((Object)val2).name + ")."); } val = val2.GetComponent<Item_Object>(); if ((Object)(object)val == (Object)null) { val = val2.GetComponentInChildren<Item_Object>(true); } return val; } private static List<Item_Object> GroupPrefabs(int group) { if (PrefabsByGroup.TryGetValue(group, out var value)) { return value; } value = new List<Item_Object>(); try { IList list = VanillaAssets.Items(); int num = 0; while (list != null && num < list.Count) { Item_Object val = AsItemObject(list[num]); if (!((Object)(object)val == (Object)null)) { string text = Key(ItemName(val)); if (text != null && GroupKeys()[group].Contains(text)) { value.Add(val); } } num++; } } catch (Exception ex) { WKLog.Warn("Delusions: prefab list failed: " + ex.Message); } PrefabsByGroup[group] = value; return value; } private static void TouchAssets(Item_Object prefab) { try { if ((Object)(object)prefab == (Object)null) { return; } if (prefab.itemData != null) { Sprite normalSprite = prefab.itemData.normalSprite; if ((Object)(object)normalSprite != (Object)null && (Object)(object)normalSprite.texture != (Object)null) { _ = ((Texture)normalSprite.texture).width; } } Renderer[] componentsInChildren = ((Component)prefab).GetComponentsInChildren<Renderer>(true); foreach (Renderer val in componentsInChildren) { if (!((Object)(object)val == (Object)null)) { SpriteRenderer val2 = (SpriteRenderer)(object)((val is SpriteRenderer) ? val : null); if ((Object)(object)val2 != (Object)null && (Object)(object)val2.sprite != (Object)null && (Object)(object)val2.sprite.texture != (Object)null) { _ = ((Texture)val2.sprite.texture).width; } if ((Object)(object)val.sharedMaterial != (Object)null && (Object)(object)val.sharedMaterial.mainTexture != (Object)null) { _ = val.sharedMaterial.mainTexture.width; } } } } catch { } } internal static Sprite RandomSpriteFor(string targetKey) { int num = GroupIndex(targetKey); if (num < 0) { return null; } List<Item_Object> list = GroupPrefabs(num); List<Item_Object> list2 = new List<Item_Object>(); for (int i = 0; i < list.Count; i++) { Item_Object val = list[i]; if (!((Object)(object)val == (Object)null) && val.itemData != null && !((Object)(object)val.itemData.normalSprite == (Object)null)) { string text = Key(ItemName(val)); if (!string.IsNullOrEmpty(text) && !string.Equals(text, targetKey, StringComparison.OrdinalIgnoreCase)) { list2.Add(val); } } } if (list2.Count == 0) { return null; } return list2[Random.Range(0, list2.Count)].itemData.normalSprite; } internal static bool RandomizeInstance(Item_Object item) { if ((Object)(object)item == (Object)null) { return false; } string text = Key(ItemName(item)); if (text == null) { return false; } int num = GroupIndex(text); if (num < 0) { return false; } List<Item_Object> list = PrefabsInGroup(num, text); if (list.Count == 0) { return false; } Visual visual = VisualFrom(((Component)item).gameObject); Sprite val = ((visual.Sprites.Count == 0 || (Object)(object)visual.Sprites[0] == (Object)null) ? null : visual.Sprites[0].sprite); Mesh val2 = ((visual.Filters.Count == 0 || (Object)(object)visual.Filters[0] == (Object)null) ? null : visual.Filters[0].sharedMesh); Texture val3 = ((visual.Meshes.Count == 0 || (Object)(object)visual.Meshes[0] == (Object)null || (Object)(object)visual.Meshes[0].sharedMaterial == (Object)null) ? null : visual.Meshes[0].sharedMaterial.mainTexture); for (int i = 0; i < list.Count && i < 5; i++) { int index = Random.Range(i, list.Count); Item_Object value = list[i]; list[i] = list[index]; list[index] = value; Item_Object val4 = list[i]; if (!((Object)(object)val4 == (Object)null)) { Visual donorVisual = VisualFrom(((Component)val4).gameObject); Snap donor = SnapFrom(((Component)val4).gameObject); ApplyModel(visual, donor, donorVisual); Sprite val5 = ((visual.Sprites.Count == 0 || (Object)(object)visual.Sprites[0] == (Object)null) ? null : visual.Sprites[0].sprite); Mesh val6 = ((visual.Filters.Count == 0 || (Object)(object)visual.Filters[0] == (Object)null) ? null : visual.Filters[0].sharedMesh); Texture val7 = ((visual.Meshes.Count == 0 || (Object)(object)visual.Meshes[0] == (Object)null || (Object)(object)visual.Meshes[0].sharedMaterial == (Object)null) ? null : visual.Meshes[0].sharedMaterial.mainTexture); if ((Object)(object)val5 != (Object)(object)val || (Object)(object)val6 != (Object)(object)val2 || (Object)(object)val7 != (Object)(object)val3) { WKLog.Info("Delusions: '" + text + "' now looks like '" + Key(ItemName(val4)) + "'."); return true; } } } if (!LoggedNoChange.ContainsKey(text)) { LoggedNoChange[text] = true; WKLog.Warn("Delusions: no visible change for '" + text + "'."); } return false; } internal static bool RandomizeItem(Item item) { if (item == null) { return false; } string text = Key(ItemName(item)); if (text == null) { return false; } int num = GroupIndex(text); if (num < 0) { return false; } List<Item_Object> list = PrefabsInGroup(num, text); if (list.Count == 0) { return false; } for (int i = 0; i < list.Count && i < 5; i++) { int index = Random.Range(i, list.Count); Item_Object value = list[i]; list[i] = list[index]; list[index] = value; Item_Object val = list[i]; if (!((Object)(object)val == (Object)null) && val.itemData != null && !((Object)(object)val.itemData.normalSprite == (Object)null) && !((Object)(object)item.normalSprite == (Object)(object)val.itemData.normalSprite)) { item.normalSprite = val.itemData.normalSprite; WKLog.Info("Delusions: item '" + text + "' sprite -> '" + Key(ItemName(val)) + "'."); return true; } } return false; } internal static HandItem RandomHandAssetFor(Item item) { if (item == null) { return null; } string text = Key(ItemName(item)); if (text == null) { return null; } int num = GroupIndex(text); if (num < 0) { return null; } List<Item_Object> list = GroupPrefabs(num); List<HandItem> list2 = new List<HandItem>(); for (int i = 0; i < list.Count; i++) { Item_Object val = list[i]; if ((Object)(object)val == (Object)null || val.itemData == null) { continue; } string text2 = Key(ItemName(val)); if (!string.IsNullOrEmpty(text2) && !string.Equals(text2, text, StringComparison.OrdinalIgnoreCase)) { HandItem val2 = val.itemData.handItemAsset; if ((Object)(object)val2 == (Object)null) { val2 = FindLoadedHandPrefab(text2); } if ((Object)(object)val2 != (Object)null) { list2.Add(val2); } } } if (list2.Count == 0) { return null; } return list2[Random.Range(0, list2.Count)]; } private static HandItem FindLoadedHandPrefab(string key) { try { Object[] array = Resources.FindObjectsOfTypeAll(typeof(HandItem)); foreach (Object obj in array) { HandItem val = (HandItem)(object)((obj is HandItem) ? obj : null); if (!((Object)(object)val == (Object)null)) { string a = Key(((Object)((Component)val).gameObject).name); if (string.Equals(a, key, StringComparison.OrdinalIgnoreCase)) { return val; } } } } catch { } return null; } private static string ItemName(Item item) { if (item == null) { return null; } if (!string.IsNullOrEmpty(item.prefabName)) { return item.prefabName; } return item.itemName; } private static string ItemName(Item_Object item) { if ((Object)(object)item == (Object)null) { return null; } if (item.itemData != null) { if (!string.IsNullOrEmpty(item.itemData.prefabName)) { return item.itemData.prefabName; } if (!string.IsNullOrEmpty(item.itemData.itemName)) { return item.itemData.itemName; } } return ((Object)item).name; } private static int GroupIndex(string key) { for (int i = 0; i < Groups.Length; i++) { if (GroupKeys()[i].Contains(key)) { return i; } } return -1; } private static List<Item_Object> PrefabsInGroup(int group, string selfKey) { if (!PrefabsByGroup.TryGetValue(group, out var value)) { value = new List<Item_Object>(); try { IList list = VanillaAssets.Items(); int num = 0; while (list != null && num < list.Count) { Item_Object val = AsItemObject(list[num]); if (!((Object)(object)val == (Object)null)) { string text = Key(ItemName(val)); if (text != null && GroupKeys()[group].Contains(text)) { value.Add(val); } } num++; } } catch (Exception ex) { WKLog.Warn("Delusions: prefab list failed: " + ex.Message); } PrefabsByGroup[group] = value; } List<Item_Object> list2 = new List<Item_Object>(); for (int i = 0; i < value.Count; i++) { string text2 = Key(ItemName(value[i])); if (text2 != null && !string.Equals(text2, selfKey, StringComparison.OrdinalIgnoreCase)) { list2.Add(value[i]); } } return list2; } private static Visual VisualFrom(GameObject root) { Visual visual = new Visual(); visual.Root = root; Renderer[] componentsInChildren = root.GetComponentsInChildren<Renderer>(true); foreach (Renderer val in componentsInChildren) { if (!((Object)(object)val == (Object)null)) { visual.Renderers.Add(val); SpriteRenderer val2 = (SpriteRenderer)(object)((val is SpriteRenderer) ? val : null); if ((Object)(object)val2 != (Object)null) { visual.Sprites.Add(val2); } else { visual.Meshes.Add(val); } } } MeshFilter[] componentsInChildren2 = root.GetComponentsInChildren<MeshFilter>(true); for (int j = 0; j < componentsInChildren2.Length; j++) { if ((Object)(object)componentsInChildren2[j] != (Object)null) { visual.Filters.Add(componentsInChildren2[j]); } } Collider[] componentsInChildren3 = root.GetComponentsInChildren<Collider>(true); for (int k = 0; k < componentsInChildren3.Length; k++) { if ((Object)(object)componentsInChildren3[k] != (Object)null) { visual.Colliders.Add(componentsInChildren3[k]); } } return visual; } private static Snap SnapFrom(GameObject root) { Snap snap = new Snap(); Renderer[] componentsInChildren = root.GetComponentsInChildren<Renderer>(true); foreach (Renderer val in componentsInChildren) { if ((Object)(object)val == (Object)null) { continue; } SpriteRenderer val2 = (SpriteRenderer)(object)((val is SpriteRenderer) ? val : null); if ((Object)(object)val2 != (Object)null) { if ((Object)(object)val2.sprite != (Object)null) { snap.Sprites.Add(val2.sprite); } } else if ((Object)(object)val.sharedMaterial != (Object)null && (Object)(object)val.sharedMaterial.mainTexture != (Object)null) { snap.Textures.Add(val.sharedMaterial.mainTexture); } } MeshFilter[] componentsInChildren2 = root.GetComponentsInChildren<MeshFilter>(true); for (int j = 0; j < componentsInChildren2.Length; j++) { if ((Object)(object)componentsInChildren2[j] != (Object)null && (Object)(object)componentsInChildren2[j].sharedMesh != (Object)null) { snap.Meshes.Add(componentsInChildren2[j].sharedMesh); } } return snap; } private static List<Visual> CollectScene() { //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) List<Visual> list = new List<Visual>(); HashSet<GameObject> hashSet = new HashSet<GameObject>(); Object[] array = Object.FindObjectsOfType(typeof(Item_Object)); foreach (Object obj in array) { Item_Object val = (Item_Object)(object)((obj is Item_Object) ? obj : null); if ((Object)(object)val == (Object)null) { continue; } Scene scene = ((Component)val).gameObject.scene; if (!((Scene)(ref scene)).IsValid()) { continue; } string text = Key(ItemName(val)); if (text != null && hashSet.Add(((Component)val).gameObject)) { Visual visual = VisualFrom(((Component)val).gameObject); visual.Key = text; if (visual.Renderers.Count > 0 || visual.Filters.Count > 0) { list.Add(visual); } } } AddDenizens(list, hashSet, typeof(DEN_Roach)); AddDenizens(list, hashSet, typeof(DEN_GiantRoach)); AddDenizens(list, hashSet, typeof(DEN_Crawler)); return list; } private static void AddDenizens(List<Visual> result, HashSet<GameObject> seen, Type type) { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) Object[] array = Object.FindObjectsOfType(type); foreach (Object obj in array) { Component val = (Component)(object)((obj is Component) ? obj : null); if ((Object)(object)val == (Object)null) { continue; } Scene scene = val.gameObject.scene; if (!((Scene)(ref scene)).IsValid()) { continue; } string text = Key(((Object)val.gameObject).name); if (text != null && seen.Add(val.gameObject)) { Visual visual = VisualFrom(val.gameObject); visual.Key = text; if (visual.Renderers.Count > 0 || visual.Filters.Count > 0) { result.Add(visual); } } } } private static List<Visual> CollectSceneLegacy() { //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) List<Visual> list = new List<Visual>(); HashSet<GameObject> hashSet = new HashSet<GameObject>(); Object[] array = Resources.FindObjectsOfTypeAll(typeof(GameObject)); foreach (Object obj in array) { GameObject val = (GameObject)(object)((obj is GameObject) ? obj : null); if ((Object)(object)val == (Object)null) { continue; } Scene scene = val.scene; if (!((Scene)(ref scene)).IsValid()) { continue; } Transform parent = val.transform.parent; if ((Object)(object)parent != (Object)null && (Object)(object)((Component)parent).GetComponentInParent<Item_Object>() != (Object)null) { continue; } Item_Object val2 = val.GetComponent<Item_Object>(); if ((Object)(object)val2 == (Object)null) { val2 = val.GetComponentInChildren<Item_Object>(true); } string name = ((Object)val).name; if ((Object)(object)val2 != (Object)null && val2.itemData != null) { if (!string.IsNullOrEmpty(val2.itemData.prefabName)) { name = val2.itemData.prefabName; } else if (!string.IsNullOrEmpty(val2.itemData.itemName)) { name = val2.itemData.itemName; } } string text = Key(name); if (text == null) { continue; } GameObject val3 = (((Object)(object)val2 != (Object)null) ? ((Component)val2).gameObject : val); if (!hashSet.Add(val3)) { continue; } Visual visual = new Visual(); visual.Key = text; visual.Root = val3; Renderer[] componentsInChildren = val3.GetComponentsInChildren<Renderer>(true); foreach (Renderer val4 in componentsInChildren) { if (!((Object)(object)val4 == (Object)null) && !((Object)(object)val4.sharedMaterial == (Object)null)) { visual.Renderers.Add(val4); SpriteRenderer val5 = (SpriteRenderer)(object)((val4 is SpriteRenderer) ? val4 : null); if ((Object)(object)val5 != (Object)null) { visual.Sprites.Add(val5); } else { visual.Meshes.Add(val4); } } } MeshFilter[] componentsInChildren2 = val3.GetComponentsInChildren<MeshFilter>(true); for (int k = 0; k < componentsInChildren2.Length; k++) { if ((Object)(object)componentsInChildren2[k] != (Object)null && (Object)(object)componentsInChildren2[k].sharedMesh != (Object)null) { visual.Filters.Add(componentsInChildren2[k]); } } Collider[] componentsInChildren3 = val3.GetComponentsInChildren<Collider>(true); for (int l = 0; l < componentsInChildren3.Length; l++) { if ((Object)(object)componentsInChildren3[l] != (Object)null) { visual.Colliders.Add(componentsInChildren3[l]); } } if (visual.Renderers.Count > 0 || visual.Filters.Count > 0) { list.Add(visual); } } return list; } internal static string Key(string name) { if (string.IsNullOrEmpty(name)) { return null; } string text = name.ToLowerInvariant().Trim().Replace("(clone)", string.Empty) .Replace(" ", string.Empty); string[] array = new string[16] { "item_object_", "item_object", "world_item_", "item_hands_", "item_hand_", "handitem_", "hand_item_", "hands_", "hand_", "item_", "denizen_", "den_", "env_", "ut_", "cl_", "trinket_" }; bool flag = true; while (flag) { flag = false; for (int i = 0; i < array.Length; i++) { if (text.StartsWith(array[i])) { text = text.Substring(array[i].Length); flag = true; break; } } } if (!string.IsNullOrEmpty(text)) { return text; } return null; } } internal static class DelusionsSpawnPatch { private static readonly HashSet<int> Done = new HashSet<int>(); private static readonly HashSet<string> LoggedHand = new HashSet<string>(StringComparer.OrdinalIgnoreCase); private static readonly Dictionary<string, Sprite> HandChoice = new Dictionary<string, Sprite>(StringComparer.OrdinalIgnoreCase); private static readonly Dictionary<int, int> Attempts = new Dictionary<int, int>(); private static readonly HashSet<string> Probed = new HashSet<string>(); private static readonly HashSet<string> LoggedHandSwap = new HashSet<string>(StringComparer.OrdinalIgnoreCase); private static Sprite HandSpriteFor(string key) { if (HandChoice.TryGetValue(key, out var value) && (Object)(object)value != (Object)null) { return value; } Sprite val = DelusionsEffect.RandomSpriteFor(key); if ((Object)(object)val != (Object)null) { HandChoice[key] = val; } return val; } internal static void Apply(Harmony harmony) { //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Expected O, but got Unknown //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Expected O, but got Unknown //IL_00d7: Unknown result type (might be due to invalid IL or missing references) //IL_00e4: Expected O, but got Unknown //IL_0125: Unknown result type (might be due to invalid IL or missing references) //IL_0132: Expected O, but got Unknown //IL_01bb: Unknown result type (might be due to invalid IL or missing references) //IL_01c8: Expected O, but got Unknown //IL_0208: Unknown result type (might be due to invalid IL or missing references) //IL_0216: Expected O, but got Unknown //IL_0257: Unknown result type (might be due to invalid IL or missing references) //IL_0264: Expected O, but got Unknown try { MethodInfo methodInfo = AccessTools.Method("Item_Object:Start", (Type[])null, (Type[])null); if (methodInfo == null) { WKLog.Warn("Delusions: Item_Object.Start not found."); return; } MethodInfo method = typeof(DelusionsSpawnPatch).GetMethod("AfterStart", BindingFlags.Static | BindingFlags.NonPublic); harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(method), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); WKLog.Info("Delusions: patched Item_Object.Start."); MethodInfo methodInfo2 = AccessTools.Method("Item_Object:Update", (Type[])null, (Type[])null); if (methodInfo2 != null) { MethodInfo method2 = typeof(DelusionsSpawnPatch).GetMethod("BeforeItemUpdate", BindingFlags.Static | BindingFlags.NonPublic); harmony.Patch((MethodBase)methodInfo2, new HarmonyMethod(method2), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); WKLog.Info("Delusions: patched Item_Object.Update."); } MethodInfo methodInfo3 = AccessTools.Method("M_Level:OnSpawn", (Type[])null, (Type[])null); if (methodInfo3 != null) { MethodInfo method3 = typeof(DelusionsSpawnPatch).GetMethod("AfterLevelSpawn", BindingFlags.Static | BindingFlags.NonPublic); harmony.Patch((MethodBase)methodInfo3, (HarmonyMethod)null, new HarmonyMethod(method3), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); WKLog.Info("Delusions: patched M_Level.OnSpawn."); } MethodInfo methodInfo4 = AccessTools.Method("HandItem:Initialize", (Type[])null, (Type[])null); if (methodInfo4 != null) { MethodInfo method4 = typeof(DelusionsSpawnPatch).GetMethod("AfterHandInitialize", BindingFlags.Static | BindingFlags.NonPublic); harmony.Patch((MethodBase)methodInfo4, (HarmonyMethod)null, new HarmonyMethod(method4), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); WKLog.Info("Delusions: patched HandItem.Initialize."); } PatchItemLifecycle(harmony, "OnPickup"); PatchItemLifecycle(harmony, "OnPlaceInInventory"); PatchItemLifecycle(harmony, "OnPlaceInWorld"); PatchItemLifecycle(harmony, "OnDrop"); PatchItemDataProbe(harmony, "InitializeInHand"); PatchItemDataProbe(harmony, "CreateDropObject"); PatchHandAssetSwap(harmony); MethodInfo methodInfo5 = AccessTools.Method("Hand:SetSprite", (Type[])null, (Type[])null); if (methodInfo5 != null) { MethodInfo method5 = typeof(DelusionsSpawnPatch).GetMethod("AfterSetSprite", BindingFlags.Static | BindingFlags.NonPublic); harmony.Patch((MethodBase)methodInfo5, (HarmonyMethod)null, new HarmonyMethod(method5), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); WKLog.Info("Delusions: patched Hand.SetSprite."); } MethodInfo methodInfo6 = AccessTools.Method("M_Gamemode:StartFreshGamemode", (Type[])null, (Type[])null); if (methodInfo6 != null) { MethodInfo method6 = typeof(DelusionsSpawnPatch).GetMethod("BeforeStartFresh", BindingFlags.Static | BindingFlags.NonPublic); harmony.Patch((MethodBase)methodInfo6, new HarmonyMethod(method6), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); WKLog.Info("Delusions: patched M_Gamemode.StartFreshGamemode (preload)."); } MethodInfo methodInfo7 = AccessTools.Method("ENT_Player:HandAnimation", (Type[])null, (Type[])null); if (methodInfo7 != null) { MethodInfo method7 = typeof(DelusionsSpawnPatch).GetMethod("AfterHandAnimation", BindingFlags.Static | BindingFlags.NonPublic); harmony.Patch((MethodBase)methodInfo7, (HarmonyMethod)null, new HarmonyMethod(method7), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); WKLog.Info("Delusions: patched ENT_Player.HandAnimation."); } } catch (Exception ex) { WKLog.Warn("Delusions spawn patch failed: " + ex.Message); } } private static void PatchItemLifecycle(Harmony harmony, string methodName) { //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Expected O, but got Unknown try { MethodInfo methodInfo = AccessTools.Method("Item_Object:" + methodName, (Type[])null, (Type[])null); if (!(methodInfo == null)) { MethodInfo method = typeof(DelusionsSpawnPatch).GetMethod("AfterItemLifecycle", BindingFlags.Static | BindingFlags.NonPublic); harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(method), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); WKLog.Info("Delusions: patched Item_Object." + methodName + "."); } } catch (Exception ex) { WKLog.Warn("Delusions: Item_Object." + methodName + " patch failed: " + ex.Message); } } private static void PatchItemDataProbe(Harmony harmony, string methodName) { //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Expected O, but got Unknown try { MethodInfo methodInfo = AccessTools.Method("Item:" + methodName, (Type[])null, (Type[])null); if (methodInfo == null) { WKLog.Warn("Delusions: Item." + methodName + " not found."); return; } MethodInfo method = typeof(DelusionsSpawnPatch).GetMethod("AfterItemDataProbe", BindingFlags.Static | BindingFlags.NonPublic); harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(method), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); WKLog.Info("Delusions: patched Item." + methodName + " (probe)."); } catch (Exception ex) { WKLog.Warn("Delusions: Item." + methodName + " probe failed: " + ex.Message); } } private static void PatchHandAssetSwap(Harmony harmony) { //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Expected O, but got Unknown try { MethodInfo methodInfo = AccessTools.Method("Item:InitializeInHand", (Type[])null, (Type[])null); if (methodInfo == null) { WKLog.Warn("Delusions: Item.InitializeInHand not found (hand swap)."); return; } MethodInfo method = typeof(DelusionsSpawnPatch).GetMethod("BeforeInitializeInHand", BindingFlags.Static | BindingFlags.NonPublic); harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(method), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); WKLog.Info("Delusions: patched Item.InitializeInHand (hand animation swap)."); } catch (Exception ex) { WKLog.Warn("Delusions: hand swap patch failed: " + ex.Message); } } private static void BeforeInitializeInHand(object __instance) { try { Item val = (Item)((__instance is Item) ? __instance : null); if (val == null || !DelusionsEffect.ActiveForHooks) { return; } HandItem val2 = DelusionsEffect.RandomHandAssetFor(val); if ((Object)(object)val2 == (Object)null) { return; } FieldInfo field = typeof(Item).GetField("handItemAsset", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (!(field == null) && !object.ReferenceEquals(field.GetValue(val), val2)) { field.SetValue(val, val2); string text = DelusionsEffect.Key(string.IsNullOrEmpty(val.prefabName) ? val.itemName : val.prefabName); if (!string.IsNullOrEmpty(text) && LoggedHandSwap.Add(text)) { WKLog.Info("Delusions: hand animation '" + text + "' -> '" + ((Object)val2).name + "'."); } } } catch (Exception ex) { WKLog.Warn("Delusions hand swap failed: " + ex.Message); } } private static void AfterItemDataProbe(object __instance) { try { Item val = (Item)((__instance is Item) ? __instance : null); if (val != null && DelusionsEffect.ActiveForHooks) { string text = DelusionsEffect.Key(string.IsNullOrEmpty(val.prefabName) ? val.itemName : val.prefabName); if (!string.IsNullOrEmpty(text) && Probed.Add(text)) { FieldInfo field = typeof(Item).GetField("itemAsset", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); FieldInfo field2 = typeof(Item).GetField("handItemAsset", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); Object val2 = (Object)((field == null) ? null : /*isinst with value type is only supported in some contexts*/); Object val3 = (Object)((field2 == null) ? null : /*isinst with value type is only supported in some contexts*/); WKLog.Info("Delusions: probe " + text + " asset=" + ((val2 == (Object)null) ? "<null>" : val2.name) + " hand=" + ((val3 == (Object)null) ? "<null>" : val3.name) + "."); } } } catch { } } private static void AfterItemLifecycle(object __instance) { try { Item_Object val = (Item_Object)((__instance is Item_Object) ? __instance : null); if (!((Object)(object)val == (Object)null) && DelusionsEffect.ActiveForHooks && !Done.Contains(((Object)val).GetInstanceID()) && DelusionsEffect.RandomizeInstance(val)) { Done.Add(((Object)val).GetInstanceID()); } } catch (Exception ex) { WKLog.Warn("Delusions lifecycle failed: " + ex.Message); } } private static void BeforeItemUpdate(object __instance) { try { Item_Object val = (Item_Object)((__instance is Item_Object) ? __instance : null); if ((Object)(object)val == (Object)null || !DelusionsEffect.ActiveForHooks) { return; } int instanceID = ((Object)val).GetInstanceID(); if (!Done.Contains(instanceID)) { if (!Attempts.ContainsKey(instanceID)) { Attempts[instanceID] = 0; WKLog.Info("Delusions: update hook " + ((Object)val).name + " (data=" + ((val.itemData == null) ? "?" : val.itemData.prefabName) + ")."); } Attempts[instanceID] += 1; if (DelusionsEffect.RandomizeInstance(val) || Attempts[instanceID] >= 8) { Done.Add(instanceID); } } } catch (Exception ex) { WKLog.Warn("Delusions update hook failed: " + ex.Message); } } private static void AfterLevelSpawn(object __instance) { try { DelusionsEffect.RequestPass(); string levelName = null; if (__instance != null) { FieldInfo field = __instance.GetType().GetField("levelName", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); levelName = ((field == null) ? null : (field.GetValue(__instance) as string)); } LambdaCatalog.ObserveLevel(levelName); } catch { } } private static void AfterHandAnimation(object __instance) { try { if (__instance == null || !DelusionsEffect.ActiveForHooks) { return; } FieldInfo field = __instance.GetType().GetField("hands", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); Array array = ((field == null) ? null : (field.GetValue(__instance) as Array)); if (array == null) { return; } for (int i = 0; i < array.Length; i++) { object value = array.GetValue(i); if (value == null) { continue; } FieldInfo field2 = value.GetType().GetField("handSprite", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); SpriteRenderer val = (SpriteRenderer)((field2 == null) ? null : /*isinst with value type is only supported in some contexts*/); if ((Object)(object)val == (Object)null || (Object)(object)val.sprite == (Object)null) { continue; } string text = DelusionsEffect.Key(((Object)val.sprite).name); if (string.IsNullOrEmpty(text)) { continue; } for (int j = 0; j < 3; j++) { Sprite val2 = HandSpriteFor(text); if ((Object)(object)val2 != (Object)null && (Object)(object)val2 != (Object)(object)val.sprite) { val.sprite = val2; if (!LoggedHand.Contains(text)) { LoggedHand.Add(text); WKLog.Info("Delusions: hand sprite '" + text + "' -> '" + ((Object)val2).name + "'."); } break; } HandChoice.Remove(text); } } } catch (Exception ex) { WKLog.Warn("Delusions hand animation failed: " + ex.Message); } } private static void BeforeStartFresh(object __instance) { try { DelusionsEffect.PreloadAllGroups(); HashSet<string> hashSet = VanillaItemGrant.ReadSelectedFromSave(__instance); bool flag = false; if (hashSet != null) { foreach (string item in hashSet) { if (!string.IsNullOrEmpty(item) && item.ToLowerInvariant().Contains("delusions")) { flag = true; break; } } } if (flag) {