Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of ValheimBB v1.2.16
BepInEx\plugins\ValheimBB.dll
Decompiled 3 days ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Drawing; using System.Globalization; using System.IO; using System.Linq; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using System.Text; using System.Text.RegularExpressions; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using GUIFramework; using HarmonyLib; using Splatform; using TMPro; using UnityEngine; using UnityEngine.Audio; using UnityEngine.EventSystems; using UnityEngine.Events; using UnityEngine.Networking; using UnityEngine.PostProcessing; using UnityEngine.UI; using ValheimBB.FireFuel; using ValheimBB.ForgeRefinement; using ValheimBB.Lighting; using ValheimBB.ResourceTracking; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyTitle("ValheimBB")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("ValheimBB")] [assembly: AssemblyCopyright("Copyright © 2025")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("1699c6b0-5753-49cf-903b-e6b635fbcab9")] [assembly: AssemblyFileVersion("1.2.16.0")] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: AssemblyVersion("1.2.16.0")] namespace ValheimBB { [BepInPlugin("com.valheimbb", "ValheimBB", "1.2.16")] public class ValheimBBPlugin : BaseUnityPlugin { internal enum WisplightOutsideMistlandsMode { VanillaOrbit, Off, LockedInPlace } [HarmonyPatch(typeof(BaseAI), "DoIdleSound")] public static class BaseAI_DoIdleSound_AttachedOriginSound_Patch { private static void Prefix(BaseAI __instance) { SetDeerAlertedIdleSoundState(__instance, (Object)(object)__instance != (Object)null && __instance.IsAlerted()); ForceAttachSoundEffects(__instance?.m_idleSound); } private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions) { return ReplaceEffectListCreateNullParentWithSelfTransform(instructions); } } [HarmonyPatch(typeof(BaseAI), "SetAlerted")] public static class BaseAI_SetAlerted_AttachedOriginSound_Patch { private static void Prefix(BaseAI __instance) { ForceAttachSoundEffects(__instance?.m_alertedEffects); } private static void Postfix(BaseAI __instance, bool __0) { SetDeerAlertedIdleSoundState(__instance, __0); } private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions) { return ReplaceEffectListCreateNullParentWithSelfTransform(instructions); } } [HarmonyPatch(typeof(BaseAI), "OnDestroy")] public static class BaseAI_OnDestroy_DeerAlertedScaredSfx_Patch { private static void Postfix(BaseAI __instance) { ClearDeerAlertedIdleSoundState(__instance); } } [HarmonyPatch(typeof(Attack), "Update")] public static class Attack_Update_AttachedOriginSound_Patch { private static void Prefix(Attack __instance) { NormalizeAttackStartSoundEffects(__instance); } } [HarmonyPatch(typeof(Attack), "DoMeleeAttack")] public static class Attack_DoMeleeAttack_AttachedOriginSound_Patch { private static void Prefix(Attack __instance) { NormalizeAttackTriggerSoundEffects(__instance); } } [HarmonyPatch(typeof(Attack), "DoAreaAttack")] public static class Attack_DoAreaAttack_AttachedOriginSound_Patch { private static void Prefix(Attack __instance) { NormalizeAttackTriggerSoundEffects(__instance); } } [HarmonyPatch(typeof(Attack), "ProjectileAttackTriggered")] public static class Attack_ProjectileAttackTriggered_AttachedOriginSound_Patch { private static void Prefix(Attack __instance) { NormalizeAttackTriggerSoundEffects(__instance); } } [HarmonyPatch(typeof(Attack), "OnTrailStart")] public static class Attack_OnTrailStart_AttachedOriginSound_Patch { private static void Prefix(Attack __instance) { NormalizeAttackTrailSoundEffects(__instance); } } [HarmonyPatch(typeof(Character), "ApplyDamage")] public static class Character_ApplyDamage_FallDamageGrunt_Patch { private static void Prefix(Character __instance, HitData hit, ref float __state) { __state = 0f; if (ShouldPlayFallDamageGrunt(__instance, hit)) { __state = __instance.GetHealth(); } } private static void Postfix(Character __instance, HitData hit, float __state) { if (!(__state <= 0f) && ShouldPlayFallDamageGrunt(__instance, hit)) { float health = __instance.GetHealth(); if (!(health <= 0f) && !(__state - health <= 0.1f)) { TryBroadcastPlayerDamageGrunt((Player)(object)((__instance is Player) ? __instance : null)); } } } private static bool ShouldPlayFallDamageGrunt(Character character, HitData hit) { //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Invalid comparison between Unknown and I4 Player val = (Player)(object)((character is Player) ? character : null); if ((Object)(object)val != (Object)null && (Object)(object)val == (Object)(object)Player.m_localPlayer && hit != null) { return (int)hit.m_hitType == 3; } return false; } } [HarmonyPatch(typeof(Character), "AddFireDamage")] public static class Character_AddFireDamage_FireDamageGrunt_Patch { private static void Postfix(Character __instance, float damage) { Player val = (Player)(object)((__instance is Player) ? __instance : null); if (!((Object)(object)val == (Object)null) && !((Object)(object)val != (Object)(object)Player.m_localPlayer) && !(damage <= 0f)) { TryBroadcastPlayerDamageGrunt(val); } } } [HarmonyPatch(typeof(Player), "Awake")] public static class Player_Awake_PlayerSfxRpc_Patch { private static void Postfix(Player __instance) { RegisterPlayerSfxRpc(__instance); RegisterPickaxeBedrockAudioRpc(__instance); } } [HarmonyPatch(typeof(Player), "OnDeath")] public static class Player_OnDeath_DeathSplat_Patch { private static void Postfix(Player __instance) { if (!((Object)(object)__instance == (Object)null) && !((Object)(object)__instance != (Object)(object)Player.m_localPlayer)) { TryBroadcastPlayerDeathSplat(__instance); } } } [HarmonyPatch(typeof(Attack), "SpawnOnHitTerrain")] public static class Attack_SpawnOnHitTerrain_PickaxeBedrockTracking_Patch { private static void Prefix(Vector3 hitPoint, GameObject prefab, Character character, ItemData weapon) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) RegisterLocalPickaxeTerrainHit(hitPoint, prefab, character, weapon); } } [HarmonyPatch(typeof(TerrainOp), "OnPlaced")] public static class TerrainOp_OnPlaced_PickaxeBedrockAudio_Patch { private static void Prefix(TerrainOp __instance) { TryHandlePickaxeBedrockHit(__instance); } } [HarmonyPatch(typeof(Attack), "DoMeleeAttack")] private static class Attack_DoMeleeAttack_PickaxeVegetationAudioContext { private static void Prefix(Attack __instance, out bool __state) { __state = BeginLocalPickaxeVegetationAudio(__instance); } private static Exception Finalizer(bool __state, Exception __exception) { EndLocalPickaxeVegetationAudio(__state); return __exception; } } [HarmonyPatch(typeof(Destructible), "Damage")] private static class Destructible_Damage_PickaxeVegetationAudio_Patch { private static void Prefix(Destructible __instance, HitData hit) { try { TryReplayPickaxeVegetationHitEffect((Component)(object)__instance, __instance?.m_hitEffect, hit); } catch (Exception arg) { ManualLogSource log = Log; if (log != null) { log.LogError((object)$"[ValheimBB] Error replaying pickaxe destructible vegetation hit effect: {arg}"); } } } } [HarmonyPatch(typeof(WearNTear), "Damage")] private static class WearNTear_Damage_PickaxeVegetationAudio_Patch { private static void Prefix(WearNTear __instance, HitData hit) { try { TryReplayPickaxeVegetationHitEffect((Component)(object)__instance, __instance?.m_hitEffect, hit); } catch (Exception arg) { ManualLogSource log = Log; if (log != null) { log.LogError((object)$"[ValheimBB] Error replaying pickaxe wear-and-tear vegetation hit effect: {arg}"); } } } } [HarmonyPatch(typeof(ZSFX), "Awake")] public static class ZSFX_Awake_TrainingDummySoundRange_Patch { private static void Prefix(ZSFX __instance) { if (!((Object)(object)__instance == (Object)null) && ((Object)((Component)__instance).gameObject).name.StartsWith("sfx_trainingdummy_", StringComparison.OrdinalIgnoreCase)) { AudioSource component = ((Component)__instance).GetComponent<AudioSource>(); if ((Object)(object)component != (Object)null) { component.maxDistance = 50f; } } } } [HarmonyPatch(typeof(AudioMan), "SelectRandomAmbientClip")] private static class AudioMan_SelectRandomAmbientClip_RemoveWaterEmergeSounds_Patch { private static void Postfix(ref AudioClip clip, ref bool __result) { if (__result && IsWaterEmergeSound(clip)) { clip = null; __result = false; } } } [HarmonyPatch(typeof(Chat), "InputText")] public static class Chat_InputText_Patch { private const float DefaultRemovePinRadius = 10f; private static readonly MethodInfo GetClosestSavedPin = AccessTools.Method(typeof(Minimap), "GetClosestPin", new Type[3] { typeof(Vector3), typeof(float), typeof(bool) }, (Type[])null); private static bool Prefix(ref Chat __instance) { string text = ((TMP_InputField)((Terminal)__instance).m_input).text; if (string.IsNullOrWhiteSpace(text)) { return true; } if (!text.StartsWith("/", StringComparison.Ordinal)) { return true; } if (text.StartsWith("/addpin", StringComparison.OrdinalIgnoreCase)) { HandleAddPin(__instance, text); return false; } if (text.StartsWith("/removepin", StringComparison.OrdinalIgnoreCase)) { HandleRemoveNearestPin(__instance, text); return false; } if (text.StartsWith("/cleardeaths", StringComparison.OrdinalIgnoreCase)) { HandleClearDeathPins(__instance); return false; } return true; } private static void HandleAddPin(Chat chat, string text) { //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Unknown result type (might be due to invalid IL or missing references) //IL_00cd: Unknown result type (might be due to invalid IL or missing references) //IL_00d9: Unknown result type (might be due to invalid IL or missing references) //IL_00df: Unknown result type (might be due to invalid IL or missing references) //IL_00f7: Unknown result type (might be due to invalid IL or missing references) //IL_00fd: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)Player.m_localPlayer == (Object)null || (Object)(object)Minimap.instance == (Object)null) { return; } string[] array = text.Split(new char[1] { ' ' }, StringSplitOptions.RemoveEmptyEntries); if (array.Length >= 2 && array[1].Equals("help", StringComparison.OrdinalIgnoreCase)) { ShowHelp(); ((TMP_InputField)((Terminal)chat).m_input).text = string.Empty; return; } PinType val = (PinType)3; int num = 3; if (array.Length >= 2) { string text2 = array[1]; if (text2.StartsWith("icon", StringComparison.OrdinalIgnoreCase)) { text2 = text2.Substring(4); } if (int.TryParse(text2, out var result) && result >= 0 && result <= 4 && Enum.TryParse<PinType>("Icon" + result, out PinType result2)) { val = result2; num = result; } } Vector3 position = ((Component)Player.m_localPlayer).transform.position; Minimap.instance.AddPin(position, val, "", true, false, 0L, default(PlatformUserID)); ManualLogSource log = Log; if (log != null) { log.LogInfo((object)$"[ValheimBB] /addpin -> {val} at {position}"); } if ((Object)(object)Chat.instance != (Object)null) { ((Terminal)Chat.instance).AddString("ValheimBB", $"Pin {num} added.\n" + "Options: Pin 0 = Campfire, Pin 1 = House, Pin 2 = Anchor, Pin 3 = Dot, Pin 4 = Portal", (Type)1, false); } ((TMP_InputField)((Terminal)chat).m_input).text = string.Empty; } private static void HandleRemoveNearestPin(Chat chat, string text) { //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)Player.m_localPlayer == (Object)null) && !((Object)(object)Minimap.instance == (Object)null)) { float num = 10f; string[] array = text.Split(new char[1] { ' ' }, StringSplitOptions.RemoveEmptyEntries); if (array.Length >= 2 && InputSanitizing.TryParseFiniteFloat(array[1], out var value) && value > 0f) { num = value; } Vector3 position = ((Component)Player.m_localPlayer).transform.position; bool flag = RemoveNearestSavedPin(Minimap.instance, position, num); if ((Object)(object)Chat.instance != (Object)null) { string text2 = (flag ? $"Removed nearest pin within {num:0.#}m." : $"No pin found within {num:0.#}m."); ((Terminal)Chat.instance).AddString("ValheimBB", text2, (Type)1, false); } ((TMP_InputField)((Terminal)chat).m_input).text = string.Empty; } } internal static bool RemoveNearestSavedPin(Minimap minimap, Vector3 position, float radius) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Expected O, but got Unknown PinData val = (PinData)GetClosestSavedPin.Invoke(minimap, new object[3] { position, radius, false }); if (val == null) { return false; } minimap.RemovePin(val); return true; } private static void HandleClearDeathPins(Chat chat) { //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Invalid comparison between Unknown and I4 if ((Object)(object)Minimap.instance == (Object)null) { return; } int num = 0; try { Minimap instance = Minimap.instance; FieldInfo field = typeof(Minimap).GetField("m_pins", BindingFlags.Instance | BindingFlags.NonPublic); if (field == null) { ManualLogSource log = Log; if (log != null) { log.LogWarning((object)"[ValheimBB] Could not find Minimap.m_pins via reflection."); } return; } if (!(field.GetValue(instance) is List<PinData> list)) { ManualLogSource log2 = Log; if (log2 != null) { log2.LogWarning((object)"[ValheimBB] Minimap.m_pins is null or of unexpected type."); } return; } List<PinData> list2 = new List<PinData>(); foreach (PinData item in list) { if ((int)item.m_type == 4) { list2.Add(item); } } num = list2.Count; foreach (PinData item2 in list2) { instance.RemovePin(item2); } if ((Object)(object)Chat.instance != (Object)null) { string text = ((num > 0) ? $"Removed {num} death marker(s)." : "No death markers found."); ((Terminal)Chat.instance).AddString("ValheimBB", text, (Type)1, false); } } catch (Exception arg) { ManualLogSource log3 = Log; if (log3 != null) { log3.LogError((object)$"[ValheimBB] Error clearing death pins: {arg}"); } } finally { ((TMP_InputField)((Terminal)chat).m_input).text = string.Empty; } } public static void ShowHelp() { if (!((Object)(object)Chat.instance == (Object)null)) { string text = "ValheimBB command help:\n/addpin [index] - Add a map pin at your current position.\n index: 0 = Campfire, 1 = House, 2 = Anchor, 3 = Dot, 4 = Portal (default: 3)\n/removepin [radius] - Remove the nearest pin within the given radius (meters).\n radius: optional, default is 10.\n/cleardeaths - Remove all death markers from the map."; ((Terminal)Chat.instance).AddString("ValheimBB", text, (Type)1, false); } } } private struct TerrainRadii { public float ModifierLevel; public float ModifierSmooth; public float ModifierPaint; public float OpLevel; public float OpRaise; public float OpSmooth; public float OpPaint; public static TerrainRadii Read(TerrainModifier modifier, TerrainOp op) { TerrainRadii result = default(TerrainRadii); if ((Object)(object)modifier != (Object)null) { result.ModifierLevel = modifier.m_levelRadius; result.ModifierSmooth = modifier.m_smoothRadius; result.ModifierPaint = modifier.m_paintRadius; } if ((Object)(object)op != (Object)null && op.m_settings != null) { result.OpLevel = op.m_settings.m_levelRadius; result.OpRaise = op.m_settings.m_raiseRadius; result.OpSmooth = op.m_settings.m_smoothRadius; result.OpPaint = op.m_settings.m_paintRadius; } return result; } public void Write(TerrainModifier modifier, TerrainOp op) { if ((Object)(object)modifier != (Object)null) { modifier.m_levelRadius = ModifierLevel; modifier.m_smoothRadius = ModifierSmooth; modifier.m_paintRadius = ModifierPaint; } if ((Object)(object)op != (Object)null && op.m_settings != null) { op.m_settings.m_levelRadius = OpLevel; op.m_settings.m_raiseRadius = OpRaise; op.m_settings.m_smoothRadius = OpSmooth; op.m_settings.m_paintRadius = OpPaint; } } } private sealed class ValheimBBCompendiumEntry { private readonly Func<string> _textFactory; private string _text; public string Label { get; } public string Name { get; } public string Topic { get; } public string Text { get { if (_text == null) { _text = _textFactory() ?? string.Empty; } return _text; } } public ValheimBBCompendiumEntry(string name, string topic, string label, string text) : this(name, topic, label, () => text) { } public ValheimBBCompendiumEntry(string name, string topic, string label, Func<string> textFactory) { if (textFactory == null) { throw new ArgumentNullException("textFactory"); } Name = name; Topic = topic; Label = label; _textFactory = textFactory; } } [HarmonyPatch] private static class Tutorial_Awake_ValheimBBCompendium_Patch { private static MethodBase TargetMethod() { Type type = AccessTools.TypeByName("Tutorial"); if (!(type == null)) { return AccessTools.Method(type, "Awake", (Type[])null, (Type[])null); } return null; } private static void Postfix(object __instance) { EnsureValheimBBCompendiumEntries(__instance); } } [HarmonyPatch(typeof(Player), "GetKnownTexts")] private static class Player_GetKnownTexts_ValheimBBCompendium_Patch { private static void Postfix(ref List<KeyValuePair<string, string>> __result) { EnsureValheimBBKnownTexts(__result); } } [Flags] private enum DeveloperModes { None = 0, God = 1, Ghost = 2, Fly = 4, Build = 8, Debug = 0x10 } [HarmonyPatch(typeof(Terminal), "InitTerminal")] private static class Terminal_RegisterDeveloperCommands_Patch { private static void Postfix() { //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Expected O, but got Unknown //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Expected O, but got Unknown //IL_0054: Unknown result type (might be due to invalid IL or missing references) if (!s_developerCommandsRegistered) { s_developerCommandsRegistered = true; new ConsoleCommand("bbdev", "on/off/status: unlock player cheat commands and spawning for this session.", new ConsoleEvent(HandleDeveloperSessionCommand), false, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false); new ConsoleCommand("bbcleanup", "on/status: permanently enable dev-command marking cleanup for this profile.", new ConsoleEvent(HandleCleanupCommand), false, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false); } } } [HarmonyPatch(typeof(ConsoleCommand), "IsValid")] private static class ConsoleCommand_DeveloperPermission_Patch { private static void Postfix(ConsoleCommand __instance, Terminal context, ref bool __result) { if (!__result && context is Console && IsDeveloperSessionActive(Player.m_localPlayer) && DeveloperPlayerCommands.Contains(__instance.Command)) { __result = true; } } } [HarmonyPatch(typeof(ConsoleCommand), "RunAction")] private static class ConsoleCommand_DeveloperSpawnTame_Patch { private static void Prefix(ConsoleCommand __instance, ref ConsoleEventArgs args, out HashSet<Character> __state) { //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Expected O, but got Unknown __state = null; if (args.Context is Console && IsDeveloperSessionActive(Player.m_localPlayer) && __instance.Command.Equals("spawn", StringComparison.OrdinalIgnoreCase) && args.Length >= 3 && args[2].Equals("tame", StringComparison.OrdinalIgnoreCase)) { List<string> list = new List<string>(args.Args); list.RemoveAt(2); args = new ConsoleEventArgs(string.Join(" ", list), args.Context, __instance); __state = new HashSet<Character>(Character.GetAllCharacters()); } } private static void Postfix(HashSet<Character> __state) { if (__state == null || !IsDeveloperSessionActive(Player.m_localPlayer)) { return; } foreach (Character item in new List<Character>(Character.GetAllCharacters())) { if (!((Object)(object)item == (Object)null) && !__state.Contains(item) && !item.IsTamed()) { Tameable component = ((Component)item).GetComponent<Tameable>(); if ((Object)(object)component != (Object)null) { DeveloperTameCreature.Invoke(component, null); } } } } } [HarmonyPatch(typeof(ConsoleCommand), "RunAction")] private static class ConsoleCommand_TrackDeveloperModes_Patch { private static void Prefix(ConsoleCommand __instance, ConsoleEventArgs args, out DeveloperModes? __state) { __state = ((args.Context is Console && IsDeveloperSessionActive(Player.m_localPlayer) && DeveloperPlayerCommands.Contains(__instance.Command)) ? new DeveloperModes?(GetDeveloperModes(Player.m_localPlayer)) : ((DeveloperModes?)null)); } private static void Postfix(DeveloperModes? __state) { if (__state.HasValue && IsDeveloperSessionActive(Player.m_localPlayer)) { RecordDeveloperModes(__state.Value, Player.m_localPlayer); } } } [HarmonyPatch(typeof(Player), "OnSpawned")] private static class Player_Spawn_LockDeveloperSession_Patch { private static void Postfix(Player __instance) { if ((Object)(object)__instance == (Object)(object)Player.m_localPlayer) { LockDeveloperSession(); } } } [HarmonyPatch(typeof(ZNet), "Shutdown")] private static class ZNet_Shutdown_LockDeveloperSession_Patch { private static void Prefix() { LockDeveloperSession(); } } private sealed class AmmoRecipeBatchTweakDefinition { public string RecipeName; public string OutputPrefabName; public HashSet<string> StaticRequirementPrefabNames; public Dictionary<string, int> VanillaRequirementAmounts; public bool TryGetTargetRequirementAmount(string requirementPrefabName, out int amount) { amount = 0; if (string.IsNullOrWhiteSpace(requirementPrefabName) || VanillaRequirementAmounts == null || !VanillaRequirementAmounts.TryGetValue(requirementPrefabName, out var value)) { return false; } amount = ((StaticRequirementPrefabNames != null && StaticRequirementPrefabNames.Contains(requirementPrefabName)) ? value : (value * 5)); return true; } } private struct AmmoRequirementBaseline { public string PrefabName; public int Amount; public AmmoRequirementBaseline(string prefabName, int amount) { PrefabName = prefabName; Amount = amount; } } [HarmonyPatch(typeof(ObjectDB), "Awake")] private static class ObjectDB_Awake_AmmoRecipeBatchTweaks_Patch { private static void Postfix(ObjectDB __instance) { ApplyAmmoRecipeBatchTweaks(__instance); } } [HarmonyPatch(typeof(ObjectDB), "CopyOtherDB")] private static class ObjectDB_CopyOtherDB_AmmoRecipeBatchTweaks_Patch { private static void Postfix(ObjectDB __instance) { ApplyAmmoRecipeBatchTweaks(__instance); } } [HarmonyPatch(typeof(ObjectDB), "Awake")] private static class ObjectDB_Awake_BearHeaddressRecipe_Patch { private static void Postfix(ObjectDB __instance) { UpdateBearHeaddressRecipe(__instance); } } [HarmonyPatch(typeof(ObjectDB), "CopyOtherDB")] private static class ObjectDB_CopyOtherDB_BearHeaddressRecipe_Patch { private static void Postfix(ObjectDB __instance) { UpdateBearHeaddressRecipe(__instance); } } [HarmonyPatch(typeof(EggGrow), "Start")] private static class EggGrow_Start_ColdEggAutoPickup_Patch { private static void Postfix(EggGrow __instance, ItemDrop ___m_item, ZNetView ___m_nview) { if (!((Object)(object)___m_nview == (Object)null) && ___m_nview.IsValid()) { UpdateColdEggAutoPickup(__instance, ___m_item, ___m_nview.GetZDO().GetFloat(ZDOVars.s_growStart, 0f)); } } } [HarmonyPatch(typeof(EggGrow), "UpdateEffects")] private static class EggGrow_UpdateEffects_ColdEggAutoPickup_Patch { private static void Postfix(EggGrow __instance, ItemDrop ___m_item, float grow) { UpdateColdEggAutoPickup(__instance, ___m_item, grow); } } [HarmonyPatch(typeof(Character), "ApplyPushback", new Type[] { typeof(Vector3), typeof(float) })] private static class Character_ApplyPushback_CreatureMassScaling_Patch { private static void Prefix(Character __instance, ref float pushForce) { if (IsFeatureEnabled(EnableCreaturePushbackScaling) && !((Object)(object)__instance == (Object)null) && !__instance.IsPlayer() && pushForce != 0f) { Rigidbody component = ((Component)__instance).GetComponent<Rigidbody>(); if (!((Object)(object)component == (Object)null) && !(component.mass <= 10f)) { float num = component.mass / 10f; float num2 = 1f + Mathf.Log(num, 2f) * 0.25f; pushForce *= Mathf.Min(num2, 2f); } } } } private struct PreviousLoadedWeaponState { public ItemData Weapon; } [HarmonyPatch] private static class Player_UpdateWeaponLoading_PersistentCrossbowLoad_Patch { private static MethodBase TargetMethod() { return AccessTools.Method(typeof(Player), "UpdateWeaponLoading", (Type[])null, (Type[])null); } private static bool Prefix(Player __instance, ItemData weapon, float dt) { if (!IsFeatureEnabled(EnableCrossbowLoadedPersistence)) { return true; } ClearInvalidLoadedWeapon(__instance); ItemData loadedWeapon = GetLoadedWeapon(__instance); if (!RequiresReload(weapon)) { return false; } if (HasPersistentLoadedFlag(weapon)) { if (loadedWeapon != weapon) { SetLoadedWeapon(__instance, weapon); } return false; } if (!IsReloadActionQueued(__instance) && ((Character)__instance).TryUseEitr(weapon.m_shared.m_attack.m_reloadEitrDrain)) { QueueReloadAction(__instance); } return false; } } [HarmonyPatch] private static class Player_SetWeaponLoaded_PersistentCrossbowLoad_Patch { private static MethodBase TargetMethod() { return AccessTools.Method(typeof(Player), "SetWeaponLoaded", (Type[])null, (Type[])null); } private static void Prefix(Player __instance, out PreviousLoadedWeaponState __state) { __state = new PreviousLoadedWeaponState { Weapon = (IsFeatureEnabled(EnableCrossbowLoadedPersistence) ? GetLoadedWeapon(__instance) : null) }; } private static void Postfix(Player __instance, ItemData weapon, PreviousLoadedWeaponState __state) { if (IsFeatureEnabled(EnableCrossbowLoadedPersistence)) { if (weapon == null && __state.Weapon != null) { SetPersistentLoadedFlag(__state.Weapon, isLoaded: false); } if (RequiresReload(weapon)) { SetPersistentLoadedFlag(weapon, isLoaded: true); } } } } [HarmonyPatch] private static class Player_IsWeaponLoaded_PersistentCrossbowLoad_Patch { private static MethodBase TargetMethod() { return AccessTools.Method(typeof(Player), "IsWeaponLoaded", (Type[])null, (Type[])null); } private static void Postfix(Player __instance, ref bool __result) { if (!IsFeatureEnabled(EnableCrossbowLoadedPersistence) || (Object)(object)__instance == (Object)null || (Object)(object)__instance != (Object)(object)Player.m_localPlayer) { return; } ItemData currentWeapon = ((Humanoid)__instance).GetCurrentWeapon(); if (!RequiresReload(currentWeapon)) { __result = false; } else if (HasPersistentLoadedFlag(currentWeapon)) { if (GetLoadedWeapon(__instance) != currentWeapon) { SetLoadedWeapon(__instance, currentWeapon); } __result = true; } else { if (GetLoadedWeapon(__instance) == currentWeapon) { ClearLoadedWeapon(__instance); } __result = false; } } } [HarmonyPatch(typeof(Humanoid), "UnequipItem")] private static class Humanoid_UnequipItem_PersistentCrossbowLoad_Patch { private static void Prefix(Humanoid __instance, ItemData item) { s_loadedWeaponPreservePlayer = null; s_loadedWeaponPreserveItem = null; if (!IsFeatureEnabled(EnableCrossbowLoadedPersistence)) { return; } Player val = (Player)(object)((__instance is Player) ? __instance : null); if (!((Object)(object)val == (Object)null) && item != null) { ItemData loadedWeapon = GetLoadedWeapon(val); if (CanPersistLoadedWeapon(val, loadedWeapon)) { s_loadedWeaponPreservePlayer = val; s_loadedWeaponPreserveItem = loadedWeapon; } } } private static void Finalizer() { s_loadedWeaponPreservePlayer = null; s_loadedWeaponPreserveItem = null; } } [HarmonyPatch(typeof(Player), "ResetLoadedWeapon")] private static class Player_ResetLoadedWeapon_PersistentCrossbowLoad_Patch { private static bool Prefix(Player __instance) { if (!IsFeatureEnabled(EnableCrossbowLoadedPersistence)) { return true; } if ((Object)(object)s_loadedWeaponPreservePlayer != (Object)(object)__instance || s_loadedWeaponPreserveItem == null) { return true; } if (!CanPersistLoadedWeapon(__instance, s_loadedWeaponPreserveItem)) { return true; } CancelReloadAction(__instance); return false; } } [HarmonyPatch(typeof(Attack), "Start", new Type[] { typeof(Humanoid), typeof(Rigidbody), typeof(ZSyncAnimation), typeof(CharacterAnimEvent), typeof(VisEquipment), typeof(ItemData), typeof(Attack), typeof(float), typeof(float) })] private static class Attack_Start_PersistentCrossbowLoad_Patch { private static bool Prefix(Humanoid character, ItemData weapon, ref bool __result) { if (!IsFeatureEnabled(EnableCrossbowLoadedPersistence)) { return true; } Player val = (Player)(object)((character is Player) ? character : null); if ((Object)(object)val == (Object)null || (Object)(object)val != (Object)(object)Player.m_localPlayer || !RequiresReload(weapon)) { return true; } if (HasPersistentLoadedFlag(weapon)) { if (GetLoadedWeapon(val) != weapon) { SetLoadedWeapon(val, weapon); } return true; } __result = false; return false; } } [HarmonyPatch(typeof(Ragdoll), "Setup")] private static class Ragdoll_Setup_FasterLoot_Patch { private static void Postfix(Ragdoll __instance, CharacterDrop characterDrop) { if (IsFeatureEnabled(EnableFasterMonsterLoot) && !((Object)(object)characterDrop == (Object)null)) { Character component = ((Component)characterDrop).GetComponent<Character>(); if (!((Object)(object)component == (Object)null) && !component.IsPlayer() && !(__instance.m_ttl <= 0f)) { ((MonoBehaviour)__instance).CancelInvoke("DestroyNow"); ((MonoBehaviour)__instance).InvokeRepeating("DestroyNow", Mathf.Max(0.01f, __instance.m_ttl * 0.5f), 1f); } } } } [HarmonyPatch(typeof(Fireplace), "Interact")] public static class Fireplace_Interact_AltFuel_Patch { private static void Prefix(Fireplace __instance, Humanoid user, bool hold, bool alt, ref ItemDrop __state) { __state = null; try { if (!IsFeatureEnabled(EnableAlternateFireFuel) || !TryWoodFuel(__instance.m_fuelItem, out var _) || (Object)(object)user == (Object)null) { return; } Inventory inventory = user.GetInventory(); if (inventory == null || inventory.GetItem("Wood", -1, true) != null) { return; } ItemData val = inventory.GetItem("RoundLog", -1, true) ?? inventory.GetItem("ElderBark", -1, true); if (val != null && !((Object)(object)val.m_dropPrefab == (Object)null)) { ItemDrop component = val.m_dropPrefab.GetComponent<ItemDrop>(); if (!((Object)(object)component == (Object)null)) { __state = __instance.m_fuelItem; __instance.m_fuelItem = component; } } } catch (Exception arg) { ManualLogSource log = Log; if (log != null) { log.LogError((object)$"[ValheimBB] Error in Fireplace.Interact alt-fuel Prefix: {arg}"); } } } private static void Finalizer(Fireplace __instance, ItemDrop __state) { try { if ((Object)(object)__state != (Object)null) { __instance.m_fuelItem = __state; } } catch (Exception arg) { ManualLogSource log = Log; if (log != null) { log.LogError((object)$"[ValheimBB] Error restoring fireplace fuel item: {arg}"); } } } } [HarmonyPatch(typeof(Player), "ActivateGuardianPower")] public static class Player_ActivateGuardianPower_ModerDuration_Patch { private static void Prefix(StatusEffect ___m_guardianSE) { try { if (!((Object)(object)___m_guardianSE == (Object)null) && !(((Object)___m_guardianSE).name != "GP_Moder")) { float ttl = ___m_guardianSE.m_ttl; ___m_guardianSE.m_ttl = 600f; ManualLogSource log = Log; if (log != null) { log.LogInfo((object)$"[ValheimBB] Moder buff duration changed from {ttl} to {___m_guardianSE.m_ttl} seconds."); } } } catch (Exception arg) { ManualLogSource log2 = Log; if (log2 != null) { log2.LogError((object)$"[ValheimBB] Error while extending Moder power duration: {arg}"); } } } } [HarmonyPatch(typeof(EnvMan), "GetWindDir")] public static class EnvMan_GetWindDir_ModerSideWind_Patch { internal static readonly int s_moderStatusEffectHash = StringExtensionMethods.GetStableHashCode("GP_Moder"); private static void Postfix(ref Vector3 __result) { //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Unknown result type (might be due to invalid IL or missing references) try { if ((Object)(object)Player.m_localPlayer == (Object)null) { return; } SEMan sEMan = ((Character)Player.m_localPlayer).GetSEMan(); if (sEMan == null || !sEMan.HaveStatusEffect(s_moderStatusEffectHash)) { return; } Ship localShip = Ship.GetLocalShip(); if ((Object)(object)localShip == (Object)null) { return; } Vector3 forward = ((Component)localShip).transform.forward; forward.y = 0f; if (!(((Vector3)(ref forward)).sqrMagnitude < 0.0001f)) { ((Vector3)(ref forward)).Normalize(); Vector3 val = Vector3.Cross(Vector3.up, forward); if (!(((Vector3)(ref val)).sqrMagnitude < 0.0001f)) { ((Vector3)(ref val)).Normalize(); __result = val; } } } catch (Exception arg) { ManualLogSource log = Log; if (log != null) { log.LogError((object)$"[ValheimBB] Error in Moder side-wind GetWindDir patch: {arg}"); } } } } internal static class AsksvinCloakTailwind { private static readonly int s_windRunHash = StringExtensionMethods.GetStableHashCode("WindRun"); internal static float Suspend(SE_Stats effect, Character wearer, ref float windModifier) { float num = windModifier; if (num == 0f || ((StatusEffect)effect).NameHash() != s_windRunHash || (Object)(object)EnvMan.instance == (Object)null) { return 0f; } if ((Object)(object)wearer == (Object)null || !wearer.GetSEMan().HaveStatusEffect(EnvMan_GetWindDir_ModerSideWind_Patch.s_moderStatusEffectHash)) { return 0f; } windModifier = 0f; return num; } internal static float FullTailwindFactor(float windModifier) { if (windModifier != 0f) { return 1f + EnvMan.instance.GetWindIntensity() * windModifier; } return 1f; } } [HarmonyPatch(typeof(SE_Stats), "ModifySpeed")] public static class SE_Stats_ModifySpeed_AsksvinTailwind_Patch { private static void Prefix(SE_Stats __instance, Character ___m_character, out float __state) { __state = AsksvinCloakTailwind.Suspend(__instance, ___m_character, ref __instance.m_windMovementModifier); } private static void Postfix(ref float speed, float __state) { if (__state != 0f) { speed *= AsksvinCloakTailwind.FullTailwindFactor(__state); if (speed < 0f) { speed = 0f; } } } private static void Finalizer(SE_Stats __instance, float __state) { if (__state != 0f) { __instance.m_windMovementModifier = __state; } } } [HarmonyPatch(typeof(SE_Stats), "ModifyRunStaminaDrain")] public static class SE_Stats_ModifyRunStaminaDrain_AsksvinTailwind_Patch { private static void Prefix(SE_Stats __instance, Character ___m_character, out float __state) { __state = AsksvinCloakTailwind.Suspend(__instance, ___m_character, ref __instance.m_windRunStaminaModifier); } private static void Postfix(ref float drain, float __state) { if (__state != 0f) { drain *= AsksvinCloakTailwind.FullTailwindFactor(__state); } } private static void Finalizer(SE_Stats __instance, float __state) { if (__state != 0f) { __instance.m_windRunStaminaModifier = __state; } } } private struct IdolDropRoll { public DropTable Table; public List<DropData> OriginalDrops; public DropTable PreviousTable; } [HarmonyPatch(typeof(Container), "AddDefaultItems")] private static class Container_AddDefaultItems_IdolDrops_Patch { private static void Prefix(Container __instance, out IdolDropRoll __state) { ZNetView val = s_containerNviewRef.Invoke(__instance); __state = BeginIdolDropRoll(__instance.m_defaultItems, ((Object)(object)val != (Object)null) ? ((Component)val).gameObject : ((Component)__instance).gameObject); } private static void Finalizer(IdolDropRoll __state) { EndIdolDropRoll(__state); } } [HarmonyPatch(typeof(DropOnDestroyed), "OnDestroyed")] private static class DropOnDestroyed_OnDestroyed_IdolDrops_Patch { private static void Prefix(DropOnDestroyed __instance, out IdolDropRoll __state) { __state = BeginIdolDropRoll(__instance.m_dropWhenDestroyed, ((Component)__instance).gameObject); } private static void Finalizer(IdolDropRoll __state) { EndIdolDropRoll(__state); } } [HarmonyPatch(typeof(DropTable), "GetDropListItems")] private static class DropTable_GetDropListItems_IdolDrops_Patch { private static void Postfix(DropTable __instance, List<ItemData> __result) { if (__result == null || __instance != s_idolDropTable) { return; } foreach (ItemData item in __result) { if ((Object)(object)item?.m_dropPrefab != (Object)null && IdolDrops.IsIdol(((Object)item.m_dropPrefab).name)) { item.m_stack = IdolDrops.ScaleStack(item.m_stack, item.m_shared.m_maxStackSize); } } } } [HarmonyPatch(typeof(DropTable), "GetDropList", new Type[] { })] private static class DropTable_GetDropList_IdolDrops_Patch { [HarmonyPriority(600)] private static void Postfix(DropTable __instance, List<GameObject> __result) { if (__result == null || __instance != s_idolDropTable) { return; } for (int num = __result.Count - 1; num >= 0; num--) { GameObject val = __result[num]; if (!((Object)(object)val == (Object)null) && IdolDrops.IsIdol(((Object)val).name)) { for (int i = 1; i < 3; i++) { __result.Insert(num + 1, val); } } } } } private sealed class ForgeRecipeInfo { public Recipe Source; public RefinementItem Entry; public RefinementRank Rank; } private struct ForgeRefinementCarry { public bool Active; public ItemData Source; public string SharedName; public string Value; } private struct ForgeListCandidate { public Recipe Recipe; public ItemData Item; public bool CanCraft; public string SortName; } [HarmonyPatch(typeof(ItemData), "GetDamage", new Type[] { typeof(int), typeof(float) })] [HarmonyBefore(new string[] { "randyknapp.mods.epicloot" })] private static class ItemData_GetDamage_ForgeRefinement_Patch { private static void Postfix(ItemData __instance, int quality, ref DamageTypes __result) { //IL_001e: Unknown result type (might be due to invalid IL or missing references) if (TryGetActiveForgeRefinement(__instance, quality, out var entry, out var rank)) { if (entry.Effect == StaffEffect.SpellLevel) { ((DamageTypes)(ref __result)).Add(__instance.m_shared.m_damagesPerLevel, entry.SpellLevelBonus(rank)); } if (entry.IsWeapon) { float num = entry.ValueBonus(rank); DamageShares shares = entry.Shares; __result.m_blunt += num * shares.Blunt; __result.m_slash += num * shares.Slash; __result.m_pierce += num * shares.Pierce; __result.m_frost += num * shares.Frost; __result.m_lightning += num * shares.Lightning; __result.m_pickaxe += num * shares.Pickaxe; } } } } [HarmonyPatch(typeof(ItemData), "GetBaseBlockPower", new Type[] { typeof(int) })] [HarmonyBefore(new string[] { "randyknapp.mods.epicloot" })] private static class ItemData_GetBaseBlockPower_ForgeRefinement_Patch { private static void Postfix(ItemData __instance, int quality, ref float __result) { if (TryGetActiveForgeRefinement(__instance, quality, out var entry, out var rank)) { if (entry.Kind == RefinementKind.Shield) { __result += entry.ValueBonus(rank); } else if (entry.IsWeapon) { __result += entry.BlockBonus(rank); } } } } [HarmonyPatch(typeof(ItemData), "GetArmor", new Type[] { typeof(int), typeof(float) })] [HarmonyBefore(new string[] { "randyknapp.mods.epicloot" })] private static class ItemData_GetArmor_ForgeRefinement_Patch { private static void Postfix(ItemData __instance, int quality, ref float __result) { if (TryGetActiveForgeRefinement(__instance, quality, out var entry, out var rank) && (entry.Kind == RefinementKind.Armor || entry.Kind == RefinementKind.Cape)) { __result += entry.ValueBonus(rank); } } } [HarmonyPatch(typeof(ItemData), "GetDrawStaminaDrain")] [HarmonyAfter(new string[] { "randyknapp.mods.epicloot" })] private static class ItemData_GetDrawStaminaDrain_ForgeRefinement_Patch { private static void Postfix(ItemData __instance, ref float __result) { if (!(__result <= 0f) && TryGetActiveForgeRefinement(__instance, __instance.m_quality, out var entry, out var rank) && entry.Kind == RefinementKind.Bow) { float drawStaminaDrain = __instance.m_shared.m_attack.m_drawStaminaDrain; if (drawStaminaDrain > 0f) { __result *= entry.RefinedStamina(rank, drawStaminaDrain, secondary: false) / drawStaminaDrain; } } } } [HarmonyPatch(typeof(Humanoid), "StartAttack", new Type[] { typeof(Character), typeof(bool) })] private static class Humanoid_StartAttack_ForgeRefinement_Patch { private static void Prefix(bool secondaryAttack, out bool __state) { __state = s_forgeAttackContextActive; s_forgeAttackContextActive = true; s_forgeAttackIsSecondary = secondaryAttack; } private static void Finalizer(bool __state) { s_forgeAttackContextActive = __state; } } [HarmonyPatch(typeof(Attack), "Start", new Type[] { typeof(Humanoid), typeof(Rigidbody), typeof(ZSyncAnimation), typeof(CharacterAnimEvent), typeof(VisEquipment), typeof(ItemData), typeof(Attack), typeof(float), typeof(float) })] private static class Attack_Start_ForgeRefinement_Patch { private static void Prefix(Attack __instance, ItemData weapon) { if (weapon?.m_shared != null && !(__instance.m_attackStamina <= 0f) && __instance != weapon.m_shared.m_attack && __instance != weapon.m_shared.m_secondaryAttack) { bool secondary = s_forgeAttackContextActive && s_forgeAttackIsSecondary; __instance.m_attackStamina = GetRefinedAttackStamina(weapon, __instance.m_attackStamina, secondary); } } } [HarmonyPatch(typeof(ItemData), "GetTooltip", new Type[] { typeof(ItemData), typeof(int), typeof(bool), typeof(float), typeof(int), typeof(bool) })] private static class ItemData_GetTooltip_ForgeRefinement_Patch { private static void Postfix(ItemData item, int qualityLevel, bool crafting, bool appending, ref string __result) { if (!appending && !crafting) { __result = AddForgeRefinementTooltip(item, qualityLevel, __result); } } } [HarmonyPatch(typeof(InventoryGrid), "UpdateGui")] private static class InventoryGrid_UpdateGui_ForgeRefinement_Patch { private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions) { //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Expected O, but got Unknown FieldInfo field = typeof(ItemData).GetField("m_quality"); MethodInfo method = typeof(int).GetMethod("ToString", Type.EmptyTypes); MethodInfo method2 = new Func<ItemData, string>(GetInventoryQualityLabel).Method; List<CodeInstruction> list = new List<CodeInstruction>(instructions); int num = 0; for (int i = 0; i + 1 < list.Count; i++) { if (!(list[i].opcode != OpCodes.Ldflda) && object.Equals(list[i].operand, field) && CodeInstructionExtensions.Calls(list[i + 1], method)) { CodeInstruction val = new CodeInstruction(OpCodes.Call, (object)method2); val.labels.AddRange(list[i].labels); val.blocks.AddRange(list[i].blocks); list[i] = val; list.RemoveAt(i + 1); num++; } } if (num != 1) { throw new InvalidOperationException("Expected one inventory quality label; found " + num); } return list; } } [HarmonyPatch(typeof(InventoryGui), "UpdateRecipeList")] private static class InventoryGui_UpdateRecipeList_ForgeRefinement_Patch { private static bool Prefix(InventoryGui __instance, List<Recipe> recipes) { Player localPlayer = Player.m_localPlayer; if (!IsForgeRefinementActive() || (Object)(object)localPlayer == (Object)null || recipes == null || __instance.InCraftTab() || !IsForgeStation(localPlayer)) { return true; } BuildForgeRefinementList(__instance, localPlayer, recipes); return false; } } [HarmonyPatch(typeof(InventoryGui), "UpdateRecipe")] private static class InventoryGui_UpdateRecipe_ForgeRefinement_Patch { private static void Postfix(InventoryGui __instance, Player player) { if (IsForgeStation(player) && TryGetSelectedForgeRecipe(__instance, out var info, out var item)) { if ((Object)(object)__instance.m_itemCraftType != (Object)null) { __instance.m_itemCraftType.text = "Refine to " + info.Entry.RankLabel(info.Rank); } if ((Object)(object)__instance.m_recipeDecription != (Object)null) { __instance.m_recipeDecription.text = GetForgePreviewText(info, item); } TMP_Text val = (((Object)(object)__instance.m_craftButton != (Object)null) ? ((Component)__instance.m_craftButton).GetComponentInChildren<TMP_Text>() : null); if ((Object)(object)val != (Object)null) { val.text = "Refine"; } } } } [HarmonyPatch(typeof(InventoryGui), "OnCraftPressed")] private static class InventoryGui_OnCraftPressed_ForgeRefinement_Patch { private static void Prefix(InventoryGui __instance, out bool __state) { __state = TryGetSelectedForgeRecipe(__instance, out var _, out var _); if (__state) { s_forgeCraftPressDepth++; } } private static void Finalizer(bool __state) { if (__state) { s_forgeCraftPressDepth = Math.Max(0, s_forgeCraftPressDepth - 1); } } } [HarmonyPatch(typeof(Inventory), "GetEmptySlots")] private static class Inventory_GetEmptySlots_ForgeRefinement_Patch { private static void Postfix(ref int __result) { if (s_forgeCraftPressDepth > 0) { __result = 1073741823; } } } [HarmonyPatch(typeof(InventoryGui), "DoCrafting")] private static class InventoryGui_DoCrafting_ForgeRefinement_Patch { [HarmonyPriority(200)] private static bool Prefix(InventoryGui __instance, Player player, bool __runOriginal) { s_forgeRefinementCarry = default(ForgeRefinementCarry); if (!__runOriginal || (Object)(object)player == (Object)null) { return __runOriginal; } Recipe recipe = s_inventoryCraftRecipeRef.Invoke(__instance); ItemData val = s_inventoryCraftUpgradeItemRef.Invoke(__instance); if (IsForgeRefinementRecipe(recipe)) { CompleteForgeRefinement(__instance, player, recipe, val); return false; } if (val != null && IsForgeRefinementActive() && IsForgeStation(player)) { ((Character)player).Message((MessageType)2, "The Forge of Potential only refines supported items", 0, (Sprite)null, false); return false; } if (val != null && val.m_customData != null && val.m_customData.TryGetValue("ValheimBB.ForgeRefinement", out var value)) { s_forgeRefinementCarry = new ForgeRefinementCarry { Active = true, Source = val, SharedName = val.m_shared.m_name, Value = value }; } return true; } private static void Finalizer() { s_forgeRefinementCarry = default(ForgeRefinementCarry); } } [HarmonyPatch(typeof(Inventory), "AddItem", new Type[] { typeof(string), typeof(int), typeof(int), typeof(int), typeof(long), typeof(string), typeof(Vector2i), typeof(bool), typeof(bool), typeof(bool) })] private static class Inventory_AddItemByName_ForgeRefinement_Patch { private static void Postfix(ItemData __result) { ForgeRefinementCarry s_forgeRefinementCarry = ValheimBBPlugin.s_forgeRefinementCarry; if (s_forgeRefinementCarry.Active && __result != null && __result != s_forgeRefinementCarry.Source && __result.m_shared != null && !(__result.m_shared.m_name != s_forgeRefinementCarry.SharedName)) { if (__result.m_customData == null) { __result.m_customData = new Dictionary<string, string>(); } if (!__result.m_customData.ContainsKey("ValheimBB.ForgeRefinement")) { __result.m_customData["ValheimBB.ForgeRefinement"] = s_forgeRefinementCarry.Value; } ValheimBBPlugin.s_forgeRefinementCarry = default(ForgeRefinementCarry); } } } private sealed class ForgeChannelSpawn { public float Factor; public readonly List<MonoBehaviour> Spawned = new List<MonoBehaviour>(); } private struct ForgeChannelFrame { public ForgeChannelSpawn Previous; public ForgeChannelSpawn Current; } [HarmonyPatch(typeof(Aoe), "Setup")] private static class Aoe_Setup_ForgeStaff_Patch { private static void Postfix(Aoe __instance, ItemData item) { if (TryGetStaffRefinement(item, StaffEffect.SpellLevel, out var entry, out var rank)) { s_aoeLevelRef.Invoke(__instance) = item.m_quality + entry.SpellLevelBonus(rank); } } } [HarmonyPatch(typeof(ItemData), "GetStatusEffectTooltip")] private static class ItemData_GetStatusEffectTooltip_ForgeStaff_Patch { private static void Prefix(ItemData __instance, ref int quality) { if (TryGetActiveForgeRefinement(__instance, quality, out var entry, out var rank) && entry.Effect == StaffEffect.SpellLevel) { quality += entry.SpellLevelBonus(rank); } } } [HarmonyPatch(typeof(SpawnAbility), "SetupAoe")] private static class SpawnAbility_SetupAoe_ForgeStaff_Patch { private static void Prefix(SpawnAbility __instance, Character owner) { ItemData val = s_spawnAbilityWeaponRef.Invoke(__instance); ZNetView val2 = (((Object)(object)owner != (Object)null) ? ((Component)owner).GetComponent<ZNetView>() : null); if (val != null && !((Object)(object)val2 == (Object)null) && val2.IsValid() && val2.IsOwner() && TryGetActiveForgeRefinement(val, val.m_quality, out var entry, out var rank)) { ZDO zDO = val2.GetZDO(); if (entry.Effect == StaffEffect.SummonHealth) { zDO.Set("ValheimBB.ForgeSummonHealth", entry.EffectFactor(rank)); ApplyForgeSummonHealth(owner, zDO); } else if (entry.Effect == StaffEffect.RootDamage && zDO.GetFloat("ValheimBB.ForgeRootDamage", 0f) <= 0f) { float num = entry.EffectFactor(rank); zDO.Set(ZDOVars.s_randomSkillFactor, zDO.GetFloat(ZDOVars.s_randomSkillFactor, 1f) * num); zDO.Set("ValheimBB.ForgeRootDamage", num); } } } } [HarmonyPatch(typeof(Character), "Awake")] private static class Character_Awake_ForgeStaff_Patch { private static void Postfix(Character __instance) { ZNetView val = s_characterNviewRef.Invoke(__instance); if (!__instance.IsPlayer() && !((Object)(object)val == (Object)null) && val.IsValid() && val.IsOwner() && IsForgeRefinementActive()) { ApplyForgeSummonHealth(__instance, val.GetZDO()); } } } [HarmonyPatch(typeof(Projectile), "SpawnOnHit")] private static class Projectile_SpawnOnHit_ForgeStaff_Patch { private static void Prefix(Projectile __instance, out ForgeChannelFrame __state) { __state = new ForgeChannelFrame { Previous = s_forgeChannelSpawn }; if (TryGetStaffRefinement(s_projectileWeaponRef.Invoke(__instance), StaffEffect.ChannelDamage, out var entry, out var rank)) { __state.Current = new ForgeChannelSpawn { Factor = entry.EffectFactor(rank) }; } s_forgeChannelSpawn = __state.Current; } private static void Finalizer(ForgeChannelFrame __state) { s_forgeChannelSpawn = __state.Previous; if (__state.Current == null) { return; } foreach (MonoBehaviour item in __state.Current.Spawned) { Aoe val = (Aoe)(object)((item is Aoe) ? item : null); if (val != null) { ((DamageTypes)(ref val.m_damage)).Modify(__state.Current.Factor); continue; } Projectile val2 = (Projectile)(object)((item is Projectile) ? item : null); if (val2 != null) { ((DamageTypes)(ref val2.m_damage)).Modify(__state.Current.Factor); } } } } [HarmonyPatch(typeof(Aoe), "Awake")] private static class Aoe_Awake_ForgeStaff_Patch { private static void Postfix(Aoe __instance) { s_forgeChannelSpawn?.Spawned.Add((MonoBehaviour)(object)__instance); } } [HarmonyPatch(typeof(Projectile), "Awake")] private static class Projectile_Awake_ForgeStaff_Patch { private static void Postfix(Projectile __instance) { s_forgeChannelSpawn?.Spawned.Add((MonoBehaviour)(object)__instance); } } [HarmonyPatch(typeof(ObjectDB), "Awake")] private static class ObjectDB_Awake_MuckshakeFoodTweaks_Patch { private static void Postfix(ObjectDB __instance) { ApplyMuckshakeFoodTweaks(__instance); } } [HarmonyPatch(typeof(ObjectDB), "CopyOtherDB")] private static class ObjectDB_CopyOtherDB_MuckshakeFoodTweaks_Patch { private static void Postfix(ObjectDB __instance) { ApplyMuckshakeFoodTweaks(__instance); } } [HarmonyPatch(typeof(Player), "OnSpawned")] private static class Player_OnSpawned_MuckshakeFoodRepair_Patch { private static void Postfix(Player __instance) { if ((Object)(object)__instance != (Object)(object)Player.m_localPlayer) { return; } try { RepairMuckshakeInventory(((Humanoid)__instance).GetInventory()); } catch (Exception arg) { ManualLogSource log = Log; if (log != null) { log.LogError((object)$"[ValheimBB] Error while repairing Muckshake items on player spawn: {arg}"); } } } } [HarmonyPatch(typeof(Inventory), "AddItem", new Type[] { typeof(ItemData) })] private static class Inventory_AddItem_MuckshakeFoodRepair_Patch { private static void Prefix(ItemData item) { NormalizeMuckshakeItem(item); } } [HarmonyPatch(typeof(Inventory), "AddItem", new Type[] { typeof(ItemData), typeof(Vector2i) })] private static class Inventory_AddItemAtPos_MuckshakeFoodRepair_Patch { private static void Prefix(ItemData item) { NormalizeMuckshakeItem(item); } } [HarmonyPatch] private static class Inventory_AddItemToGrid_MuckshakeFoodRepair_Patch { private static MethodBase TargetMethod() { return AccessTools.Method(typeof(Inventory), "AddItem", new Type[5] { typeof(ItemData), typeof(int), typeof(int), typeof(int), typeof(bool) }, (Type[])null); } private static void Prefix(ItemData item) { NormalizeMuckshakeItem(item); } } private sealed class CraftRecipeSeenClickHandler : MonoBehaviour { public InventoryGui InventoryGui; public GameObject Element; public void HandleClick() { if (IsFeatureEnabled(EnableBuildAndRecipeUnlockMarkers)) { MarkCraftRecipeSeenByElement(InventoryGui, Element); } } } [HarmonyPatch(typeof(Hud), "UpdatePieceList")] private static class Hud_UpdatePieceList_NewBuildPieceMarkers_Patch { private static void Postfix(Hud __instance, Player player) { RefreshNewBuildPieceMarkers(__instance, player, onlyIfChanged: true); } } [HarmonyPatch(typeof(Hud), "OnHoverPiece", new Type[] { typeof(UIInputHandler) })] private static class Hud_OnHoverPiece_NewBuildPieceMarkers_Patch { private static void Postfix(Hud __instance, UIInputHandler ih) { if (!IsFeatureEnabled(EnableBuildAndRecipeUnlockMarkers)) { return; } Player localPlayer = Player.m_localPlayer; if (!((Object)(object)localPlayer == (Object)null) && !((Object)(object)ih == (Object)null)) { Piece buildPieceForIcon = GetBuildPieceForIcon(__instance, localPlayer, ((Component)ih).gameObject); if (!((Object)(object)buildPieceForIcon == (Object)null) && MarkBuildPieceSeen(localPlayer, buildPieceForIcon)) { RefreshNewBuildPieceMarkers(__instance, localPlayer); } } } } [HarmonyPatch(typeof(Hud), "OnHoverPiece", new Type[] { typeof(Piece) })] private static class Hud_OnHoverQuickPiece_NewBuildPieceMarkers_Patch { private static void Postfix(Hud __instance, Piece piece) { Player localPlayer = Player.m_localPlayer; if (IsFeatureEnabled(EnableBuildAndRecipeUnlockMarkers) && (Object)(object)localPlayer != (Object)null && (Object)(object)piece != (Object)null && MarkBuildPieceSeen(localPlayer, piece)) { RefreshNewBuildPieceMarkers(__instance, localPlayer); } } } [HarmonyPatch(typeof(InventoryGui), "UpdateRecipeList")] private static class InventoryGui_UpdateRecipeList_NewRecipeMarkers_Patch { private static void Postfix(InventoryGui __instance) { Player localPlayer = Player.m_localPlayer; if (!((Object)(object)localPlayer == (Object)null) && __instance.InCraftTab()) { if (IsFeatureEnabled(EnableBuildAndRecipeUnlockMarkers)) { WireCraftRecipeHoverHandlers(__instance); } RefreshCraftRecipeMarkers(__instance, localPlayer); } } } [HarmonyPatch(typeof(Minimap), "Update")] private static class Minimap_Update_NoMapBiomeLabel_Patch { private static void Postfix(Minimap __instance) { UpdateNoMapBiomeLabel(__instance); } } [HarmonyPatch(typeof(Minimap), "OnDestroy")] private static class Minimap_OnDestroy_NoMapBiomeLabel_Patch { private static void Prefix() { s_noMapBiomeLabel = null; } } [HarmonyPatch(typeof(Attack), "DoMeleeAttack")] private static class Attack_DoMeleeAttack_BedrockEffectContext { private static void Prefix(Attack __instance, ref bool __state) { __state = false; if (IsPickaxeAttack(__instance)) { if (s_activePickaxeAttackDepth == 0) { s_activePickaxeAttack = __instance; } s_activePickaxeAttackDepth++; __state = true; } } private static Exception Finalizer(bool __state, Exception __exception) { if (__state && s_activePickaxeAttackDepth > 0) { s_activePickaxeAttackDepth--; if (s_activePickaxeAttackDepth == 0) { s_activePickaxeAttack = null; } } return __exception; } } [HarmonyPatch(typeof(TerrainModifier), "OnPlaced")] private static class TerrainModifier_OnPlaced_BedrockEffectContext { private static void Prefix(TerrainModifier __instance, ref bool __state) { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) __state = false; if (!((Object)(object)__instance == (Object)null)) { Vector3 checkPosition = ((Component)__instance).transform.position + Vector3.up * s_terrainModifierLevelOffsetRef.Invoke(__instance); __state = TryBeginSuppressedPlacementEffect(s_terrainModifierOnPlacedEffectRef.Invoke(__instance), checkPosition); } } private static Exception Finalizer(bool __state, Exception __exception) { EndSuppressedPlacementEffect(__state); return __exception; } } [HarmonyPatch(typeof(TerrainOp), "OnPlaced")] private static class TerrainOp_OnPlaced_BedrockEffectContext { private static void Prefix(TerrainOp __instance, ref bool __state) { //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0025: 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) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) __state = false; if (!((Object)(object)__instance == (Object)null)) { Settings val = s_terrainOpSettingsRef.Invoke(__instance); Vector3 checkPosition = ((Component)__instance).transform.position + Vector3.up * val.m_levelOffset; __state = TryBeginSuppressedPlacementEffect(s_terrainOpOnPlacedEffectRef.Invoke(__instance), checkPosition); } } private static Exception Finalizer(bool __state, Exception __exception) { EndSuppressedPlacementEffect(__state); return __exception; } } [HarmonyPatch(typeof(EffectList), "Create", new Type[] { typeof(Vector3), typeof(Quaternion), typeof(Transform), typeof(float), typeof(int), typeof(ZDOID) })] private static class EffectList_Create_BedrockParticleSuppress { private static bool Prefix(EffectList __instance, Vector3 __0, ref GameObject[] __result) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) if (!IsSuppressedPlacementEffect(__instance) && !ShouldSuppressPickaxeTerrainEffect(__instance, __0)) { return true; } __result = Array.Empty<GameObject>(); return false; } } private struct ActivePickaxeSwingState { public bool Active; public Player Player; public float PaidStaminaCost; public bool HitDirt; public bool HitNonDirt; } [HarmonyPatch(typeof(Attack), "GetAttackStamina")] public static class Attack_GetAttackStamina_PickaxeCost_Patch { [HarmonyPostfix] private static void Postfix(Attack __instance, ref float __result) { try { if (IsFeatureEnabled(EnablePickaxeStaminaTweaks) && TryGetLocalPickaxeSwingPlayer(__instance, out var _) && TryGetOverridePickaxeStaminaCost(__instance, out var staminaCost)) { __result = staminaCost; } } catch (Exception arg) { ManualLogSource log = Log; if (log != null) { log.LogError((object)$"[ValheimBB] Error overriding pickaxe stamina: {arg}"); } } } } [HarmonyPatch(typeof(Attack), "DoMeleeAttack")] public static class Attack_DoMeleeAttack_PickaxeRefund_Patch { [HarmonyPrefix] private static void Prefix(Attack __instance, out bool __state) { __state = false; try { if (IsFeatureEnabled(EnablePickaxeDirtOnlyRefund) && TryGetLocalPickaxeSwingPlayer(__instance, out var player)) { float paidStaminaCost = Mathf.Max(0f, GetCurrentAttackStaminaCost(__instance)); BeginLocalPickaxeSwing(player, paidStaminaCost); __state = true; } } catch (Exception arg) { s_activePickaxeSwing = default(ActivePickaxeSwingState); ManualLogSource log = Log; if (log != null) { log.LogError((object)$"[ValheimBB] Error starting pickaxe refund tracking: {arg}"); } } } [HarmonyPostfix] private static void Postfix(bool __state) { if (!__state) { return; } try { FinishLocalPickaxeSwing(); } catch (Exception arg) { s_activePickaxeSwing = default(ActivePickaxeSwingState); ManualLogSource log = Log; if (log != null) { log.LogError((object)$"[ValheimBB] Error finishing pickaxe refund tracking: {arg}"); } } } [HarmonyFinalizer] private static Exception Finalizer(bool __state, Exception __exception) { if (__state) { s_activePickaxeSwing = default(ActivePickaxeSwingState); } return __exception; } } [HarmonyPatch(typeof(Attack), "SpawnOnHit")] public static class Attack_SpawnOnHit_PickaxeRefund_Patch { [HarmonyPrefix] private static void Prefix(GameObject target) { try { if (IsFeatureEnabled(EnablePickaxeDirtOnlyRefund) && (Object)(object)target != (Object)null) { RegisterLocalPickaxeNonDirtHit(); } } catch (Exception arg) { ManualLogSource log = Log; if (log != null) { log.LogError((object)$"[ValheimBB] Error registering pickaxe non-dirt hit: {arg}"); } } } } [HarmonyPatch(typeof(Attack), "SpawnOnHitTerrain")] public static class Attack_SpawnOnHitTerrain_PickaxeRefund_Patch { [HarmonyPrefix] private static void Prefix(Vector3 hitPoint) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) try { if (IsFeatureEnabled(EnablePickaxeDirtOnlyRefund)) { if (Heightmap.AtMaxLevelDepth(hitPoint)) { RegisterLocalPickaxeNonDirtHit(); } else { RegisterLocalPickaxeDirtHit(); } } } catch (Exception arg) { ManualLogSource log = Log; if (log != null) { log.LogError((object)$"[ValheimBB] Error registering pickaxe terrain hit: {arg}"); } } } } [HarmonyPatch(typeof(Humanoid), "SetUseHandVisual")] private static class Humanoid_SetUseHandVisual_PotionTiming_Patch { private static void Prefix(Humanoid __instance, GameObject obj, ref float seconds) { if ((Object)(object)__instance == (Object)(object)Player.m_localPlayer && (Object)(object)obj != (Object)null && IsPotionDrink(obj.GetComponent<ItemDrop>()?.m_itemData?.m_shared)) { seconds = 0.5f; } } } [HarmonyPatch(typeof(Humanoid), "UpdateUseVisual")] private static class Humanoid_UpdateUseVisual_PotionTiming_Patch { private static void Prefix(Humanoid __instance, out bool __state) { __state = (Object)(object)__instance == (Object)(object)Player.m_localPlayer && s_potionUseItemTimeRef.Invoke(__instance) > 0f && IsPotionDrink(s_potionUseItemVisualRef.Invoke(__instance)); } private static void Postfix(Humanoid __instance, bool __state) { //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Expected O, but got Unknown if (__state && !(s_potionUseItemTimeRef.Invoke(__instance) > 0f) && !((Character)__instance).IsDead()) { Animator componentInChildren = ((Component)__instance).GetComponentInChildren<Animator>(); if (!((Object)(object)componentInChildren == (Object)null) && (FinishPotionAnimationLayer(componentInChildren, 0, "Base Layer.eat", "Base Layer.Movement") | FinishPotionAnimationLayer(componentInChildren, 1, "upperbody.eat", "upperbody.None"))) { componentInChildren.Update(0f); s_potionAnimCacheFrameRef.Invoke((Character)(object)__instance) = -1; s_potionPlayerCacheFrameRef.Invoke((Player)__instance) = -1; } } } } [HarmonyPatch(typeof(ObjectDB), "Awake")] private static class ObjectDB_Awake_PulledBearFoodTweaks_Patch { private static void Postfix(ObjectDB __instance) { ApplyPulledBearFoodTweaks(__instance); } } [HarmonyPatch(typeof(ObjectDB), "CopyOtherDB")] private static class ObjectDB_CopyOtherDB_PulledBearFoodTweaks_Patch { private static void Postfix(ObjectDB __instance) { ApplyPulledBearFoodTweaks(__instance); } } private enum ResourceTrackerSortColumn { Item, Collected, Used, InBuilds, Net, Inventory } private sealed class ResourceTrackerRow { public string PrefabName; public string DisplayName; public long Collected; public long Used; public long InBuilds; public long Net; public int Inventory; } private sealed class ResourceDropContext { public DropTable DropTable; public long PlayerId; } private struct ResourceTrackerHeaderLabel { public TMP_Text Label; public string Text; public ResourceTrackerSortColumn Column; } private struct ResourceTrackerInventoryRemoveState { public bool Active; public ResourceRemovalGate.Lease Scope; public string PrefabName; public int BeforeStack; public int BeforeCount; } [HarmonyPatch(typeof(InventoryGui), "Show")] private static class InventoryGui_Show_ResourceTracker_Patch { private static void Postfix(InventoryGui __instance) { EnsureResourceTrackerButton(__instance); } } [HarmonyPatch(typeof(InventoryGui), "Hide")] private static class InventoryGui_Hide_ResourceTracker_Patch { private static void Postfix() { CloseResourceTrackerPanel(); } } [HarmonyPatch(typeof(DropTable), "GetDropList", new Type[] { })] private static class DropTable_GetDropList_ResourceTracker_Patch { private static void Postfix(DropTable __instance, List<GameObject> __result) { ResourceDropContext resourceDropContext = FindResourceDropContext(__instance); if (resourceDropContext != null) { RecordDropListForContext(resourceDropContext, __result); } } } [HarmonyPatch(typeof(TreeBase), "RPC_Damage")] private static class TreeBase_RPCDamage_ResourceTracker_Patch { private static void Prefix(TreeBase __instance, HitData hit, out ResourceDropContext __state) { PushResourceDropContext(__instance?.m_dropWhenDestroyed, hit, out __state); } private static void Finalizer(ResourceDropContext __state) { PopResourceDropContext(__state); } } [HarmonyPatch(typeof(TreeLog), "Destroy")] private static class TreeLog_Destroy_ResourceTracker_Patch { private static void Prefix(TreeLog __instance, HitData hitData, out ResourceDropContext __state) { PushResourceDropContext(__instance?.m_dropWhenDestroyed, hitData, out __state); } private static void Finalizer(ResourceDropContext __state) { PopResourceDropContext(__state); } } [HarmonyPatch(typeof(MineRock), "RPC_Hit")] private static class MineRock_RPCHit_ResourceTracker_Patch { private static void Prefix(MineRock __instance, HitData hit, out ResourceDropContext __state) { PushResourceDropContext(__instance?.m_dropItems, hit, out __state); } private static void Finalizer(ResourceDropContext __state) { PopResourceDropContext(__state); } } [HarmonyPatch(typeof(MineRock5), "DamageArea")] private static class MineRock5_DamageArea_ResourceTracker_Patch { private static void Prefix(MineRock5 __instance, HitData hit, out ResourceDropContext __state) { PushResourceDropContext(__instance?.m_dropItems, hit, out __state); } private static void Finalizer(ResourceDropContext __state) { PopResourceDropContext(__state); } } [HarmonyPatch(typeof(InventoryGui), "DoCrafting")] private static class InventoryGui_DoCrafting_ResourceTracker_Patch { private static void Prefix(Player player, out bool __state) { PushResourceTrackerUsageContext((Humanoid)(object)player, out __state); } private static void Finalizer(bool __state) { PopResourceTrackerUsageContext(__state); } } [HarmonyPatch(typeof(Fireplace), "Interact")] private static class Fireplace_Interact_ResourceTracker_Patch { private static void Prefix(Humanoid user, out bool __state) { PushResourceTrackerUsageContext(user, out __state); } private static void Finalizer(bool __state) { PopResourceTrackerUsageContext(__state); } } [HarmonyPatch(typeof(Fireplace), "UseItem")] private static class Fireplace_UseItem_ResourceTracker_Patch { private static void Prefix(Humanoid user, out bool __state) { PushResourceTrackerUsageContext(user, out __state); } private static void Finalizer(bool __state) { PopResourceTrackerUsageContext(__state); } } [HarmonyPatch(typeof(Smelter), "OnAddOre")] private static class Smelter_OnAddOre_ResourceTracker_Patch { private static void Prefix(Humanoid user, out bool __state) { PushResourceTrackerUsageContext(user, out __state); } private static void Finalizer(bool __state) { PopResourceTrackerUsageContext(__state); } } [HarmonyPatch(typeof(Smelter), "OnAddFuel")] private static class Smelter_OnAddFuel_ResourceTracker_Patch { private static void Prefix(Humanoid user, out bool __state) { PushResourceTrackerUsageContext(user, out __state); } private static void Finalizer(bool __state) { PopResourceTrackerUsageContext(__state); } } [HarmonyPatch(typeof(CookingStation), "OnUseItem")] private static class CookingStation_OnUseItem_ResourceTracker_Patch { private static void Prefix(Humanoid user, out bool __state) { PushResourceTrackerUsageContext(user, out __state); } private static void Finalizer(bool __state) { PopResourceTrackerUsageContext(__state); } } [HarmonyPatch(typeof(CookingStation), "OnAddFuelSwitch")] private static class CookingStation_OnAddFuelSwitch_ResourceTracker_Patch { private static void Prefix(Humanoid user, out bool __state) { PushResourceTrackerUsageContext(user, out __state); } private static void Finalizer(bool __state) { PopResourceTrackerUsageContext(__state); } } [HarmonyPatch(typeof(Player), "ConsumeItem", new Type[] { typeof(Inventory), typeof(ItemData), typeof(bool) })] private static class Player_ConsumeItem_ResourceTracker_Patch { private static void Postfix(Player __instance, ItemData item, bool __result) { if (__result && (Object)(object)__instance == (Object)(object)Player.m_localPlayer) { RecordUsedItem(item, 1); } } } [HarmonyPatch(typeof(Attack), "UseAmmo")] private static class Attack_UseAmmo_ResourceTracker_Patch { private static void Postfix(Attack __instance, ref ItemData ammoItem, bool __result) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Invalid comparison between Unknown and I4 if (__result && ammoItem != null) { SharedData shared = ammoItem.m_shared; if ((shared == null || (int)shared.m_itemType != 2) && (Object)(object)s_resourceTrackerAttackCharacterRef.Invoke(__instance) == (Object)(object)Player.m_localPlayer) { RecordUsedItem(ammoItem, 1); } } } } [HarmonyPatch(typeof(Inventory), "RemoveItem", new Type[] { typeof(string), typeof(int), typeof(int), typeof(bool) })] private static class Inventory_RemoveItemByName_ResourceTracker_Patch { private static void Prefix(Inventory __instance, string name, int itemQuality, out ResourceTrackerInventoryRemoveState __state) { __state = default(ResourceTrackerInventoryRemoveState); if (ShouldBeginInventoryRemoveTracking(__instance) && TryGetPrefabNameFromSharedName(name, out var prefabName)) { __state.Active = true; __state.PrefabName = prefabName; __state.BeforeCount = __instance.CountItems(name, itemQuality, false); BeginInventoryRemoveTracking(ref __state); } } private static void Postfix(Inventory __instance, string name, int itemQuality, ResourceTrackerInventoryRemoveState __state) { if (__state.Active) { int num = __instance.CountItems(name, itemQuality, false); EndInventoryRemoveTracking(__state, Mathf.Max(0, __state.BeforeCount - num)); } } private static void Finalizer(ResourceTrackerInventoryRemoveState __state) { __state.Scope?.Dispose(); } } [HarmonyPatch(typeof(Inventory), "RemoveItem", new Type[] { typeof(ItemData), typeof(int) })] private static class Inventory_RemoveItemAmount_ResourceTracker_Patch { private static void Prefix(Inventory __instance, ItemData item, out ResourceTrackerInventoryRemoveState __state) { __state = default(ResourceTrackerInventoryRemoveState); if (ShouldBeginInventoryRemoveTracking(__instance) && ShouldTrackUsedItem(item)) { __state.Active = true; __state.PrefabName = GetItemPrefabName(item); __state.BeforeStack = item?.m_stack ?? 0; BeginInventoryRemoveTracking(ref __state); } } private static void Postfix(Inventory __instance, ItemData item, bool __result, ResourceTrackerInventoryRemoveState __state) { if (__state.Active) { int num = ((item != null && __instance.ContainsItem(item)) ? item.m_stack : 0); EndInventoryRemoveTracking(__state, __result ? Mathf.Max(0, __state.BeforeStack - num) : 0); } } private static void Finalizer(ResourceTrackerInventoryRemoveState __state) { __state.Scope?.Dispose(); } } [HarmonyPatch(typeof(Inventory), "RemoveItem", new Type[] { typeof(ItemData) })] private static class Inventory_RemoveWholeItem_ResourceTracker_Patch { private static void Prefix(Inventory __instance, ItemData item, out ResourceTrackerInventoryRemoveState __state) { __state = default(ResourceTrackerInventoryRemoveState); if (ShouldBeginInventoryRemoveTracking(__instance) && ShouldTrackUsedItem(item)) { __state.Active = true; __state.PrefabName = GetItemPrefabName(item); __state.BeforeStack = item?.m_stack ?? 0; BeginInventoryRemoveTracking(ref __state); } } private static void Postfix(bool __result, ResourceTrackerInventoryRemoveState __state) { EndInventoryRemoveTracking(__state, __result ? Mathf.Max(0, __state.BeforeStack) : 0); } private static void Finalizer(ResourceTrackerInventoryRemoveState __state) { __state.Scope?.Dispose(); } } [HarmonyPatch(typeof(Inventory), "RemoveOneItem")] private static class Inventory_RemoveOneItem_ResourceTracker_Patch { private static void Prefix(Inventory __instance, ItemData item, out ResourceTrackerInventoryRemoveState __state) { __state = default(ResourceTrackerInventoryRemoveState); if (ShouldBeginInventoryRemoveTracking(__instance) && ShouldTrackUsedItem(item)) { __state.Active = true; __state.PrefabName = GetItemPrefabName(item); __state.BeforeStack = item?.m_stack ?? 0; BeginInventoryRemoveTracking(ref __state); } } private static void Postfix(bool __result, ResourceTrackerInventoryRemoveState __state) { EndInventoryRemoveTracking(__state, __result ? 1 : 0); } private static void Finalizer(ResourceTrackerInventoryRemoveState __state) { __state.Scope?.Dispose(); } } [HarmonyPatch(typeof(Player), "TryPlacePiece")] private static class Player_TryPlacePiece_ResourceTracker_Patch { private static void Prefix(Player __instance) { if (IsResourceTrackerEnabled() && !((Object)(object)__instance != (Object)(object)Player.m_localPlayer)) { s_resourceTrackerBuildContext = new ResourceTrackerBuildContext { Active = true, PlayerId = __instance.GetPlayerID() }; } } private static void Finalizer() { s_resourceTrackerBuildContext = default(ResourceTrackerBuildContext); } } [HarmonyPatch(typeof(Piece), "SetCreator")] private static class Piece_SetCreator_ResourceTracker_Patch { private static void Postfix(Piece __instance, long uid) { //IL_0041: Unknown result type (might be due to invalid IL or missing references) if (s_resourceTrackerBuildContext.Active && uid != 0L && uid == s_resourceTrackerBuildContext.PlayerId && !((Object)(object)__instance == (Object)null) && __instance.GetCreator() == uid && (!((Object)(object)ZoneSystem.instance != (Object)null) || (!ZoneSystem.instance.GetGlobalKey(__instance.FreeBuildKey()) && !ZoneSystem.instance.GetGlobalKey((GlobalKeys)24))) && (!((Object)(object)Player.m_localPlayer != (Object)null) || !Player.m_localPlayer.NoCostCheat())) { MarkPieceResourceTracking(__instance); SendBuildResourceTotals(__instance, uid, 1); } } } [HarmonyPatch(typeof(Piece), "DropResources")] private static class Piece_DropResources_ResourceTracker_Patch { private static void Prefix(Piece __instance) { if (TryGetTrackedPieceCreator(__instance, out var creatorId)) { SendBuildResourceTotals(__instance, creatorId, -1); ClearPieceResourceTracking(__instance); } } } [HarmonyPatch(typeof(WearNTear), "Destroy", new Type[] { typeof(HitData), typeof(bool) })] private static class WearNTear_Destroy_ResourceTracker_Patch { private static void Prefix(WearNTear __instance, bool blockDrop) { if (blockDrop) { Piece piece = (((Object)(object)__instance != (Object)null) ? ((Component)__instance).GetComponent<Piece>() : null); if (TryGetTrackedPieceCreator(piece, out var creatorId)) { SendBuildRecoverablesConsumed(piece, creatorId); ClearPieceResourceTracking(piece); } } } } [HarmonyPatch(typeof(Destructible), "Destroy")] private static class Destructible_Destroy_ResourceTracker_Patch { private static void Prefix(Destructible __instance) { Piece piece = (((Object)(object)__instance != (Object)null) ? ((Component)__instance).GetComponent<Piece>() : null); if (TryGetTrackedPieceCreator(piece, out var creatorId)) { SendBuildRecoverablesConsumed(piece, creatorId); ClearPieceResourceTracking(piece); } } } [HarmonyPatch(typeof(ObjectDB), "Awake")] public static class ObjectDB_Awake_RestingDelay_Patch { private static void Postfix(ObjectDB __instance) { ApplyRestingDelayToTemplates(__instance); } } [HarmonyPatch(typeof(ObjectDB), "CopyOtherDB")] public static class ObjectDB_CopyOtherDB_RestingDelay_Patch { private static void Postfix(ObjectDB __instance) { ApplyRestingDelayToTemplates(__instance); } } [HarmonyPatch(typeof(SE_Cozy), "Setup")] public static class SE_Cozy_Setup_RestingDelay_Patch { private static void Postfix(SE_Cozy __instance) { ApplyRestingDelay(__instance); } } [HarmonyPatch(typeof(SE_Cozy), "UpdateStatusEffect")] public static class SE_Cozy_UpdateStatusEffect_RestingDelay_Patch { private static void Prefix(SE_Cozy __instance) { ApplyRestingDelay(__instance); } } [HarmonyPatch(typeof(Hud), "UpdateStatusEffects")] public static class Hud_UpdateStatusEffects_RestingCountdown_Patch { private static void Postfix(Hud __instance, List<StatusEffect> statusEffects) { if (!((Object)(object)__instance == (Object)null) && statusEffects != null && HudStatusEffectsField?.GetValue(__instance) is List<RectTransform> list) { int num = Mathf.Min(statusEffects.Count, list.Count); for (int i = 0; i < num; i++) { RectTransform statusEffectRoot = list[i]; StatusEffect obj = statusEffects[i]; UpdateRestingCountdown(statusEffectRoot, (SE_Cozy)(object)((obj is SE_Cozy) ? obj : null)); } } } private static void UpdateRestingCountdown(RectTransform statusEffectRoot, SE_Cozy cozyEffect) { if ((Object)(object)statusEffectRoot == (Object)null) { return; } if (!IsRestingEffect(cozyEffect)) { HideRestingCountdown(statusEffectRoot); return; } if (!IsFeatureEnabled(EnableRestingTweaks)) { ApplyRestingDelay(cozyEffect); HideRestingCountdown(statusEffectRoot); return; } ApplyRestingDelay(cozyEffect); TextMeshProUGUI val = EnsureRestingCountdownLabel(statusEffectRoot); if (!((Object)(object)val == (Object)null)) { PositionRestingCountdownLabel(statusEffectRoot, ((TMP_Text)val).rectTransform); int num = Mathf.CeilToInt(15f - ((StatusEffect)cozyEffect).GetDuration()); if (num > 0) { ((TMP_Text)val).text = num.ToString(); ((Component)val).gameObject.SetActive(true); } else { ((Component)val).gameObject.SetActive(false); } } } private static void HideRestingCountdown(RectTransform statusEffectRoot) { Transform val = ((Transform)statusEffectRoot).Find("BB_RestingCountdown"); if ((Object)(object)val != (Object)null) { ((Component)val).gameObject.SetActive(false); } } private static TextMeshProUGUI EnsureRestingCountdownLabel(RectTransform statusEffectRoot) { //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00c8: Unknown result type (might be due to invalid IL or missing references) //IL_00dd: Unknown result type (might be due to invalid IL or missing references) //IL_00f2: Unknown result type (might be due to invalid IL or missing references) //IL_0122: Unknown result type (might be due to invalid IL or missing references) //IL_0182: Unknown result type (might be due to invalid IL or missing references) Transform val = ((Transform)statusEffectRoot).Find("BB_RestingCountdown"); if ((Object)(object)val != (Object)null) { return ((Component)val).GetComponent<TextMeshProUGUI>(); } Transform obj = ((Transform)statusEffectRoot).Find("Icon"); Transform obj2 = ((obj is RectTransform) ? obj : null); Transform obj3 = ((Transform)statusEffectRoot).Find("TimeText"); TMP_Text val2 = ((obj3 != null) ? ((Component)obj3).GetComponent<TMP_Text>() : null); if ((Object)(object)obj2 == (Object)null || (Object)(object)val2 == (Object)null) { return null; } GameObject val3 = new GameObject("BB_RestingCountdown", new Type[1] { typeof(RectTransform) }); val3.SetActive(false); val3.AddComponent<TextMeshProUGUI>(); val3.layer = ((Component)statusEffectRoot).gameObject.layer; RectTransform component = val3.GetComponent<RectTransform>(); ((Transform)component).SetParent((Transform)(object)statusEffectRoot, false); ((Transform)component).SetAsLastSibling(); component.pivot = new Vector2(1f, 0f); component.anchorMin = new Vector2(0.5f, 0.5f); component.anchorMax = new Vector2(0.5f, 0.5f); component.sizeDelta = new Vector2(26f, 16f); PositionRestingCountdownLabel(statusEffectRoot, component); TextMeshProUGUI component2 = val3.GetComponent<TextMeshProUGUI>(); ((TMP_Text)component2).font = val2.font; ((TMP_Text)component2).fontSharedMaterial = val2.fontSharedMaterial; ((TMP_Text)component2).fontStyle = val2.fontStyle; ((TMP_Text)component2).fontSize = val2.fontSize; ((TMP_Text)component2).characterSpacing = val2.characterSpacing; ((TMP_Text)component2).wordSpacing = val2.wordSpacing; ((TMP_Text)component2).lineSpacing = val2.lineSpacing; ((TMP_Text)component2).enableAutoSizing = val2.enableAutoSizing; ((TMP_Text)component2).fontSizeMin = val2.fontSizeMin; ((TMP_Text)component2).fontSizeMax = val2.fontSizeMax; ((Graphic)component2).color = ((Graphic)val2).color; ((TMP_Text)component2).alignment = (TextAlignmentOptions)1028; ((TMP_Text)component2).textWrappingMode = (TextWrappingModes)0; ((TMP_Text)component2).overflowMode = (TextOverflowModes)0; ((Graphic)component2).raycastTarget = false; ((Component)component2).gameObject.SetActive(false); return component2; } private static void PositionRestingCountdownLabel(RectTransform statusEffectRoot, RectTransform countdownRect) { //IL_0025: 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) //IL_0030: 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_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) Transform obj = ((Transform)statusEffectRoot).Find("Icon"); RectTransform val = (RectTransform)(object)((obj is RectTransform) ? obj : null); if (!((Object)(object)val == (Object)null) && !((Object)(object)countdownRect == (Object)null)) { Vector2 anchoredPosition = val.anchoredPosition; Rect rect = val.rect; float num = ((Rect)(ref rect)).width * (1f - val.pivot.x); rect = val.rect; Vector2 val2 = anchoredPosition + new Vector2(num, (0f - ((Rect)(ref rect)).height) * val.pivot.y); countdownRect.anchoredPosition = val2 + new Vector2(-2f, 4f); } } } [HarmonyPatch(typeof(GameCamera), "UpdateCamera")] private static class GameCamera_UpdateCamera_ShipPassengerZoom_Patch { private static void Prefix(GameCamera __instance, out float? __state) { __state = null; Player localPlayer = Player.m_localPlayer; if (!((Object)(object)localPlayer == (Object)null) && ((Character)localPlayer).IsAttached()) { Transform attachPoint = localPlayer.GetAttachPoint(); if (!((Object)(object)attachPoint == (Object)null) && !((Object)(object)((Component)attachPoint).GetComponentInParent<Ship>() == (Object)null)) { __state = __instance.m_maxDistance; __instance.m_maxDistance = __instance.m_maxDistanceBoat; } } } private static Exception Finalizer(GameCamera __instance, float? __state, Exception __exception) { if (__state.HasValue) { __instance.m_maxDistance = __state.Value; } return __exception; } } [HarmonyPatch(typeof(Ship), "GetWindAngleFactor")] private static class Ship_GetWindAngleFactor_SailingRange_Patch { private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions) { List<CodeInstruction> list = new List<CodeInstruction>(instructions); int num = -1; for (int i = 0; i < list.Count - 1; i++) { if (list[i].opcode != OpCodes.Ldc_R4 || !(list[i].operand is float num2) || num2 != 0.75f || list[i + 1].opcode != OpCodes.Ldc_R4 || !(list[i + 1].operand is float num3) || num3 != 0.8f) { continue; } if (num >= 0) { ManualLogSource log = Log; if (log != null) { log.LogWarning((object)"[ValheimBB] Ambiguous ship wind cutoff; leaving sailing range unchanged."); } return list; } num = i; } if (num < 0) { ManualLogSource log2 = Log; if (log2 != null) { log2.LogWarning((object)"[ValheimBB] Ship wind cutoff not found; leaving sailing range unchanged."); } return list; } float num4 = Mathf.Cos((float)Math.PI / 6f); list[num].operand = num4 - 0.05f; list[num + 1].operand = num4; return list; } } [HarmonyPatch(typeof(Player), "UpdatePlacementGhost")] private static class Player_UpdatePlacementGhost_SignChestPlacement_Patch { private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions) { MethodInfo method = new Func<WearNTear, Player, bool>(CanSupportSignPlacement).Method; return RewriteSignSupportChecks(instructions, method, 1); } } [HarmonyPatch(typeof(WearNTear), "UpdateSupport")] private static class WearNTear_UpdateSupport_SignChestPlacement_Patch { private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions) { MethodInfo method = new Func<WearNTear, WearNTear, bool>(CanSupportAttachedSign).Method; return RewriteSignSupportChecks(instructions, method, 2); } } [HarmonyPatch(typeof(Sign), "Awake")] private static class Sign_Awake_DefaultTextColor_Patch { private static void Postfix(Sign __instance) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)__instance.m_textWidget != (Object)null) { ((Graphic)__instance.m_textWidget).color = Color.white; } } } private struct PendingThrownSpearContext { public bool Active; public string ThrowerIdentity; public string ExpectedItemName; } [HarmonyPatch(typeof(Projectile), "OnHit")] private static class Projectile_OnHit_ThrownSpearPickupRules_Patch { private static void Prefix(Projectile __instance, out PendingThrownSpearContext __state) { __state = s_pendingThrownSpearContext; if (TryCreatePendingThrownSpearContext(__instance, out var context)) { s_pendingThrownSpearContext = context; } } private static void Finalizer(PendingThrownSpearContext __state) { s_pendingThrownSpearContext = __state; } } [HarmonyPatch(typeof(ItemDrop), "DropItem", new Type[] { typeof(ItemData), typeof(int), typeof(Vector3), typeof(Quaternion) })] private static class ItemDrop_DropItem_ThrownSpearPickupRules_Patch { private static void Prefix(ItemData item) { TryTagPendingThrownSpearItem(item); } } [HarmonyPatch(typeof(Player), "AutoPickup")] private static class Player_AutoPickup_ThrownSpearPickupRules_Patch { private static void Prefix(out int __state) { __state = s_autoPickupContextDepth; s_autoPickupContextDepth = __state + 1; } private static void Finalizer(int __state) { s_autoPickupContextDepth = __state; } } [HarmonyPatch(typeof(ItemDrop), "CanPickup", new Type[] { typeof(bool) })] private static class ItemDrop_CanPickup_ThrownSpearPickupRules_Patch { private static void Postfix(ItemDrop __instance, ref bool __result) { if (IsFeatureEnabled(EnableThrownSpearPickupProtection) && __result && IsInAutoPickupContext() && __instance?.m_itemData != null && TryGetThrownSpearThrowerIdentity(__instance.m_itemData, out var throwerIdentity) && TryGetPlayerIdentity(Player.m_localPlayer, out var playerIdentity) && !string.Equals(playerIdentity, throwerIdentity, StringComparison.Ordinal)) { __result = false; } } } [HarmonyPatch(typeof(ItemDrop), "RequestOwn")] private static class ItemDrop_RequestOwn_ThrownSpearPickupRules_Patch { private static bool Prefix(ItemDrop __instance) { if (!IsFeatureEnabled(EnableThrownSpearPickupProtection)) { return true; } if (!IsInAutoPickupContext() || __instance?.m_itemData == null) { return true; } if (!TryGetThrownSpearThrowerIdentity(__instance.m_itemData, out var throwerIdentity)) { return true; } if (!TryGetPlayerIdentity(Player.m_localPlayer, out var playerIdentity)) { return true; } return string.Equals(playerIdentity, throwerIdentity, StringComparison.Ordinal); } } [HarmonyPatch(typeof(Humanoid), "Pickup", new Type[] { typeof(GameObject), typeof(bool), typeof(bool) })] private static class Humanoid_Pickup_ThrownSpearPickupRules_Patch { private static void Postfix(GameObject go, bool __result) { if (__result && !((Object)(object)go == (Object)null)) { ItemDrop component = go.GetComponent<ItemDrop>(); if (component?.m_itemData != null) { ClearThrownSpearThrowerIdentity(component.m_itemData); } } } } [HarmonyPatch(typeof(Player), "UpdatePlacementGhost")] private static class Player_UpdatePlacementGhost_StationUpgradePlacement_Patch { private static void Prefix(GameObject ___m_placementGhost) { if (!((Object)(object)___m_placementGhost == (Object)null) && !((Object)(object)___m_placementGhost.GetComponent<StationExtension>() == (Object)null)) { Piece component = ___m_placementGhost.GetComponent<Piece>(); if (!((Object)(object)component == (Object)null)) { component.m_noInWater = false; component.m_waterPiece = false; component.m_spaceRequirement = 0f; } } } } [HarmonyPatch(typeof(ProximityState), "OnTriggerEnter")] private static class ProximityState_OnTriggerEnter_StoneOvenDoorDelay_Patch { private static void Postfix(ProximityState __instance, Collider other) { if (ShouldDelayStoneOvenDoor(__instance) && IsAcceptedProximityCollider(__instance, other)) { CancelStoneOvenDoorClose(__instance); } } } [HarmonyPat