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 BrennivinProtection v0.1.3
plugins/BrennivinProtection/BrennivinProtection.dll
Decompiled a day agousing System; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Jotunn.Configs; using Jotunn.Entities; using Jotunn.Managers; using Jotunn.Utils; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyTitle("BrennivinProtection")] [assembly: AssemblyFileVersion("0.1.3")] [assembly: AssemblyCompany("R4V9N1")] [assembly: AssemblyDescription("Created by R4V9N1")] [assembly: AssemblyProduct("BrennivinProtection")] [assembly: AssemblyCopyright("Created by R4V9N1")] [assembly: AssemblyMetadata("Creator", "Created by R4V9N1")] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: AssemblyVersion("0.1.3.0")] namespace BrennivinProtection; internal static class BrennivinEquipmentSheetCompat { private static bool _lookupComplete; private static MethodInfo _moveSheetItemsForDeath; internal static bool TryMoveSheetItemsToPlayerInventory(Player player) { if ((Object)(object)player == (Object)null) { return false; } EnsureLookup(); if (_moveSheetItemsForDeath == null) { return false; } try { _moveSheetItemsForDeath.Invoke(null, new object[1] { player }); BrennivinPlugin.LogInfo("Asked Equipment Sheet to move sheet items into the death inventory before Brennivin protection check."); return true; } catch (Exception ex) { BrennivinPlugin.LogWarning("Equipment Sheet compatibility call failed: " + ex.Message); return false; } } private static void EnsureLookup() { if (_lookupComplete) { return; } _lookupComplete = true; Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); for (int i = 0; i < assemblies.Length; i++) { Type type = assemblies[i].GetType("EquipmentSheet.EquipmentSheetPlugin", throwOnError: false); if (!(type == null)) { _moveSheetItemsForDeath = type.GetMethod("MoveSheetItemsToPlayerInventoryForDeath", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); break; } } } } internal static class BrennivinBedTeleport { internal unsafe static bool TryTeleportToClaimedBed(Player player) { //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) //IL_0042: 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_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)player == (Object)null || (Object)(object)Game.instance == (Object)null) { return false; } PlayerProfile playerProfile = Game.instance.GetPlayerProfile(); if (playerProfile == null || !playerProfile.HaveCustomSpawnPoint()) { BrennivinPlugin.Message(player, "Brennivin needs a claimed bed."); return false; } Vector3 customSpawnPoint = playerProfile.GetCustomSpawnPoint(); if (customSpawnPoint == Vector3.zero) { BrennivinPlugin.Message(player, "Brennivin could not find your claimed bed."); return false; } if (((Character)player).IsTeleporting()) { BrennivinPlugin.Message(player, "Brennivin cannot be used while teleporting."); return false; } if (!((Character)player).TeleportTo(customSpawnPoint, ((Component)player).transform.rotation, true)) { BrennivinPlugin.Message(player, "Brennivin could not start the teleport."); return false; } BrennivinWakeupAnimation.Queue(player); BrennivinPlugin.Message(player, "Brennivin carries you home."); Vector3 val = customSpawnPoint; BrennivinPlugin.LogInfo("Started Brennivin bed teleport to " + ((object)(*(Vector3*)(&val))/*cast due to .constrained prefix*/).ToString() + "."); return true; } } internal sealed class BrennivinWakeupAnimation : MonoBehaviour { private static readonly FieldInfo AnimatorField = AccessTools.Field(typeof(Character), "m_animator"); private static readonly FieldInfo WakeupTimerField = AccessTools.Field(typeof(Player), "m_wakeupTimer"); private Player _player; private float _timeout; private float _settleDelay = 0.25f; internal static void Queue(Player player) { if (!((Object)(object)player == (Object)null)) { BrennivinWakeupAnimation brennivinWakeupAnimation = ((Component)player).GetComponent<BrennivinWakeupAnimation>(); if ((Object)(object)brennivinWakeupAnimation == (Object)null) { brennivinWakeupAnimation = ((Component)player).gameObject.AddComponent<BrennivinWakeupAnimation>(); } brennivinWakeupAnimation._player = player; brennivinWakeupAnimation._timeout = 18f; brennivinWakeupAnimation._settleDelay = 0.25f; } } private void Update() { if ((Object)(object)_player == (Object)null) { Object.Destroy((Object)(object)this); return; } _timeout -= Time.deltaTime; if (_timeout <= 0f) { Object.Destroy((Object)(object)this); } else if (!((Character)_player).IsTeleporting()) { _settleDelay -= Time.deltaTime; if (!(_settleDelay > 0f)) { PulseWakeup(_player); Object.Destroy((Object)(object)this); } } } private static void PulseWakeup(Player player) { try { ZNetView component = ((Component)player).GetComponent<ZNetView>(); if ((Object)(object)component != (Object)null && component.IsValid() && component.IsOwner() && component.GetZDO() != null) { component.GetZDO().Set(ZDOVars.s_wakeup, true); } Animator val = (Animator)((AnimatorField == null) ? null : /*isinst with value type is only supported in some contexts*/); if ((Object)(object)val != (Object)null) { val.SetBool("wakeup", true); } if (WakeupTimerField != null) { WakeupTimerField.SetValue(player, 0f); } BrennivinPlugin.LogInfo("Pulsed Valheim wakeup animation after Brennivin teleport."); } catch (Exception ex) { BrennivinPlugin.LogWarning("Brennivin wakeup animation pulse failed: " + ex.Message); } } } [HarmonyPatch(typeof(Player), "CreateTombStone")] [HarmonyPriority(800)] [HarmonyBefore(new string[] { "r4v9n1.equipmentsheet" })] internal static class PlayerCreateTombStoneBrennivinPatch { private static bool Prefix(Player __instance) { if (!BrennivinPlugin.IsDeathProtectionEnabled() || (Object)(object)__instance == (Object)null) { return true; } Inventory inventory = ((Humanoid)__instance).GetInventory(); if (BrennivinPlugin.TryConsumeOne(inventory)) { BrennivinPlugin.Message(__instance, "Brennivin was spent. Your inventory stayed with you."); BrennivinPlugin.LogInfo("Brennivin death protection consumed one carried flask and skipped tombstone creation."); return false; } if (BrennivinEquipmentSheetCompat.TryMoveSheetItemsToPlayerInventory(__instance) && BrennivinPlugin.TryConsumeOne(inventory)) { BrennivinPlugin.Message(__instance, "Brennivin was spent. Your inventory stayed with you."); BrennivinPlugin.LogInfo("Brennivin death protection consumed one flask after Equipment Sheet items were moved into the player inventory."); return false; } return true; } } [HarmonyPatch(typeof(Player), "ConsumeItem", new Type[] { typeof(Inventory), typeof(ItemData), typeof(bool) })] internal static class PlayerConsumeItemBrennivinPatch { private static bool Prefix(Player __instance, Inventory inventory, ItemData item, bool checkWorldLevel, ref bool __result) { if (!BrennivinPlugin.IsBrennivin(item)) { return true; } __result = false; if ((Object)(object)__instance == (Object)null || inventory == null || !inventory.ContainsItem(item)) { return false; } if (!BrennivinPlugin.IsBedTeleportEnabled()) { BrennivinPlugin.Message(__instance, "Brennivin bed teleport is disabled."); return false; } if (!((Humanoid)__instance).CanConsumeItem(item, checkWorldLevel)) { return false; } if (!BrennivinBedTeleport.TryTeleportToClaimedBed(__instance)) { return false; } __result = inventory.RemoveOneItem(item); return false; } } [BepInPlugin("r4v9n1.brennivin", "BrennivinProtection", "0.1.3")] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [NetworkCompatibility(/*Could not decode attribute arguments.*/)] public sealed class BrennivinPlugin : BaseUnityPlugin { public const string PluginGuid = "r4v9n1.brennivin"; public const string PluginName = "BrennivinProtection"; public const string PluginVersion = "0.1.3"; public const string CreatorCredit = "Created by R4V9N1"; internal const string PrefabName = "R4V9N1_Brennivin"; internal const string BasePrefabName = "R4V9N1_BrennivinBase"; internal const string DisplayName = "Brennivín"; internal const string BaseDisplayName = "Mead base: Brennivín"; internal const string ItemDescription = "One sip of this can make you forget everything....\nWhile in inventory you will not loose your items on death, if you drink it....."; private static readonly string[] MeadBaseCandidates = new string[8] { "MeadHealthMinor", "MeadTasty", "MeadStaminaMinor", "MeadHealthMedium", "MeadEitrMinor", "MeadPoisonResist", "MeadFrostResist", "MeadHealthLingering" }; private static readonly string[] MeadBaseBaseCandidates = new string[8] { "MeadBaseHealthMinor", "MeadBaseTasty", "MeadBaseStaminaMinor", "MeadBaseHealthMedium", "MeadBaseEitrMinor", "MeadBasePoisonResist", "MeadBaseFrostResist", "BarleyWineBase" }; private static ConfigEntry<bool> _enabled; private static ConfigEntry<bool> _deathProtection; private static ConfigEntry<bool> _bedTeleport; private static ConfigEntry<bool> _logDiagnostics; private static ManualLogSource _log; private Harmony _harmony; private bool _itemRegistered; private void Awake() { //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Expected O, but got Unknown //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Expected O, but got Unknown //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_0072: Expected O, but got Unknown //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Expected O, but got Unknown //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Expected O, but got Unknown //IL_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: Expected O, but got Unknown //IL_00e2: Unknown result type (might be due to invalid IL or missing references) //IL_00ec: Expected O, but got Unknown _log = ((BaseUnityPlugin)this).Logger; _enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, new ConfigDescription("Enable Brennivin item behavior. Server-controlled.", (AcceptableValueBase)null, new object[1] { (object)new ConfigurationManagerAttributes { IsAdminOnly = true } })); _deathProtection = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "DeathProtection", true, new ConfigDescription("If true, carrying Brennivin lets the player die normally but keep inventory and equipment, consuming one flask. Server-controlled.", (AcceptableValueBase)null, new object[1] { (object)new ConfigurationManagerAttributes { IsAdminOnly = true } })); _bedTeleport = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "BedTeleportOnDrink", true, new ConfigDescription("If true, drinking Brennivin teleports the player to their claimed bed. Server-controlled.", (AcceptableValueBase)null, new object[1] { (object)new ConfigurationManagerAttributes { IsAdminOnly = true } })); _logDiagnostics = ((BaseUnityPlugin)this).Config.Bind<bool>("Diagnostics", "LogDiagnostics", false, "Log Brennivin death protection, item registration, and teleport decisions."); _harmony = new Harmony("r4v9n1.brennivin"); _harmony.PatchAll(); PrefabManager.OnVanillaPrefabsAvailable += RegisterBrennivin; ((BaseUnityPlugin)this).Logger.LogInfo((object)"BrennivinProtection 0.1.3 loaded."); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Created by R4V9N1."); } private void OnDestroy() { PrefabManager.OnVanillaPrefabsAvailable -= RegisterBrennivin; if (_harmony != null) { _harmony.UnpatchSelf(); _harmony = null; } } private void RegisterBrennivin() { //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Expected O, but got Unknown //IL_0092: 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) //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: 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_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_00da: Expected O, but got Unknown //IL_012c: Unknown result type (might be due to invalid IL or missing references) //IL_0133: Expected O, but got Unknown //IL_013f: Unknown result type (might be due to invalid IL or missing references) //IL_0146: Expected O, but got Unknown //IL_01d9: Unknown result type (might be due to invalid IL or missing references) //IL_01de: Unknown result type (might be due to invalid IL or missing references) //IL_01e9: Unknown result type (might be due to invalid IL or missing references) //IL_01f4: Unknown result type (might be due to invalid IL or missing references) //IL_01ff: Unknown result type (might be due to invalid IL or missing references) //IL_020b: Expected O, but got Unknown //IL_0206: Unknown result type (might be due to invalid IL or missing references) //IL_0210: Expected O, but got Unknown if (_itemRegistered || (ItemManager.Instance.GetItem("R4V9N1_Brennivin") != null && ItemManager.Instance.GetItem("R4V9N1_BrennivinBase") != null)) { _itemRegistered = true; return; } GameObject val = ResolveBaseMeadPrefab(); GameObject val2 = ResolveBaseMeadBasePrefab(); if ((Object)(object)val == (Object)null || (Object)(object)val2 == (Object)null) { ((BaseUnityPlugin)this).Logger.LogError((object)"Could not find vanilla mead flask/base prefabs to clone. Brennivin was not registered."); return; } ItemConfig val3 = new ItemConfig { Name = "Brennivín", Description = "One sip of this can make you forget everything....\nWhile in inventory you will not loose your items on death, if you drink it.....", StackSize = 10, Weight = 1f }; ItemConfig val4 = new ItemConfig { Name = "Mead base: Brennivín", Description = "Ferment this into Brennivín.", Amount = 1, CraftingStation = "MeadKetill", MinStationLevel = 1, StackSize = 10, Weight = 1f }; val4.AddRequirement("Cloudberry", 50, 0); val4.AddRequirement("Honey", 50, 0); val4.AddRequirement("Thistle", 50, 0); val4.AddRequirement("Dandelion", 50, 0); val4.AddRequirement("BoneFragments", 50, 0); CustomItem val5 = new CustomItem("R4V9N1_Brennivin", ((Object)val).name, val3); CustomItem val6 = new CustomItem("R4V9N1_BrennivinBase", ((Object)val2).name, val4); if (!IsValidCustomItem(val5) || !IsValidCustomItem(val6)) { ((BaseUnityPlugin)this).Logger.LogError((object)("Jotunn could not clone Brennivin flask/base from '" + ((Object)val).name + "' and '" + ((Object)val2).name + "'.")); return; } ConfigureFlask(val5); ConfigureMeadBase(val6); if (!ItemManager.Instance.AddItem(val5) || !ItemManager.Instance.AddItem(val6)) { ((BaseUnityPlugin)this).Logger.LogError((object)"Jotunn rejected Brennivin item registration."); return; } ItemManager.Instance.AddItemConversion(new CustomItemConversion((ConversionConfig)new FermenterConversionConfig { Station = "Fermenter", FromItem = "R4V9N1_BrennivinBase", ToItem = "R4V9N1_Brennivin", ProducedItems = 1 })); _itemRegistered = true; PrefabManager.OnVanillaPrefabsAvailable -= RegisterBrennivin; ((BaseUnityPlugin)this).Logger.LogInfo((object)"Registered Mead base: Brennivin as a Mead Ketill craft and Brennivin as a one-flask fermenter output."); } private GameObject ResolveBaseMeadPrefab() { for (int i = 0; i < MeadBaseCandidates.Length; i++) { GameObject prefab = PrefabManager.Instance.GetPrefab(MeadBaseCandidates[i]); if (IsUsableConsumablePrefab(prefab)) { return prefab; } } return null; } private GameObject ResolveBaseMeadBasePrefab() { for (int i = 0; i < MeadBaseBaseCandidates.Length; i++) { GameObject prefab = PrefabManager.Instance.GetPrefab(MeadBaseBaseCandidates[i]); if (IsUsableItemPrefab(prefab)) { return prefab; } } return null; } private static bool IsUsableConsumablePrefab(GameObject prefab) { //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Invalid comparison between Unknown and I4 ItemDrop usableItemDrop = GetUsableItemDrop(prefab); if ((Object)(object)usableItemDrop != (Object)null) { return (int)usableItemDrop.m_itemData.m_shared.m_itemType == 2; } return false; } private static bool IsUsableItemPrefab(GameObject prefab) { return (Object)(object)GetUsableItemDrop(prefab) != (Object)null; } private static ItemDrop GetUsableItemDrop(GameObject prefab) { if ((Object)(object)prefab == (Object)null) { return null; } ItemDrop component = prefab.GetComponent<ItemDrop>(); if ((Object)(object)component == (Object)null || component.m_itemData == null || component.m_itemData.m_shared == null) { return null; } return component; } private static bool IsValidCustomItem(CustomItem item) { if (item != null && (Object)(object)item.ItemPrefab != (Object)null && (Object)(object)item.ItemDrop != (Object)null && item.ItemDrop.m_itemData != null) { return item.ItemDrop.m_itemData.m_shared != null; } return false; } private static void ConfigureFlask(CustomItem item) { //IL_0035: Unknown result type (might be due to invalid IL or missing references) ItemData itemData = item.ItemDrop.m_itemData; SharedData shared = itemData.m_shared; itemData.m_dropPrefab = item.ItemPrefab; shared.m_name = "Brennivín"; shared.m_description = "One sip of this can make you forget everything....\nWhile in inventory you will not loose your items on death, if you drink it....."; shared.m_itemType = (ItemType)2; shared.m_maxStackSize = 10; shared.m_weight = 1f; shared.m_teleportable = true; shared.m_isDrink = true; shared.m_food = 0f; shared.m_foodStamina = 0f; shared.m_foodEitr = 0f; shared.m_foodBurnTime = 0f; shared.m_foodRegen = 0f; shared.m_consumeStatusEffect = null; shared.m_equipDuration = 1f; TintPrefabCyan(item.ItemPrefab); } private static void ConfigureMeadBase(CustomItem item) { //IL_0035: Unknown result type (might be due to invalid IL or missing references) ItemData itemData = item.ItemDrop.m_itemData; SharedData shared = itemData.m_shared; itemData.m_dropPrefab = item.ItemPrefab; shared.m_name = "Mead base: Brennivín"; shared.m_description = "Ferment this into Brennivín."; shared.m_itemType = (ItemType)1; shared.m_maxStackSize = 10; shared.m_weight = 1f; shared.m_teleportable = true; shared.m_isDrink = false; shared.m_food = 0f; shared.m_foodStamina = 0f; shared.m_foodEitr = 0f; shared.m_foodBurnTime = 0f; shared.m_foodRegen = 0f; shared.m_consumeStatusEffect = null; TintPrefabCyan(item.ItemPrefab); } private static void TintPrefabCyan(GameObject prefab) { //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Expected O, but got Unknown //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_00ef: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)prefab == (Object)null) { return; } Renderer[] componentsInChildren = prefab.GetComponentsInChildren<Renderer>(true); foreach (Renderer val in componentsInChildren) { Material[] sharedMaterials = val.sharedMaterials; for (int j = 0; j < sharedMaterials.Length; j++) { Material val2 = sharedMaterials[j]; if (!((Object)(object)val2 == (Object)null)) { Material val3 = new Material(val2); ((Object)val3).name = "Brennivin_Cyan_" + ((Object)val2).name; if (val3.HasProperty("_Color")) { val3.SetColor("_Color", new Color(0f, 0.9f, 1f, 1f)); } if (val3.HasProperty("_BaseColor")) { val3.SetColor("_BaseColor", new Color(0f, 0.9f, 1f, 1f)); } if (val3.HasProperty("_EmissionColor")) { val3.SetColor("_EmissionColor", new Color(0f, 0.35f, 0.45f, 1f)); } sharedMaterials[j] = val3; } } val.sharedMaterials = sharedMaterials; } } internal static bool IsEnabled() { if (_enabled != null) { return _enabled.Value; } return false; } internal static bool IsDeathProtectionEnabled() { if (IsEnabled() && _deathProtection != null) { return _deathProtection.Value; } return false; } internal static bool IsBedTeleportEnabled() { if (IsEnabled() && _bedTeleport != null) { return _bedTeleport.Value; } return false; } internal static bool IsBrennivin(ItemData item) { if (item == null) { return false; } if ((Object)(object)item.m_dropPrefab != (Object)null && string.Equals(GetPrefabName(((Object)item.m_dropPrefab).name), "R4V9N1_Brennivin", StringComparison.Ordinal)) { return true; } if (item.m_shared != null) { return string.Equals(item.m_shared.m_name, "Brennivín", StringComparison.Ordinal); } return false; } private static string GetPrefabName(string name) { if (string.IsNullOrEmpty(name)) { return string.Empty; } int num = name.IndexOfAny(new char[2] { '(', ' ' }); if (num < 0) { return name; } return name.Substring(0, num); } internal static bool TryConsumeOne(Inventory inventory) { if (inventory == null) { return false; } List<ItemData> allItems = inventory.GetAllItems(); if (allItems == null) { return false; } for (int i = 0; i < allItems.Count; i++) { ItemData val = allItems[i]; if (IsBrennivin(val)) { return inventory.RemoveOneItem(val); } } return false; } internal static void Message(Player player, string text) { if ((Object)(object)player != (Object)null) { ((Character)player).Message((MessageType)2, text, 0, (Sprite)null); } } internal static void LogInfo(string text) { if (_logDiagnostics != null && _logDiagnostics.Value && _log != null) { _log.LogInfo((object)text); } } internal static void LogWarning(string text) { if (_log != null) { _log.LogWarning((object)text); } } }