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 Taum v1.0.0
plugins/Taum/Taum.dll
Decompiled 21 hours agousing System; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using Ezomic.Core; using Ezomic.Shared; using HarmonyLib; using Microsoft.CodeAnalysis; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.6.2", FrameworkDisplayName = ".NET Framework 4.6.2")] [assembly: AssemblyCompany("Thijssen Software")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyCopyright("Copyright (c) 2026 Robbin Thijssen")] [assembly: AssemblyDescription("Lead a tamed boar or hen on a crafted halter.")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+65d55ce3fad9f553ca8123356c93a24835772f42")] [assembly: AssemblyProduct("Taum")] [assembly: AssemblyTitle("Taum")] [assembly: AssemblyVersion("1.0.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace Ezomic.Shared { public static class Prefabs { private sealed class Kept { internal string Name; internal Func<GameObject> Build; internal bool Item; internal string Tool; internal GameObject Prefab; internal int Failures; internal bool Abandoned; } private static ManualLogSource _log; private static GameObject _holder; private static readonly List<Kept> Standing = new List<Kept>(); private const int MaxFailures = 5; private static readonly HashSet<string> Complained = new HashSet<string>(); private static FieldRef<ZNetScene, Dictionary<int, GameObject>> _named; private static MethodInfo _updateRegisters; public static ManualLogSource Log { get { return _log ?? (_log = Logger.CreateLogSource("Prefabs")); } set { _log = value; } } public static Transform Holder { get { //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Expected O, but got Unknown if ((Object)(object)_holder == (Object)null) { _holder = new GameObject(Log.SourceName + "Prefabs"); _holder.SetActive(false); Object.DontDestroyOnLoad((Object)(object)_holder); } return _holder.transform; } } public static void Keep(string name, Func<GameObject> build, bool item = false, string buildTool = null) { if (string.IsNullOrEmpty(name)) { throw new ArgumentNullException("name"); } if (build == null) { throw new ArgumentNullException("build"); } foreach (Kept item2 in Standing) { if (!(item2.Name != name)) { item2.Build = build; item2.Item = item; item2.Tool = buildTool; item2.Failures = 0; item2.Abandoned = false; return; } } Standing.Add(new Kept { Name = name, Build = build, Item = item, Tool = buildTool }); Log.LogInfo((object)("Keeping " + name + " registered.")); } public static void Drop(string name) { Standing.RemoveAll((Kept k) => k.Name == name); } public static void Tick() { if (Standing.Count == 0) { return; } ZNetScene instance = ZNetScene.instance; if (!((Object)(object)instance == (Object)null)) { for (int i = 0; i < Standing.Count; i++) { Apply(Standing[i], instance); } } } private static void Apply(Kept kept, ZNetScene scene) { if (!kept.Abandoned && (!((Object)(object)kept.Prefab == (Object)null) || TryBuild(kept))) { if ((Object)(object)scene.GetPrefab(kept.Name) == (Object)null) { Register(kept.Prefab); } if (kept.Item) { RegisterItem(kept.Prefab); } if (!string.IsNullOrEmpty(kept.Tool)) { AddToTool(kept.Prefab, kept.Tool); } } } private static bool TryBuild(Kept kept) { GameObject val = null; try { val = kept.Build(); } catch (Exception ex) { Log.LogWarning((object)("Building " + kept.Name + " failed: " + ex.Message)); } if ((Object)(object)val != (Object)null) { kept.Prefab = val; kept.Failures = 0; if (((Object)val).name != kept.Name) { ((Object)val).name = kept.Name; } return true; } if (++kept.Failures < 5) { return false; } kept.Abandoned = true; Log.LogError((object)(kept.Name + " could not be built after " + 5 + " attempts and will not be retried. Anything already built with it in a world is untouched; it simply will not be placeable this session.")); return false; } public static bool Known(string name) { if ((Object)(object)ZNetScene.instance != (Object)null) { return (Object)(object)ZNetScene.instance.GetPrefab(name) != (Object)null; } return false; } public static GameObject Clone(GameObject source, string name) { if ((Object)(object)source == (Object)null) { return null; } bool forceDisableInit = ZNetView.m_forceDisableInit; ZNetView.m_forceDisableInit = true; GameObject val; try { val = Object.Instantiate<GameObject>(source, Holder); } finally { ZNetView.m_forceDisableInit = forceDisableInit; } ((Object)val).name = name; return val; } public static GameObject Donor(string commaSeparated, out string chosen) { chosen = null; if ((Object)(object)ZNetScene.instance == (Object)null) { return null; } string[] array = (commaSeparated ?? "").Split(new char[1] { ',' }); for (int i = 0; i < array.Length; i++) { string text = array[i].Trim(); if (text.Length != 0) { GameObject prefab = ZNetScene.instance.GetPrefab(text); if (!((Object)(object)prefab == (Object)null)) { chosen = text; return prefab; } } } return null; } public static bool Register(GameObject prefab) { ZNetScene instance = ZNetScene.instance; if ((Object)(object)instance == (Object)null || (Object)(object)prefab == (Object)null) { return false; } if ((Object)(object)instance.GetPrefab(((Object)prefab).name) != (Object)null) { return true; } if (!instance.m_prefabs.Contains(prefab)) { instance.m_prefabs.Add(prefab); } try { NamedPrefabs(instance)[StringExtensionMethods.GetStableHashCode(((Object)prefab).name)] = prefab; } catch (Exception ex) { ComplainOnce("scene:" + ((Object)prefab).name, "Could not register " + ((Object)prefab).name + " with ZNetScene: " + ex.Message); return false; } Log.LogInfo((object)("Registered " + ((Object)prefab).name + " with ZNetScene.")); return true; } public static bool RegisterItem(GameObject prefab) { ObjectDB instance = ObjectDB.instance; if ((Object)(object)instance == (Object)null || (Object)(object)prefab == (Object)null) { return false; } if (instance.m_items == null || instance.m_items.Count == 0) { return false; } if ((Object)(object)instance.GetItemPrefab(((Object)prefab).name) != (Object)null) { return true; } if (!instance.m_items.Contains(prefab)) { instance.m_items.Add(prefab); } try { UpdateRegisters(instance); } catch (Exception ex) { ComplainOnce("db:" + ((Object)prefab).name, "Could not refresh ObjectDB for " + ((Object)prefab).name + ": " + ex.Message); return false; } Log.LogInfo((object)("Registered " + ((Object)prefab).name + " with ObjectDB.")); return true; } public static PieceTable ToolPieces(string toolPrefab) { if ((Object)(object)ObjectDB.instance == (Object)null || string.IsNullOrEmpty(toolPrefab)) { return null; } GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(toolPrefab); ItemDrop val = (((Object)(object)itemPrefab != (Object)null) ? itemPrefab.GetComponent<ItemDrop>() : null); if ((Object)(object)val == (Object)null || val.m_itemData == null || val.m_itemData.m_shared == null) { return null; } PieceTable buildPieces = val.m_itemData.m_shared.m_buildPieces; if (!((Object)(object)buildPieces != (Object)null) || buildPieces.m_pieces == null) { return null; } return buildPieces; } public static bool InTool(GameObject prefab, string toolPrefab) { PieceTable val = ToolPieces(toolPrefab); if ((Object)(object)val != (Object)null && (Object)(object)prefab != (Object)null) { return val.m_pieces.Contains(prefab); } return false; } public static bool AddToTool(GameObject prefab, string toolPrefab) { if ((Object)(object)prefab == (Object)null) { return false; } PieceTable val = ToolPieces(toolPrefab); if ((Object)(object)val == (Object)null) { return false; } if (val.m_pieces.Contains(prefab)) { return true; } val.m_pieces.Add(prefab); Log.LogInfo((object)(((Object)prefab).name + " added to the " + toolPrefab + ".")); return true; } private static void ComplainOnce(string key, string message) { if (Complained.Add(key)) { Log.LogError((object)message); } } private static Dictionary<int, GameObject> NamedPrefabs(ZNetScene scene) { if (_named == null) { _named = AccessTools.FieldRefAccess<ZNetScene, Dictionary<int, GameObject>>("m_namedPrefabs"); } return _named.Invoke(scene); } private static void UpdateRegisters(ObjectDB db) { if (_updateRegisters == null) { _updateRegisters = AccessTools.Method(typeof(ObjectDB), "UpdateRegisters", (Type[])null, (Type[])null); } if (_updateRegisters == null) { throw new MissingMethodException("ObjectDB.UpdateRegisters"); } _updateRegisters.Invoke(db, null); } } } namespace Taum { [HarmonyPatch] internal static class Follow { private static bool Wants(Tameable tameable) { if (!TaumConfig.Enabled.Value || (Object)(object)tameable == (Object)null) { return false; } if (!tameable.IsTamed()) { return false; } return !tameable.m_commandable; } [HarmonyPrefix] [HarmonyPatch(typeof(Tameable), "Interact")] private static bool AltToFollow(Tameable __instance, Humanoid user, bool hold, bool alt, ref bool __result) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) if (hold || alt || !Wants(__instance)) { return true; } if (!Input.GetKey(TaumConfig.FollowKey.Value)) { return true; } __instance.Command(user, true); __result = true; return false; } [HarmonyPostfix] [HarmonyPatch(typeof(Tameable), "GetHoverText")] private static void Offer(Tameable __instance, ref string __result) { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) if (Wants(__instance) && !string.IsNullOrEmpty(__result)) { string text = ((object)TaumConfig.FollowKey.Value/*cast due to .constrained prefix*/).ToString().Replace("Left", "").Replace("Right", ""); __result += Localization.instance.Localize("\n[<color=yellow><b>" + text + " + $KEY_Use</b></color>] Follow / stay"); } } } internal static class TaumConfig { internal static ConfigEntry<bool> Enabled; internal static ConfigEntry<bool> Verbose; internal static ConfigEntry<KeyCode> FollowKey; internal static void Bind(ConfigFile cfg) { Enabled = cfg.Bind<bool>("Taum", "Enabled", true, "Off leaves the plugin loaded and changing nothing."); Verbose = cfg.Bind<bool>("Taum", "Verbose", false, "Write each halter put on, taken off and dropped to BepInEx/LogOutput.log."); FollowKey = cfg.Bind<KeyCode>("Taum", "FollowKey", (KeyCode)308, "Held with E on a tamed boar or hen to toggle follow/stay. Alt because vanilla already spends Shift+E on renaming and plain E on petting - all three gestures keep their own key."); } internal static Dictionary<string, string> Table(string raw, char separator = ',') { Dictionary<string, string> dictionary = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase); if (string.IsNullOrEmpty(raw)) { return dictionary; } string[] array = raw.Split(new char[1] { separator }, StringSplitOptions.RemoveEmptyEntries); for (int i = 0; i < array.Length; i++) { string text = array[i].Trim(); int num = text.IndexOf(':'); if (num > 0 && num != text.Length - 1) { dictionary[text.Substring(0, num).Trim()] = text.Substring(num + 1).Trim(); } } return dictionary; } } internal static class TaumPatches { [HarmonyPostfix] [HarmonyPatch(typeof(Player), "OnSpawned")] private static void OnSpawned(Player __instance) { if (!((Object)(object)__instance != (Object)(object)Player.m_localPlayer) && TaumConfig.Enabled.Value && TaumConfig.Verbose.Value) { TaumPlugin.Log.LogInfo((object)"Player spawned - patches are live."); } } } [BepInPlugin("ezomic.valheim.taum", "Taum", "1.0.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] public class TaumPlugin : BaseUnityPlugin { public const string PluginGuid = "ezomic.valheim.taum"; public const string PluginName = "Taum"; public const string PluginVersion = "1.0.0"; public const string PluginAuthor = "Robbin Thijssen"; private const string CoreGuid = "ezomic.valheim.core"; internal static ManualLogSource Log; private static readonly HashSet<string> Said = new HashSet<string>(); internal static bool CorePresent; private Harmony _harmony; internal static void LogOnce(string message) { if (Log != null && Said.Add(message)) { Log.LogWarning((object)message); } } private void Awake() { //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Expected O, but got Unknown Log = ((BaseUnityPlugin)this).Logger; TaumConfig.Bind(((BaseUnityPlugin)this).Config); Prefabs.Log = ((BaseUnityPlugin)this).Logger; TryRegisterWithCore(); _harmony = new Harmony("ezomic.valheim.taum"); _harmony.PatchAll(typeof(TaumPatches)); _harmony.PatchAll(typeof(Follow)); Log.LogInfo((object)"Taum 1.0.0 by Robbin Thijssen - ready."); } private void TryRegisterWithCore() { CorePresent = Chainloader.PluginInfos.ContainsKey("ezomic.valheim.core"); if (!CorePresent) { Log.LogInfo((object)"Core not installed - running standalone, without the version gate."); } else { RegisterWithCore(); } } [MethodImpl(MethodImplOptions.NoInlining)] private void RegisterWithCore() { Suite.Register("ezomic.valheim.taum", "Taum", "1.0.0", ((BaseUnityPlugin)this).Config, (Requirement)0, (Assembly)null); Suite.Sync((ConfigEntryBase)(object)TaumConfig.Enabled); } private void Update() { if (TaumConfig.Enabled.Value) { Prefabs.Tick(); } } private void OnDestroy() { if (_harmony != null) { _harmony.UnpatchSelf(); } } } }