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 TameAll v1.2.0
plugins/TameAll.dll
Decompiled a week agousing System; using System.Diagnostics; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: IgnoresAccessChecksTo("assembly_valheim")] [assembly: AssemblyCompany("TameAll")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.2.0.0")] [assembly: AssemblyInformationalVersion("1.2.0")] [assembly: AssemblyProduct("TameAll")] [assembly: AssemblyTitle("TameAll")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.2.0.0")] [module: UnverifiableCode] [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 Oddhatter.TameAll { [BepInPlugin("com.oddhatter.tameall", "TameAll", "1.2.0")] [BepInProcess("valheim.exe")] public sealed class TameAllPlugin : BaseUnityPlugin { public const string Guid = "com.oddhatter.tameall"; public const string Name = "TameAll"; public const string Version = "1.2.0"; internal static ManualLogSource Log; internal static ConfigEntry<bool> Enabled; internal static ConfigEntry<KeyCode> TameKey; internal static ConfigEntry<KeyCode> StayAllKey; internal static ConfigEntry<float> MaxDistance; internal static ConfigEntry<float> MaxHealthPercent; internal static ConfigEntry<bool> AllowBosses; internal static ConfigEntry<bool> FollowAfterTaming; private const float ConfigReloadDelay = 0.5f; private Harmony _harmony; private FileSystemWatcher _configWatcher; private volatile bool _configFileChanged; private float _configReloadAt = -1f; private bool _configLockedLogged; private void Awake() { //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Expected O, but got Unknown //IL_00d8: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: Expected O, but got Unknown //IL_012d: Unknown result type (might be due to invalid IL or missing references) //IL_0137: Expected O, but got Unknown Log = ((BaseUnityPlugin)this).Logger; Enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Master switch. When false the key does nothing (creatures you already tamed stay tame)."); TameKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("General", "TameKey", (KeyCode)106, "Look at a creature and press this key to tame it instantly. Press it on a monster you tamed to make it wild again."); StayAllKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("General", "StayAllKey", (KeyCode)104, "Press this key to make every creature that is following you stay where it is (they stay tame). Same as pressing Use on each one; press Use on one to make it follow again."); MaxDistance = ((BaseUnityPlugin)this).Config.Bind<float>("General", "MaxDistance", 20f, new ConfigDescription("How far away the creature can be, in meters.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 50f), Array.Empty<object>())); MaxHealthPercent = ((BaseUnityPlugin)this).Config.Bind<float>("General", "MaxHealthPercent", 100f, new ConfigDescription("The creature's health must be at or below this percent of its maximum. 100 = any health; 25 = you have to wear it down to a quarter first.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 100f), Array.Empty<object>())); AllowBosses = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "AllowBosses", false, "true: bosses can be tamed too. A tamed boss never dies, so you won't get its trophy or the world progress it unlocks."); FollowAfterTaming = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "FollowAfterTaming", true, "true: a creature starts following you as soon as it's tamed. Press Use on it to toggle follow / stay."); _harmony = new Harmony("com.oddhatter.tameall"); _harmony.PatchAll(typeof(TameAllPlugin).Assembly); foreach (MethodBase patchedMethod in _harmony.GetPatchedMethods()) { Log.LogInfo((object)("Patched " + patchedMethod.DeclaringType?.Name + "." + patchedMethod.Name)); } WatchConfigFile(); Log.LogInfo((object)"TameAll 1.2.0 loaded."); } private void Update() { Taming.UpdateKey(); if (_configFileChanged) { _configFileChanged = false; _configReloadAt = Time.realtimeSinceStartup + 0.5f; } if (_configReloadAt >= 0f && Time.realtimeSinceStartup >= _configReloadAt) { _configReloadAt = -1f; ReloadConfigFromDisk(); } } private void OnDestroy() { _configWatcher?.Dispose(); Harmony harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } } private void WatchConfigFile() { string configFilePath = ((BaseUnityPlugin)this).Config.ConfigFilePath; _configWatcher = new FileSystemWatcher(Path.GetDirectoryName(configFilePath), Path.GetFileName(configFilePath)) { NotifyFilter = (NotifyFilters.FileName | NotifyFilters.Size | NotifyFilters.LastWrite), IncludeSubdirectories = false }; _configWatcher.Changed += OnConfigFileEvent; _configWatcher.Created += OnConfigFileEvent; _configWatcher.Renamed += OnConfigFileEvent; _configWatcher.EnableRaisingEvents = true; } private void OnConfigFileEvent(object sender, FileSystemEventArgs e) { _configFileChanged = true; } private void ReloadConfigFromDisk() { if (!File.Exists(((BaseUnityPlugin)this).Config.ConfigFilePath)) { return; } bool saveOnConfigSet = ((BaseUnityPlugin)this).Config.SaveOnConfigSet; ((BaseUnityPlugin)this).Config.SaveOnConfigSet = false; try { ((BaseUnityPlugin)this).Config.Reload(); _configLockedLogged = false; Log.LogInfo((object)"Configuration reloaded from disk."); } catch (IOException ex) { if (!_configLockedLogged) { _configLockedLogged = true; Log.LogWarning((object)("Config file busy, will retry: " + ex.Message)); } _configReloadAt = Time.realtimeSinceStartup + 0.5f; } catch (Exception ex2) { Log.LogError((object)("Failed to reload configuration: " + ex2.Message)); } finally { ((BaseUnityPlugin)this).Config.SaveOnConfigSet = saveOnConfigSet; } } } internal static class Taming { internal static void UpdateKey() { //IL_0029: 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) Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null || !TameAllPlugin.Enabled.Value || !((Character)localPlayer).TakeInput()) { return; } if (ZInput.GetKeyDown(TameAllPlugin.StayAllKey.Value, false)) { StayAll(localPlayer); } else if (ZInput.GetKeyDown(TameAllPlugin.TameKey.Value, false)) { Character hoverCreature = localPlayer.GetHoverCreature(); string text = CheckTarget(localPlayer, hoverCreature); if (text != null) { ((Character)localPlayer).Message((MessageType)1, text, 0, (Sprite)null, false); } else if (hoverCreature.IsTamed()) { Untame(localPlayer, hoverCreature); } else { Tame(localPlayer, hoverCreature); } } } private static void StayAll(Player player) { string playerName = player.GetPlayerName(); int num = 0; foreach (Character allCharacter in Character.GetAllCharacters()) { if (!allCharacter.IsTamed()) { continue; } BaseAI baseAI = allCharacter.GetBaseAI(); MonsterAI val = (MonsterAI)(object)((baseAI is MonsterAI) ? baseAI : null); if (val != null) { Tameable component = ((Component)allCharacter).GetComponent<Tameable>(); ZDO zDO = ((BaseAI)val).m_nview.GetZDO(); if (!((Object)(object)component == (Object)null) && zDO != null && ((Object)(object)val.GetFollowTarget() == (Object)(object)((Component)player).gameObject || zDO.GetString(ZDOVars.s_follow, "") == playerName)) { component.Command((Humanoid)(object)player, false); num++; } } } ((Character)player).Message((MessageType)2, num switch { 1 => "1 creature stays", 0 => "Nothing is following you", _ => $"{num} creatures stay", }, 0, (Sprite)null, false); } private static string CheckTarget(Player player, Character target) { //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)target == (Object)null || target.IsPlayer()) { return "Look at a creature to tame it"; } if (!(target.GetBaseAI() is MonsterAI)) { return target.m_name + " can't be tamed"; } if (target.IsTamed() && !IsTameableAddedByMod(((Component)target).gameObject)) { return target.m_name + " is already tame"; } if (target.IsBoss() && !target.IsTamed() && !TameAllPlugin.AllowBosses.Value) { return "Bosses can't be tamed (AllowBosses is off)"; } if (Vector3.Distance(((Component)player).transform.position, ((Component)target).transform.position) > TameAllPlugin.MaxDistance.Value) { return target.m_name + " is too far away"; } if (target.IsTamed()) { return null; } if (((target.GetMaxHealth() > 0f) ? (target.GetHealth() / target.GetMaxHealth() * 100f) : 0f) > TameAllPlugin.MaxHealthPercent.Value + 0.01f) { return $"{target.m_name} is too healthy to tame (needs {TameAllPlugin.MaxHealthPercent.Value:0}% health or less)"; } return null; } private static void Tame(Player player, Character target) { //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Expected O, but got Unknown //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_0072: 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) ZNetView component = ((Component)target).GetComponent<ZNetView>(); if (!((Object)(object)component == (Object)null) && component.IsValid()) { component.ClaimOwnership(); MonsterAI val = (MonsterAI)target.GetBaseAI(); Tameable val2 = EnsureTameable(val); val.MakeTame(); val.SetDespawnInDay(false); val.SetEventCreature(false); ((BaseAI)val).SetHuntPlayer(false); val2.m_tamedEffect.Create(((Component)target).transform.position, ((Component)target).transform.rotation, (Transform)null, 1f, -1, default(ZDOID)); if (TameAllPlugin.FollowAfterTaming.Value && (Object)(object)val.GetFollowTarget() == (Object)null) { val2.Command((Humanoid)(object)player, false); } ((Character)player).Message((MessageType)2, target.m_name + " $hud_tamedone", 0, (Sprite)null, false); TameAllPlugin.Log.LogInfo((object)("Tamed " + Utils.GetPrefabName(((Component)target).gameObject) + ".")); } } private static void Untame(Player player, Character target) { //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Expected O, but got Unknown ZNetView component = ((Component)target).GetComponent<ZNetView>(); if (!((Object)(object)component == (Object)null) && component.IsValid()) { component.ClaimOwnership(); MonsterAI val = (MonsterAI)target.GetBaseAI(); val.SetFollowTarget((GameObject)null); ((BaseAI)val).SetPatrolPoint(); component.GetZDO().Set(ZDOVars.s_follow, ""); target.SetTamed(false); RemoveTameable(val); ((Character)player).Message((MessageType)2, target.m_name + " is wild again", 0, (Sprite)null, false); TameAllPlugin.Log.LogInfo((object)("Untamed " + Utils.GetPrefabName(((Component)target).gameObject) + ".")); } } internal static bool IsTameableAddedByMod(GameObject creature) { GameObject val = (((Object)(object)ZNetScene.instance != (Object)null) ? ZNetScene.instance.GetPrefab(Utils.GetPrefabName(creature)) : null); if ((Object)(object)val != (Object)null) { return (Object)(object)val.GetComponent<Tameable>() == (Object)null; } return false; } private static void RemoveTameable(MonsterAI ai) { Tameable component = ((Component)ai).GetComponent<Tameable>(); if (!((Object)(object)component == (Object)null)) { ((BaseAI)ai).m_nview.Unregister("Command"); ((BaseAI)ai).m_nview.Unregister("SetName"); ((BaseAI)ai).m_nview.Unregister("RPC_UnSummon"); Character character = ((BaseAI)ai).m_character; character.m_onDeath = (Action)Delegate.Remove(character.m_onDeath, new Action(component.OnDeath)); ai.m_onConsumedItem = (Action<ItemDrop>)Delegate.Remove(ai.m_onConsumedItem, new Action<ItemDrop>(component.OnConsumedItem)); ((BaseAI)ai).m_tamable = null; Object.Destroy((Object)(object)component); } } internal static Tameable EnsureTameable(MonsterAI ai) { Tameable component = ((Component)ai).GetComponent<Tameable>(); if ((Object)(object)component != (Object)null) { return component; } component = ((Component)ai).gameObject.AddComponent<Tameable>(); component.m_commandable = true; component.m_fedDuration = float.MaxValue; ((BaseAI)ai).m_tamable = component; return component; } } [HarmonyPatch(typeof(MonsterAI), "Awake")] internal static class MonsterAI_Awake_Patch { private static void Postfix(MonsterAI __instance) { ZDO val = (((Object)(object)((BaseAI)__instance).m_nview != (Object)null) ? ((BaseAI)__instance).m_nview.GetZDO() : null); if (val != null && val.GetBool(ZDOVars.s_tamed, false) && (Object)(object)((Component)__instance).GetComponent<Tameable>() == (Object)null) { Taming.EnsureTameable(__instance); } } } [HarmonyPatch(typeof(Tameable), "TamingUpdate")] internal static class Tameable_TamingUpdate_Patch { private static bool Prefix(Tameable __instance) { return !Taming.IsTameableAddedByMod(((Component)__instance).gameObject); } } } namespace System.Runtime.CompilerServices { [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] internal sealed class IgnoresAccessChecksToAttribute : Attribute { internal IgnoresAccessChecksToAttribute(string assemblyName) { } } }