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 LetsGo v1.0.0
LetsGo.dll
Decompiled 3 days agousing System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using UnityEngine; using UnityEngine.EventSystems; [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: AssemblyCompany("LetsGo")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyDescription("Follow, Stay, pack call, portal-follow, and cart hitch for any tamed Valheim creature.")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+d5478cea8ca2b6da00ba699f5f5cd9ddbc4cfc1a")] [assembly: AssemblyProduct("LetsGo")] [assembly: AssemblyTitle("LetsGo")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.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 LetsGo { internal sealed class AnimalFollowController : MonoBehaviour { public static void EnsureAttached(Character character) { if (!((Object)(object)character == (Object)null) && !((Object)(object)((Component)character).GetComponent<AnimalAI>() == (Object)null) && (Object)(object)((Component)character).GetComponent<AnimalFollowController>() == (Object)null) { ((Component)character).gameObject.AddComponent<AnimalFollowController>(); } } public static bool TryApply(AnimalAI animalAi, float dt) { //IL_007a: 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_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: 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_00dd: Unknown result type (might be due to invalid IL or missing references) if (!ModConfig.Enabled.Value || !ModConfig.EnableFollow.Value || (Object)(object)animalAi == (Object)null) { return false; } Character component = ((Component)animalAi).GetComponent<Character>(); ZNetView component2 = ((Component)animalAi).GetComponent<ZNetView>(); if ((Object)(object)component == (Object)null || (Object)(object)component2 == (Object)null || !component2.IsValid() || !component2.IsOwner()) { return false; } if (!TameEligibility.IsEligible(component) || FollowCommands.GetOrder(component) != TameOrder.Follow) { return false; } ZDO zdo = component.GetZdo(); if (zdo == null) { return false; } Player val = TameEligibility.ResolvePlayer(zdo.GetZDOID("hw_letsgo_follow")); if ((Object)(object)val == (Object)null) { return false; } Vector3 val2 = ((Component)val).transform.position - ((Component)component).transform.position; val2.y = 0f; float magnitude = ((Vector3)(ref val2)).magnitude; float followStopDistance = FollowCommands.GetFollowStopDistance(component); if (magnitude < followStopDistance) { ((BaseAI)animalAi).StopMoving(); return true; } ((BaseAI)animalAi).MoveTowards(val2 / magnitude, magnitude > followStopDistance * 3f); return true; } } internal static class CartAttachment { private struct RearCache { public float Extent; public float Time; } private const float HitchY = 0.8f; private const float DetachSlack = 1.5f; private static readonly Dictionary<int, RearCache> RearExtentCache = new Dictionary<int, RearCache>(); public static bool CanPullCart(Character character) { if ((Object)(object)character == (Object)null || character.IsPlayer() || character.IsDead()) { return false; } if (!character.IsTamed() || !TameEligibility.IsEligible(character)) { return false; } if (JuvenileSpecies.IsEligibleJuvenile(character) || (Object)(object)((Component)character).GetComponent<Growup>() != (Object)null) { return false; } return character.GetRadius() >= ModConfig.CartMinRadius.Value; } public static Vector3 GetOffset(Character character) { //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)character == (Object)null || character.IsPlayer()) { return new Vector3(0f, 0.8f, 0f); } return new Vector3(0f, 0.8f, 0f - GetHitchBack(character)); } public static float GetDetachDistance(Character character) { if ((Object)(object)character == (Object)null || character.IsPlayer()) { return ModConfig.CartDetachDistancePlayer.Value; } return Mathf.Max(character.GetRadius() * ModConfig.CartDetachDistanceFactor.Value, GetHitchBack(character) + 1.5f); } public static Character FindClosestAttachable(Vagon cart) { //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)cart == (Object)null || (Object)(object)cart.m_attachPoint == (Object)null) { return null; } Character result = null; float num = float.MaxValue; foreach (Character allCharacter in Character.GetAllCharacters()) { if (CanPullCart(allCharacter)) { Vector3 offset = GetOffset(allCharacter); float num2 = Vector3.Distance(((Component)allCharacter).transform.position + offset, cart.m_attachPoint.position); float detachDistance = GetDetachDistance(allCharacter); if (num2 < detachDistance && num2 < num) { result = allCharacter; num = num2; } } } return result; } public static Character GetAttached(Vagon cart) { if ((Object)(object)cart == (Object)null || !cart.IsAttached()) { return null; } ConfigurableJoint val = VagonAccess.GetJoin(cart); if ((Object)(object)val == (Object)null || (Object)(object)((Joint)val).connectedBody == (Object)null) { return null; } return ((Component)((Joint)val).connectedBody).GetComponent<Character>(); } public static void Attach(Character target, Vagon cart) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)target == (Object)null) && !((Object)(object)cart == (Object)null)) { cart.m_attachOffset = GetOffset(target); VagonAccess.AttachTo(cart, ((Component)target).gameObject); ConfigurableJoint val = VagonAccess.GetJoin(cart); if ((Object)(object)val != (Object)null && !target.IsPlayer()) { float num = Mathf.Max(1f, target.GetRadius() * ModConfig.CartPullScalePerRadius.Value); ((Joint)val).breakForce = cart.m_breakForce * num; } if (!target.IsPlayer()) { SetPullerCollision(cart, target, ignore: true); } } } public static void DetachFrom(Character character) { if ((Object)(object)character == (Object)null) { return; } Vagon[] array = Object.FindObjectsByType<Vagon>((FindObjectsSortMode)0); foreach (Vagon cart in array) { if ((Object)(object)GetAttached(cart) == (Object)(object)character) { VagonAccess.Detach(cart); } } } public static void SetPullerCollision(Vagon cart, Character character, bool ignore) { if ((ignore && !ModConfig.CartIgnorePullerCollision.Value) || (Object)(object)cart == (Object)null || (Object)(object)character == (Object)null) { return; } Collider[] componentsInChildren = ((Component)cart).GetComponentsInChildren<Collider>(true); Collider[] componentsInChildren2 = ((Component)character).GetComponentsInChildren<Collider>(true); Collider[] array = componentsInChildren; foreach (Collider val in array) { if ((Object)(object)val == (Object)null || val.isTrigger) { continue; } Collider[] array2 = componentsInChildren2; foreach (Collider val2 in array2) { if (!((Object)(object)val2 == (Object)null) && !val2.isTrigger) { Physics.IgnoreCollision(val, val2, ignore); } } } } private static float GetHitchBack(Character character) { float radius = character.GetRadius(); float rearExtent = GetRearExtent(character); return Mathf.Max(radius, rearExtent) + ModConfig.CartHitchBackPadding.Value; } private static float GetRearExtent(Character character) { //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0075: 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_007e: 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_0087: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00c7: 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_00d3: Unknown result type (might be due to invalid IL or missing references) //IL_00da: Unknown result type (might be due to invalid IL or missing references) //IL_00e1: Unknown result type (might be due to invalid IL or missing references) //IL_00e8: Unknown result type (might be due to invalid IL or missing references) //IL_00ed: Unknown result type (might be due to invalid IL or missing references) //IL_00f4: Unknown result type (might be due to invalid IL or missing references) //IL_00fb: Unknown result type (might be due to invalid IL or missing references) //IL_0102: Unknown result type (might be due to invalid IL or missing references) //IL_0109: Unknown result type (might be due to invalid IL or missing references) //IL_010e: Unknown result type (might be due to invalid IL or missing references) //IL_0115: Unknown result type (might be due to invalid IL or missing references) //IL_011c: Unknown result type (might be due to invalid IL or missing references) //IL_0123: Unknown result type (might be due to invalid IL or missing references) //IL_012a: Unknown result type (might be due to invalid IL or missing references) //IL_012f: Unknown result type (might be due to invalid IL or missing references) //IL_0136: Unknown result type (might be due to invalid IL or missing references) //IL_013d: Unknown result type (might be due to invalid IL or missing references) //IL_0144: Unknown result type (might be due to invalid IL or missing references) //IL_014b: Unknown result type (might be due to invalid IL or missing references) //IL_0150: Unknown result type (might be due to invalid IL or missing references) //IL_0157: Unknown result type (might be due to invalid IL or missing references) //IL_015e: Unknown result type (might be due to invalid IL or missing references) //IL_0165: Unknown result type (might be due to invalid IL or missing references) //IL_016c: Unknown result type (might be due to invalid IL or missing references) //IL_0171: Unknown result type (might be due to invalid IL or missing references) //IL_0178: Unknown result type (might be due to invalid IL or missing references) //IL_017f: Unknown result type (might be due to invalid IL or missing references) //IL_0186: Unknown result type (might be due to invalid IL or missing references) //IL_018d: Unknown result type (might be due to invalid IL or missing references) //IL_0192: Unknown result type (might be due to invalid IL or missing references) //IL_01a2: Unknown result type (might be due to invalid IL or missing references) //IL_01a7: Unknown result type (might be due to invalid IL or missing references) //IL_01aa: Unknown result type (might be due to invalid IL or missing references) //IL_01ac: Unknown result type (might be due to invalid IL or missing references) int instanceID = ((Object)character).GetInstanceID(); if (RearExtentCache.TryGetValue(instanceID, out var value) && Time.time - value.Time < 2f) { return value.Extent; } float num = character.GetRadius(); Transform transform = ((Component)character).transform; Renderer[] componentsInChildren = ((Component)character).GetComponentsInChildren<Renderer>(); foreach (Renderer val in componentsInChildren) { if ((Object)(object)val == (Object)null || !val.enabled) { continue; } Bounds bounds = val.bounds; Vector3 min = ((Bounds)(ref bounds)).min; Vector3 max = ((Bounds)(ref bounds)).max; Vector3[] array = (Vector3[])(object)new Vector3[8] { new Vector3(min.x, min.y, min.z), new Vector3(min.x, min.y, max.z), new Vector3(min.x, max.y, min.z), new Vector3(min.x, max.y, max.z), new Vector3(max.x, min.y, min.z), new Vector3(max.x, min.y, max.z), new Vector3(max.x, max.y, min.z), new Vector3(max.x, max.y, max.z) }; foreach (Vector3 val2 in array) { float num2 = 0f - transform.InverseTransformPoint(val2).z; if (num2 > num) { num = num2; } } } RearExtentCache[instanceID] = new RearCache { Extent = num, Time = Time.time }; return num; } } internal static class CompatPlugins { internal static bool OffspringPortalLoaded => Chainloader.PluginInfos.ContainsKey("offspringportal.mod"); internal static bool ServersideQoLLoaded { get { if (!Chainloader.PluginInfos.ContainsKey("argusmagnus.ServersideQoL")) { return Chainloader.PluginInfos.ContainsKey("ArgusMagnus.ServersideQoL"); } return true; } } internal static bool TeleportEverythingLoaded { get { if (Chainloader.PluginInfos.ContainsKey("com.kpro.TeleportEverything")) { return true; } foreach (PluginInfo value in Chainloader.PluginInfos.Values) { if (value.Metadata.GUID.IndexOf("teleporteverything", StringComparison.OrdinalIgnoreCase) >= 0 || value.Metadata.Name.IndexOf("TeleportEverything", StringComparison.OrdinalIgnoreCase) >= 0) { return true; } } return false; } } internal static bool SkipOurCommandable { get { if (ModConfig.SkipCommandableIfServersideQoL.Value) { return ServersideQoLLoaded; } return false; } } internal static bool SkipOurRecall { get { if (ModConfig.SkipRecallIfServersideQoL.Value) { return ServersideQoLLoaded; } return false; } } internal static bool SkipOurPortalFollow { get { if (!SkipOurRecall) { if (ModConfig.SkipPortalFollowIfTeleportEverything.Value) { return TeleportEverythingLoaded; } return false; } return true; } } } internal static class FollowCommands { public static Character LastHovered; public static TameOrder GetOrder(Character character) { ZDO zdo = character.GetZdo(); if (zdo == null) { return TameOrder.Stay; } return (TameOrder)zdo.GetInt("hw_letsgo_order", (int)InferOrderFromAi(character)); } public static bool IsFollowing(Character character, Player player = null) { //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)character == (Object)null) { return false; } MonsterAI component = ((Component)character).GetComponent<MonsterAI>(); if ((Object)(object)component != (Object)null) { GameObject followTarget = component.GetFollowTarget(); if ((Object)(object)followTarget == (Object)null) { return false; } if ((Object)(object)player == (Object)null) { return (Object)(object)followTarget.GetComponent<Player>() != (Object)null; } return (Object)(object)followTarget == (Object)(object)((Component)player).gameObject; } ZDO zdo = character.GetZdo(); if (zdo == null) { return false; } ZDOID zDOID = zdo.GetZDOID("hw_letsgo_follow"); if (zDOID == ZDOID.None) { return false; } if ((Object)(object)player == (Object)null) { return true; } ZDO zdo2 = ((Character)(object)player).GetZdo(); if (zdo2 != null) { return zDOID == zdo2.m_uid; } return false; } public static bool IsFollowingAnyoneElse(Character character, Player self) { if (!IsFollowing(character)) { return false; } return !IsFollowing(character, self); } public static TameOrder CycleOrder(Character character, Player player, bool showMessage) { TameOrder tameOrder = ((GetOrder(character) != TameOrder.Follow) ? TameOrder.Follow : TameOrder.Stay); ApplyOrder(character, player, tameOrder, showMessage); return tameOrder; } public static void ApplyOrder(Character character, Player player, TameOrder order, bool showMessage) { if (!((Object)(object)character == (Object)null) && !((Object)(object)player == (Object)null) && TameEligibility.IsEligible(character)) { Tameable component = ((Component)character).GetComponent<Tameable>(); if ((Object)(object)component != (Object)null && !CompatPlugins.SkipOurCommandable) { component.m_commandable = true; } character.GetNview(); LocalAuthority.TryClaim(character); ZDO zdo = character.GetZdo(); if (zdo != null) { zdo.Set("hw_letsgo_order", (int)order); } MonsterAI component2 = ((Component)character).GetComponent<MonsterAI>(); if ((Object)(object)component2 != (Object)null) { ApplyMonsterOrder(character, component2, player, order); } else { ApplyAnimalOrder(character, player, order); } AnimalFollowController.EnsureAttached(character); JuvenileFollowController.EnsureAttached(character); if (showMessage) { ((Character)player).Message((MessageType)2, FormatOrderMessage(character, order), 0, (Sprite)null, false); } } } public static float GetFollowStopDistance(Character character) { if ((Object)(object)character == (Object)null) { return ModConfig.MediumFollowDistance.Value; } float num = character.GetRadius() * ModConfig.FollowDistanceFactor.Value; return Mathf.Max(ModConfig.MediumFollowDistance.Value, num); } public static string FormatOrderMessage(Character character, TameOrder order) { string hoverName = character.GetHoverName(); if (order == TameOrder.Follow) { return hoverName + " " + Localization.instance.Localize("$hud_tamefollow"); } return hoverName + " " + Localization.instance.Localize("$hud_tamestay"); } private static TameOrder InferOrderFromAi(Character character) { if (!IsFollowing(character)) { return TameOrder.Stay; } return TameOrder.Follow; } private static void ApplyMonsterOrder(Character character, MonsterAI monsterAi, Player player, TameOrder order) { ZNetView nview = character.GetNview(); if (order == TameOrder.Follow) { ((BaseAI)monsterAi).ResetPatrolPoint(); monsterAi.SetFollowTarget(((Component)player).gameObject); if ((Object)(object)nview != (Object)null && nview.IsOwner()) { ZDO zDO = nview.GetZDO(); if (zDO != null) { zDO.Set(ZDOVars.s_follow, player.GetPlayerName()); } } return; } monsterAi.SetFollowTarget((GameObject)null); ((BaseAI)monsterAi).SetPatrolPoint(); if ((Object)(object)nview != (Object)null && nview.IsOwner()) { ZDO zDO2 = nview.GetZDO(); if (zDO2 != null) { zDO2.Set(ZDOVars.s_follow, string.Empty); } } } private static void ApplyAnimalOrder(Character character, Player player, TameOrder order) { //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) ZDO zdo = character.GetZdo(); if (zdo != null) { if (order == TameOrder.Follow) { zdo.Set("hw_letsgo_follow", ((Character)player).GetZDOID()); } else { zdo.Set("hw_letsgo_follow", ZDOID.None); } } } } internal static class VagonAccess { private static readonly FieldRef<Vagon, ConfigurableJoint> AttachJoin = AccessTools.FieldRefAccess<Vagon, ConfigurableJoint>("m_attachJoin"); private static readonly FieldRef<Vagon, Humanoid> UseRequester = AccessTools.FieldRefAccess<Vagon, Humanoid>("m_useRequester"); private static readonly FieldRef<Vagon, ZNetView> Nview = AccessTools.FieldRefAccess<Vagon, ZNetView>("m_nview"); private static readonly MethodInfo AttachToMethod = AccessTools.Method(typeof(Vagon), "AttachTo", new Type[1] { typeof(GameObject) }, (Type[])null); private static readonly MethodInfo DetachMethod = AccessTools.Method(typeof(Vagon), "Detach", (Type[])null, (Type[])null); private static readonly MethodInfo CanAttachMethod = AccessTools.Method(typeof(Vagon), "CanAttach", new Type[1] { typeof(GameObject) }, (Type[])null); private static readonly MethodInfo UpdateAudioMethod = AccessTools.Method(typeof(Vagon), "UpdateAudio", new Type[1] { typeof(float) }, (Type[])null); private static readonly MethodInfo UpdateSnowMethod = AccessTools.Method(typeof(Vagon), "UpdateSnow", (Type[])null, (Type[])null); internal static ConfigurableJoint GetJoin(Vagon cart) { return AttachJoin.Invoke(cart); } internal static Player GetUseRequester(Vagon cart) { Humanoid obj = UseRequester.Invoke(cart); return (Player)(object)((obj is Player) ? obj : null); } internal static void SetUseRequester(Vagon cart, Player player) { UseRequester.Invoke(cart) = (Humanoid)(object)player; } internal static ZNetView GetNview(Vagon cart) { return Nview.Invoke(cart); } internal static void AttachTo(Vagon cart, GameObject target) { AttachToMethod?.Invoke(cart, new object[1] { target }); } internal static void Detach(Vagon cart) { DetachMethod?.Invoke(cart, null); } internal static bool CanAttach(Vagon cart, GameObject target) { object obj = CanAttachMethod?.Invoke(cart, new object[1] { target }); bool flag = default(bool); int num; if (obj is bool) { flag = (bool)obj; num = 1; } else { num = 0; } return (byte)((uint)num & (flag ? 1u : 0u)) != 0; } internal static void UpdateAudio(Vagon cart, float dt) { UpdateAudioMethod?.Invoke(cart, new object[1] { dt }); } internal static void UpdateSnow(Vagon cart) { UpdateSnowMethod?.Invoke(cart, null); } } internal static class BaseAIAccess { private static readonly FieldRef<BaseAI, Character> CharacterField = AccessTools.FieldRefAccess<BaseAI, Character>("m_character"); private static readonly MethodInfo MoveToMethod = AccessTools.Method(typeof(BaseAI), "MoveTo", new Type[4] { typeof(float), typeof(Vector3), typeof(float), typeof(bool) }, (Type[])null); internal static Character GetCharacter(BaseAI ai) { if (!((Object)(object)ai != (Object)null)) { return null; } return CharacterField.Invoke(ai); } internal static bool MoveTo(BaseAI ai, float dt, Vector3 point, float distance, bool run) { //IL_001e: Unknown result type (might be due to invalid IL or missing references) object obj = MoveToMethod?.Invoke(ai, new object[4] { dt, point, distance, run }); bool flag = default(bool); int num; if (obj is bool) { flag = (bool)obj; num = 1; } else { num = 0; } return (byte)((uint)num & (flag ? 1u : 0u)) != 0; } } internal static class JuvenileFollow { public static bool TryCommand(Character character, Player player, bool showMessage) { //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)character == (Object)null || (Object)(object)player == (Object)null) { return false; } if (!JuvenileSpecies.IsEligibleJuvenile(character) || !character.IsTamed()) { return false; } ZNetView nview = character.GetNview(); if ((Object)(object)nview == (Object)null || !nview.IsValid()) { return false; } JuvenileGroundSnapper.EnsureAttached(character); JuvenileFollowController.EnsureAttached(character); if (LocalAuthority.HasLoaded(character)) { return ApplyFollowToggle(character, player, showMessage); } JuvenileFollowRpc.RequestToggle(nview.GetZDO().m_uid, ((Character)player).GetZDOID(), showMessage); return true; } public static bool ApplyFollowToggle(Character character, Player player, bool showMessage) { if ((Object)(object)character == (Object)null || (Object)(object)player == (Object)null || !character.IsTamed()) { return false; } MonsterAI component = ((Component)character).GetComponent<MonsterAI>(); if ((Object)(object)component != (Object)null) { Tameable component2 = ((Component)character).GetComponent<Tameable>(); if ((Object)(object)component2 != (Object)null) { component2.m_commandable = true; } ApplyMonsterFollowToggle(character, component, player, showMessage); SyncOrderZdo(character); return true; } if ((Object)(object)((Component)character).GetComponent<AnimalAI>() != (Object)null) { bool num = ApplyAnimalFollowToggle(character, player, showMessage); if (num) { SyncOrderZdo(character); } return num; } return false; } public static bool IsFollowing(Character character) { //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)character == (Object)null) { return false; } MonsterAI component = ((Component)character).GetComponent<MonsterAI>(); if ((Object)(object)component != (Object)null && (Object)(object)component.GetFollowTarget() != (Object)null) { return true; } ZDO zdo = character.GetZdo(); if (zdo != null) { return zdo.GetZDOID("hw_letsgo_follow") != ZDOID.None; } return false; } private static void SyncOrderZdo(Character character) { ZDO zdo = character.GetZdo(); if (zdo != null) { zdo.Set("hw_letsgo_order", IsFollowing(character) ? 1 : 0); } } private static void ApplyMonsterFollowToggle(Character character, MonsterAI monsterAi, Player player, bool showMessage) { //IL_0100: 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) ZNetView nview = character.GetNview(); if ((Object)(object)nview != (Object)null && !nview.IsOwner()) { nview.ClaimOwnership(); } string hoverName = character.GetHoverName(); if ((Object)(object)monsterAi.GetFollowTarget() != (Object)null) { monsterAi.SetFollowTarget((GameObject)null); ((BaseAI)monsterAi).SetPatrolPoint(); if ((Object)(object)nview != (Object)null && nview.IsOwner()) { ZDO zDO = nview.GetZDO(); if (zDO != null) { zDO.Set(ZDOVars.s_follow, string.Empty); } ZDO zDO2 = nview.GetZDO(); if (zDO2 != null) { zDO2.Set("hw_letsgo_follow", ZDOID.None); } } if (showMessage) { ((Character)player).Message((MessageType)2, hoverName + " " + Localization.instance.Localize("$hud_tamestay"), 0, (Sprite)null, false); } return; } ((BaseAI)monsterAi).ResetPatrolPoint(); monsterAi.SetFollowTarget(((Component)player).gameObject); if ((Object)(object)nview != (Object)null && nview.IsOwner()) { ZDO zDO3 = nview.GetZDO(); if (zDO3 != null) { zDO3.Set(ZDOVars.s_follow, player.GetPlayerName()); } ZDO zDO4 = nview.GetZDO(); if (zDO4 != null) { zDO4.Set("hw_letsgo_follow", ((Character)player).GetZDOID()); } } if (showMessage) { ((Character)player).Message((MessageType)2, hoverName + " " + Localization.instance.Localize("$hud_tamefollow"), 0, (Sprite)null, false); } } public static bool ApplyAnimalFollowToggle(Character character, Player player, bool showMessage) { //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_0041: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) ZNetView nview = character.GetNview(); if ((Object)(object)nview == (Object)null || !nview.IsValid()) { return false; } if (!nview.IsOwner()) { nview.ClaimOwnership(); } ZDO zdo = character.GetZdo(); if (zdo == null) { return false; } ZDOID zDOID = ((Character)player).GetZDOID(); ZDOID zDOID2 = zdo.GetZDOID("hw_letsgo_follow"); string hoverName = character.GetHoverName(); if (zDOID2 == zDOID) { zdo.Set("hw_letsgo_follow", ZDOID.None); if (showMessage) { ((Character)player).Message((MessageType)2, hoverName + " " + Localization.instance.Localize("$hud_tamestay"), 0, (Sprite)null, false); } } else { zdo.Set("hw_letsgo_follow", zDOID); if (showMessage) { ((Character)player).Message((MessageType)2, hoverName + " " + Localization.instance.Localize("$hud_tamefollow"), 0, (Sprite)null, false); } } return true; } } internal sealed class JuvenileFollowController : MonoBehaviour { public static bool TryApplyAnimalFollow(AnimalAI animalAi, float dt) { //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_0081: 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_0090: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00ee: 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) if (!ModConfig.Enabled.Value || !ModConfig.EnableFollow.Value || (Object)(object)animalAi == (Object)null) { return false; } Character component = ((Component)animalAi).GetComponent<Character>(); ZNetView component2 = ((Component)animalAi).GetComponent<ZNetView>(); if ((Object)(object)component == (Object)null || (Object)(object)component2 == (Object)null || !component2.IsValid()) { return false; } if (!component2.IsOwner()) { return false; } if (!JuvenileSpecies.IsEligibleJuvenile(component) || !component.IsTamed()) { return false; } ZDO zdo = component.GetZdo(); if (zdo == null) { return false; } ZDOID zDOID = zdo.GetZDOID("hw_letsgo_follow"); if (zDOID == ZDOID.None) { return false; } Player val = TameEligibility.ResolvePlayer(zDOID); if ((Object)(object)val == (Object)null) { return false; } Vector3 val2 = ((Component)val).transform.position - ((Component)component).transform.position; val2.y = 0f; float magnitude = ((Vector3)(ref val2)).magnitude; float followStopDistance = FollowCommands.GetFollowStopDistance(component); if (magnitude < followStopDistance) { ((BaseAI)animalAi).StopMoving(); return true; } ((BaseAI)animalAi).MoveTowards(val2 / magnitude, magnitude > followStopDistance * 3f); return true; } public static void EnsureAttached(Character character) { if (!((Object)(object)character == (Object)null) && !((Object)(object)((Component)character).GetComponent<AnimalAI>() == (Object)null) && (Object)(object)((Component)character).GetComponent<JuvenileFollowController>() == (Object)null) { ((Component)character).gameObject.AddComponent<JuvenileFollowController>(); } } } internal static class JuvenileFollowDisplay { public static void ApplyFollowHover(Character character, ref string hoverText) { if (ModConfig.Enabled.Value && ModConfig.EnableFollow.Value && !((Object)(object)character == (Object)null) && JuvenileSpecies.IsEligibleJuvenile(character) && character.IsTamed() && (!((Object)(object)((Component)character).GetComponent<MonsterAI>() == (Object)null) || !((Object)(object)((Component)character).GetComponent<AnimalAI>() == (Object)null))) { string text = (JuvenileFollow.IsFollowing(character) ? "$hud_tamestay" : "$hud_tamefollow"); string newValue = Localization.instance.Localize(text); string text2 = Localization.instance.Localize("$hud_pet"); if (!string.IsNullOrEmpty(hoverText) && hoverText.Contains(text2)) { hoverText = hoverText.Replace(text2, newValue); } else if (!string.IsNullOrEmpty(hoverText)) { hoverText += Localization.instance.Localize("\n[<color=yellow><b>$KEY_Use</b></color>] " + text); } else { hoverText = Localization.instance.Localize(character.GetHoverName() + "\n[<color=yellow><b>$KEY_Use</b></color>] " + text); } } } } internal static class JuvenileFollowRpc { private const string RpcToggleFollow = "hw_letsgo_juv_follow"; private const string RpcExecuteToggleFollow = "hw_letsgo_juv_follow_exec"; public static void Register() { ZRoutedRpc.instance.Register<ZDOID, ZDOID, bool>("hw_letsgo_juv_follow", (Action<long, ZDOID, ZDOID, bool>)OnToggleFollowRpc); ZRoutedRpc.instance.Register<ZDOID, ZDOID, bool>("hw_letsgo_juv_follow_exec", (Action<long, ZDOID, ZDOID, bool>)OnExecuteToggleFollowRpc); } public static void RequestToggle(ZDOID creatureId, ZDOID playerId, bool showMessage) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) ZRoutedRpc.instance.InvokeRoutedRPC("hw_letsgo_juv_follow", new object[3] { creatureId, playerId, showMessage }); } private static void OnToggleFollowRpc(long sender, ZDOID creatureId, ZDOID playerId, bool showMessage) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //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_0035: Unknown result type (might be due to invalid IL or missing references) if (ZNet.instance.IsServer() && !TryApply(creatureId, playerId, sender, showMessage)) { ZRoutedRpc.instance.InvokeRoutedRPC(sender, "hw_letsgo_juv_follow_exec", new object[3] { creatureId, playerId, showMessage }); } } private static void OnExecuteToggleFollowRpc(long sender, ZDOID creatureId, ZDOID playerId, bool showMessage) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0001: Unknown result type (might be due to invalid IL or missing references) TryApply(creatureId, playerId, sender, showMessage); } private static bool TryApply(ZDOID creatureId, ZDOID playerId, long sender, bool showMessage) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) Character val = TameEligibility.ResolveCharacter(creatureId); Player val2 = ResolveRequestingPlayer(sender, playerId); if ((Object)(object)val == (Object)null || (Object)(object)val2 == (Object)null) { return false; } if (!JuvenileSpecies.IsEligibleJuvenile(val) || !val.IsTamed()) { return false; } JuvenileGroundSnapper.EnsureAttached(val); JuvenileFollowController.EnsureAttached(val); JuvenileFollow.ApplyFollowToggle(val, val2, showMessage); return true; } private static Player ResolveRequestingPlayer(long sender, ZDOID playerId) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) Player player = Player.GetPlayer(sender); if ((Object)(object)player != (Object)null) { return player; } Player val = TameEligibility.ResolvePlayer(playerId); if ((Object)(object)val != (Object)null) { return val; } return Player.m_localPlayer; } } internal sealed class JuvenileGroundSnapper : MonoBehaviour { private Character character; private ZNetView nview; private float nextCheckTime; private void Awake() { character = ((Component)this).GetComponent<Character>(); nview = ((Component)this).GetComponent<ZNetView>(); } private void Start() { TrySnapToGround(force: true); } private void LateUpdate() { if (!(Time.time < nextCheckTime) && !((Object)(object)character == (Object)null) && !((Object)(object)nview == (Object)null) && nview.IsValid() && nview.IsOwner() && JuvenileSpecies.IsEligibleJuvenile(character)) { nextCheckTime = Time.time + 1f; TrySnapToGround(force: false); } } public static void EnsureAttached(Character character) { if (!((Object)(object)character == (Object)null) && JuvenileSpecies.IsEligibleJuvenile(character)) { JuvenileGroundSnapper juvenileGroundSnapper = ((Component)character).GetComponent<JuvenileGroundSnapper>(); if ((Object)(object)juvenileGroundSnapper == (Object)null) { juvenileGroundSnapper = ((Component)character).gameObject.AddComponent<JuvenileGroundSnapper>(); } juvenileGroundSnapper.TrySnapToGround(force: true); } } private void TrySnapToGround(bool force) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_001b: 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_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) if (JuvenilePlacement.TryGetFloorPosition(((Component)this).transform.position, out var grounded)) { float num = ((Component)this).transform.position.y - grounded.y; if (force || !(num < 0.35f)) { JuvenilePlacement.ApplyPosition(character, grounded, ((Component)this).transform.rotation); } } } } internal static class JuvenileInteractHelper { private static readonly int InteractMask = LayerMask.GetMask(new string[10] { "item", "piece", "piece_nonsolid", "Default", "static_solid", "Default_small", "character", "character_net", "terrain", "vehicle" }); public static Character FindJuvenileUnderCrosshair(Player player, float maxDistance = 6f) { return FindTamedCharacterUnderCrosshair(player, maxDistance, juvenilesOnly: true); } public static Character FindTamedCharacterUnderCrosshair(Player player, float maxDistance, bool juvenilesOnly) { //IL_0022: 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_0036: Unknown result type (might be due to invalid IL or missing references) //IL_003d: 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_0089: 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) //IL_0146: Unknown result type (might be due to invalid IL or missing references) //IL_0149: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)player == (Object)null || (Object)(object)GameCamera.instance == (Object)null) { return null; } Vector3 position = ((Component)GameCamera.instance).transform.position; Vector3 forward = ((Component)GameCamera.instance).transform.forward; Vector3 position2 = ((Character)player).m_eye.position; RaycastHit[] source = Physics.RaycastAll(position, forward, 50f, InteractMask); Character result = null; float num = maxDistance; foreach (RaycastHit item in source.OrderBy((RaycastHit h) => ((RaycastHit)(ref h)).distance)) { RaycastHit current = item; if ((Object)(object)((RaycastHit)(ref current)).collider == (Object)null || ((Object)(object)((RaycastHit)(ref current)).collider.attachedRigidbody != (Object)null && (Object)(object)((Component)((RaycastHit)(ref current)).collider.attachedRigidbody).gameObject == (Object)(object)((Component)player).gameObject)) { continue; } Character val = (((Object)(object)((RaycastHit)(ref current)).collider.attachedRigidbody != (Object)null) ? ((Component)((RaycastHit)(ref current)).collider.attachedRigidbody).GetComponent<Character>() : ((Component)((RaycastHit)(ref current)).collider).GetComponentInParent<Character>()); if (!((Object)(object)val == (Object)null) && !val.IsPlayer() && val.IsTamed() && (!juvenilesOnly || JuvenileSpecies.IsEligibleJuvenile(val)) && (juvenilesOnly || !((Object)(object)((Component)val).GetComponent<Tameable>() == (Object)null))) { float num2 = Vector3.Distance(position2, ((RaycastHit)(ref current)).point); if (num2 <= num) { result = val; num = num2; } } } return result; } } internal static class JuvenilePlacement { private static readonly int FloorMask = LayerMask.GetMask(new string[6] { "Default", "static_solid", "piece", "piece_nonsolid", "terrain", "water" }); public static bool TryGetFloorPosition(Vector3 position, out Vector3 grounded) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0016: 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_0036: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: 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_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: Unknown result type (might be due to invalid IL or missing references) //IL_00c7: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: Unknown result type (might be due to invalid IL or missing references) //IL_00eb: Unknown result type (might be due to invalid IL or missing references) grounded = position; if ((Object)(object)ZoneSystem.instance == (Object)null) { return false; } float num = Mathf.Max(position.y + 30f, 128f); Vector3 val = default(Vector3); ((Vector3)(ref val))..ctor(position.x, num, position.z); float solidHeight = default(float); if (!ZoneSystem.instance.GetGroundHeight(val, ref solidHeight)) { solidHeight = ZoneSystem.instance.GetSolidHeight(position); } if (position.y - solidHeight > 2f) { grounded.y = solidHeight + 0.2f; return true; } float num2 = solidHeight + 0.2f; RaycastHit[] array = Physics.RaycastAll(val, Vector3.down, num + 100f, FloorMask); for (int i = 0; i < array.Length; i++) { RaycastHit val2 = array[i]; if (!(((RaycastHit)(ref val2)).point.y > position.y + 1f) && !(((RaycastHit)(ref val2)).point.y < solidHeight - 1f) && ((RaycastHit)(ref val2)).point.y > num2) { num2 = ((RaycastHit)(ref val2)).point.y + 0.15f; } } grounded.y = num2; return true; } public static void ApplyPosition(Character character, Vector3 position, Quaternion rotation) { //IL_0010: 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) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_004f: 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_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0075: 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) if (!((Object)(object)character == (Object)null)) { ((Component)character).transform.position = position; ((Component)character).transform.rotation = rotation; Rigidbody component = ((Component)character).GetComponent<Rigidbody>(); if ((Object)(object)component != (Object)null) { component.linearVelocity = Vector3.zero; component.angularVelocity = Vector3.zero; } character.SetLookDir(rotation * Vector3.forward, 0f); ZNetView nview = character.GetNview(); ZDO val = ((nview != null) ? nview.GetZDO() : null); if (val != null) { val.SetPosition(position); val.SetRotation(rotation); } } } } internal static class JuvenileSpecies { public static bool IsEligibleJuvenile(Character character) { if ((Object)(object)character == (Object)null || character.IsPlayer() || character.IsDead() || !character.IsTamed()) { return false; } if ((Object)(object)((Component)character).GetComponent<Growup>() != (Object)null) { return true; } string name = ((Object)character).name ?? string.Empty; string prefabName = character.GetPrefabName(); if (!MatchesWolfCub(name) && !MatchesWolfCub(prefabName) && !MatchesAsksvinHatchling(name)) { return MatchesAsksvinHatchling(prefabName); } return true; } private static bool MatchesWolfCub(string name) { if (!string.IsNullOrEmpty(name)) { return name.IndexOf("wolfcub", StringComparison.OrdinalIgnoreCase) >= 0; } return false; } private static bool MatchesAsksvinHatchling(string name) { if (string.IsNullOrEmpty(name) || name.IndexOf("asksvin", StringComparison.OrdinalIgnoreCase) < 0) { return false; } return name.IndexOf("hatchling", StringComparison.OrdinalIgnoreCase) >= 0; } } [BepInPlugin("hardwire99.letsgo", "LetsGo", "1.0.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInIncompatibility("org.bepinex.plugins.beasts_of_burden")] public sealed class LetsGoPlugin : BaseUnityPlugin { internal static ManualLogSource Log; private Harmony _harmony; private void Awake() { //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Expected O, but got Unknown Log = ((BaseUnityPlugin)this).Logger; ModConfig.Bind(((BaseUnityPlugin)this).Config); if (!ModConfig.Enabled.Value) { Log.LogInfo((object)"LetsGo 1.0.0 is disabled in config."); return; } _harmony = new Harmony("hardwire99.letsgo"); PatchAllSafe(); Log.LogInfo((object)("LetsGo 1.0.0 loaded (valheim-1.0, dll " + GetDllTimestamp() + ").")); } private void Update() { //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) if (ModConfig.Enabled.Value && !((Object)(object)Player.m_localPlayer == (Object)null) && CanTakeHotkeys() && ModConfig.EnablePackCall.Value) { KeyboardShortcut value = ModConfig.PackCallKey.Value; if (((KeyboardShortcut)(ref value)).IsDown()) { PackCall.TryCallFromLocal(); } } } private void OnDestroy() { Harmony harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } } private void PatchAllSafe() { Type[] types = typeof(LetsGoPlugin).Assembly.GetTypes(); foreach (Type type in types) { try { _harmony.CreateClassProcessor(type).Patch(); } catch (Exception ex) { Log.LogError((object)("Failed to patch " + type.FullName + ": " + ex)); } } } private static string GetDllTimestamp() { string location = Assembly.GetExecutingAssembly().Location; if (!File.Exists(location)) { return "unknown"; } return File.GetLastWriteTime(location).ToString("yyyy-MM-dd HH:mm:ss"); } private static bool CanTakeHotkeys() { Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null || ((Character)localPlayer).IsDead() || ((Character)localPlayer).InCutscene() || ((Character)localPlayer).IsTeleporting()) { return false; } if (Console.IsVisible() || TextInput.IsVisible() || InventoryGui.IsVisible() || Minimap.IsOpen() || StoreGui.IsVisible() || Menu.IsVisible() || GameCamera.InFreeFly() || PlayerCustomizaton.IsBarberGuiVisible()) { return false; } if ((Object)(object)TextViewer.instance != (Object)null && TextViewer.instance.IsVisible()) { return false; } if ((Object)(object)Chat.instance != (Object)null && Chat.instance.HasFocus()) { return false; } return !IsTextFieldFocused(); } private static bool IsTextFieldFocused() { EventSystem current = EventSystem.current; if ((Object)(object)current == (Object)null) { return false; } GameObject currentSelectedGameObject = current.currentSelectedGameObject; if ((Object)(object)currentSelectedGameObject == (Object)null) { return false; } Transform val = currentSelectedGameObject.transform; while ((Object)(object)val != (Object)null) { Component[] components = ((Component)val).GetComponents<Component>(); foreach (Component val2 in components) { if (!((Object)(object)val2 == (Object)null)) { string name = ((object)val2).GetType().Name; if (name == "InputField" || name == "TMP_InputField") { return true; } } } val = val.parent; } return false; } } internal static class LetsGoRpc { private const string RpcOrder = "hw_letsgo_order"; private const string RpcExecuteOrder = "hw_letsgo_order_exec"; private const string RpcPackCall = "hw_letsgo_pack"; private const string RpcExecutePackCall = "hw_letsgo_pack_exec"; public static void Register() { ZRoutedRpc.instance.Register<ZDOID, ZDOID, int>("hw_letsgo_order", (Action<long, ZDOID, ZDOID, int>)OnOrder); ZRoutedRpc.instance.Register<ZDOID, ZDOID, int>("hw_letsgo_order_exec", (Action<long, ZDOID, ZDOID, int>)OnExecuteOrder); ZRoutedRpc.instance.Register<ZDOID>("hw_letsgo_pack", (Action<long, ZDOID>)OnPackCall); ZRoutedRpc.instance.Register<ZDOID>("hw_letsgo_pack_exec", (Action<long, ZDOID>)OnExecutePackCall); JuvenileFollowRpc.Register(); } public static void RequestCycleOrder(Character character, Player player) { RequestOrder(character, player, 0, delegate { FollowCommands.CycleOrder(character, player, showMessage: true); }); } public static void RequestFollow(Character character, Player player) { RequestOrder(character, player, 1, delegate { FollowCommands.ApplyOrder(character, player, TameOrder.Follow, showMessage: true); }); } public static void RequestPackCall(Player player) { //IL_004a: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)player == (Object)null)) { if ((Object)(object)Player.m_localPlayer == (Object)(object)player || ((Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsServer())) { PackCall.Apply(player); return; } ZRoutedRpc.instance.InvokeRoutedRPC("hw_letsgo_pack", new object[1] { ((Character)player).GetZDOID() }); } } private static void RequestOrder(Character character, Player player, int mode, Action local) { //IL_0056: 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) ZDO val = character?.GetZdo(); if (val != null && !((Object)(object)player == (Object)null)) { if (LocalAuthority.HasLoaded(character)) { local(); } else if (!((Object)(object)ZNet.instance != (Object)null) || !ZNet.instance.IsServer()) { ZRoutedRpc.instance.InvokeRoutedRPC("hw_letsgo_order", new object[3] { val.m_uid, ((Character)player).GetZDOID(), mode }); } } } private static void OnOrder(long sender, ZDOID creatureId, ZDOID playerId, int mode) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //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_0035: Unknown result type (might be due to invalid IL or missing references) if (ZNet.instance.IsServer() && !TryApplyOrder(creatureId, playerId, sender, mode)) { ZRoutedRpc.instance.InvokeRoutedRPC(sender, "hw_letsgo_order_exec", new object[3] { creatureId, playerId, mode }); } } private static void OnExecuteOrder(long sender, ZDOID creatureId, ZDOID playerId, int mode) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0001: Unknown result type (might be due to invalid IL or missing references) TryApplyOrder(creatureId, playerId, sender, mode); } private static void OnPackCall(long sender, ZDOID playerId) { //IL_000d: 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) if (ZNet.instance.IsServer() && !TryApplyPackCall(playerId)) { ZRoutedRpc.instance.InvokeRoutedRPC(sender, "hw_letsgo_pack_exec", new object[1] { playerId }); } } private static void OnExecutePackCall(long sender, ZDOID playerId) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) TryApplyPackCall(playerId); } private static bool TryApplyOrder(ZDOID creatureId, ZDOID playerId, long sender, int mode) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) Character val = TameEligibility.ResolveCharacter(creatureId); Player val2 = TameEligibility.ResolvePlayer(playerId) ?? Player.GetPlayer(sender) ?? Player.m_localPlayer; if ((Object)(object)val == (Object)null || (Object)(object)val2 == (Object)null) { return false; } if (mode == 1) { FollowCommands.ApplyOrder(val, val2, TameOrder.Follow, showMessage: true); } else { FollowCommands.CycleOrder(val, val2, showMessage: true); } return true; } private static bool TryApplyPackCall(ZDOID playerId) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) Player val = TameEligibility.ResolvePlayer(playerId) ?? Player.m_localPlayer; if ((Object)(object)val == (Object)null) { return false; } PackCall.Apply(val); return true; } } internal static class LocalAuthority { public static bool HasLoaded(Character character) { ZNetView val = character?.GetNview(); if ((Object)(object)val != (Object)null) { return val.IsValid(); } return false; } public static bool TryClaim(Character character) { ZNetView val = character?.GetNview(); if ((Object)(object)val == (Object)null || !val.IsValid()) { return false; } if (!val.IsOwner()) { val.ClaimOwnership(); } return val.IsOwner(); } public static bool IsOwner(Character character) { ZNetView val = character?.GetNview(); if ((Object)(object)val != (Object)null && val.IsValid()) { return val.IsOwner(); } return false; } } internal static class ModConfig { internal static ConfigEntry<bool> Enabled; internal static ConfigEntry<bool> DebugLogging; internal static ConfigEntry<bool> EnableFollow; internal static ConfigEntry<bool> EnableCarts; internal static ConfigEntry<bool> EnablePackCall; internal static ConfigEntry<bool> EnablePortalFollow; internal static ConfigEntry<string> ExcludePrefabs; internal static ConfigEntry<float> FollowDistanceFactor; internal static ConfigEntry<float> MediumFollowDistance; internal static ConfigEntry<float> CartMinRadius; internal static ConfigEntry<float> CartHitchBackPadding; internal static ConfigEntry<bool> CartIgnorePullerCollision; internal static ConfigEntry<float> CartDetachDistanceFactor; internal static ConfigEntry<float> CartDetachDistancePlayer; internal static ConfigEntry<float> CartPullScalePerRadius; internal static ConfigEntry<float> PackCallRadius; internal static ConfigEntry<int> PackCallMax; internal static ConfigEntry<bool> PackCallIgnorePenned; internal static ConfigEntry<float> PackCallPenCheckDistance; internal static ConfigEntry<int> PackCallPenHitMin; internal static ConfigEntry<float> PortalFollowRadius; internal static ConfigEntry<bool> SkipCommandableIfServersideQoL; internal static ConfigEntry<bool> SkipRecallIfServersideQoL; internal static ConfigEntry<bool> SkipPortalFollowIfTeleportEverything; internal static ConfigEntry<KeyboardShortcut> PackCallKey; internal static void Bind(ConfigFile config) { //IL_0257: Unknown result type (might be due to invalid IL or missing references) Enabled = config.Bind<bool>("General", "Enabled", true, "Master switch. When false, no patches run."); DebugLogging = config.Bind<bool>("General", "DebugLogging", false, "Extra BepInEx logs."); EnableFollow = config.Bind<bool>("General", "EnableFollow", true, "Follow / Stay on tamed creatures, including young."); EnableCarts = config.Bind<bool>("General", "EnableCarts", true, "Hitch vanilla carts to adult boar-sized or larger tames."); EnablePackCall = config.Bind<bool>("General", "EnablePackCall", true, "Hotkey to call nearby tames that are not inside a pen."); EnablePortalFollow = config.Bind<bool>("General", "EnablePortalFollow", true, "Following tames travel vanilla portals with you."); ExcludePrefabs = config.Bind<string>("General", "ExcludePrefabs", "", "Comma-separated prefab names that never receive orders (for problem AllTameable bosses)."); FollowDistanceFactor = config.Bind<float>("Follow", "FollowDistanceFactor", 3f, "Follow stop distance = max(MediumFollowDistance, radius * this). Larger beasts stay farther back."); MediumFollowDistance = config.Bind<float>("Follow", "MediumFollowDistance", 3f, "Minimum follow stop distance for small/medium tames."); CartMinRadius = config.Bind<float>("Carts", "MinRadius", 0.45f, "Smallest adult tame radius that can hitch a cart. Adult boar is the floor; hens and young never pull."); CartHitchBackPadding = config.Bind<float>("Carts", "HitchBackPadding", 1.25f, "Extra meters behind the animal's rear so the vanilla cart is not under a lox, moose, or Asksvin."); CartIgnorePullerCollision = config.Bind<bool>("Carts", "IgnorePullerCollision", true, "Ignore physics between the cart and the animal pulling it so turns and body clips do not damage the cart."); CartDetachDistanceFactor = config.Bind<float>("Carts", "DetachDistanceFactor", 3.5f, "Detach distance is animal radius times this factor."); CartDetachDistancePlayer = config.Bind<float>("Carts", "DetachDistancePlayer", 2f, "How far the player can be from the cart while pulling."); CartPullScalePerRadius = config.Bind<float>("Carts", "PullScalePerRadius", 2f, "Joint break force multiplier is max(1, radius * this). Larger adults haul more weight."); PackCallRadius = config.Bind<float>("PackCall", "Radius", 50f, "How far the pack call reaches."); PackCallMax = config.Bind<int>("PackCall", "MaxTames", 10, "Maximum tames one call can take (1-50)."); PackCallIgnorePenned = config.Bind<bool>("PackCall", "IgnorePenned", true, "If true, skip tames enclosed by player-built structures (fences, walls, barns). Stay in the open still answers."); PackCallPenCheckDistance = config.Bind<float>("PackCall", "PenCheckDistance", 6f, "How far to look for player-built structures when deciding if a tame is penned."); PackCallPenHitMin = config.Bind<int>("PackCall", "PenHitMin", 5, "A tame is penned when this many of 8 directions hit a player-built structure (1-8)."); PackCallKey = config.Bind<KeyboardShortcut>("Controls", "PackCallKey", new KeyboardShortcut((KeyCode)116, Array.Empty<KeyCode>()), "Call nearby eligible tames to Follow."); PortalFollowRadius = config.Bind<float>("Portal", "FollowRadius", 12f, "Following tames within this radius of the source portal come with you."); SkipCommandableIfServersideQoL = config.Bind<bool>("Compatibility", "SkipCommandableIfServersideQoL", true, "If ServersideQoL is loaded, do not also force m_commandable."); SkipRecallIfServersideQoL = config.Bind<bool>("Compatibility", "SkipRecallIfServersideQoL", true, "If ServersideQoL is loaded, skip portal-follow (its TeleportFollow already warps distant followers)."); SkipPortalFollowIfTeleportEverything = config.Bind<bool>("Compatibility", "SkipPortalFollowIfTeleportEverything", true, "If TeleportEverything is loaded, skip our portal-follow to avoid double-teleport."); } internal static void Log(string message) { if (DebugLogging.Value) { LetsGoPlugin.Log.LogInfo((object)message); } } } internal static class ModConstants { public const string ModGuid = "hardwire99.letsgo"; public const string ModName = "LetsGo"; public const string ModVersion = "1.0.0"; public const string BuildLabel = "valheim-1.0"; public const string OffspringPortalGuid = "offspringportal.mod"; public const string BeastsOfBurdenGuid = "org.bepinex.plugins.beasts_of_burden"; public const string ServersideQoLGuid = "argusmagnus.ServersideQoL"; public const string ServersideQoLGuidAlt = "ArgusMagnus.ServersideQoL"; public const string TeleportEverythingGuid = "com.kpro.TeleportEverything"; } internal static class PackCall { public static void TryCallFromLocal() { if (ModConfig.EnablePackCall.Value) { Player localPlayer = Player.m_localPlayer; if (!((Object)(object)localPlayer == (Object)null)) { Apply(localPlayer); } } } public static void Apply(Player player) { //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)player == (Object)null || !ModConfig.EnablePackCall.Value) { return; } int num = Mathf.Clamp(ModConfig.PackCallMax.Value, 1, 50); float value = ModConfig.PackCallRadius.Value; int num2 = 0; foreach (Character allCharacter in Character.GetAllCharacters()) { if (num2 >= num) { break; } if (TameEligibility.IsEligible(allCharacter) && !(Vector3.Distance(((Component)player).transform.position, ((Component)allCharacter).transform.position) > value) && !FollowCommands.IsFollowingAnyoneElse(allCharacter, player) && (!ModConfig.PackCallIgnorePenned.Value || !PenDetector.IsPenned(allCharacter))) { FollowCommands.ApplyOrder(allCharacter, player, TameOrder.Follow, showMessage: false); num2++; } } ((Character)player).Message((MessageType)2, (num2 == 0) ? "No tames answered." : ("Follow " + num2), 0, (Sprite)null, false); } } internal static class PenDetector { private static readonly Vector3[] Directions; private static readonly int StructureMask; public static bool IsPenned(Character character) { //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_005c: 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_0074: Unknown result type (might be due to invalid IL or missing references) //IL_0076: 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_0088: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)character == (Object)null) { return false; } float num = Mathf.Max(1f, ModConfig.PackCallPenCheckDistance.Value); int num2 = Mathf.Clamp(ModConfig.PackCallPenHitMin.Value, 1, 8); Vector3 val = ((Component)character).transform.position + Vector3.up * Mathf.Max(0.6f, character.GetRadius()); int num3 = 0; Vector3[] directions = Directions; RaycastHit hit = default(RaycastHit); foreach (Vector3 val2 in directions) { if (Physics.Raycast(val, val2, ref hit, num, StructureMask) && IsPlayerBuiltStructure(hit)) { num3++; } } bool flag = num3 >= num2; if (flag) { ModConfig.Log(character.GetHoverName() + " penned (" + num3 + "/" + Directions.Length + " player-built hits)."); } return flag; } private static bool IsPlayerBuiltStructure(RaycastHit hit) { if ((Object)(object)((RaycastHit)(ref hit)).collider == (Object)null) { return false; } if ((Object)(object)((Component)((RaycastHit)(ref hit)).collider).GetComponentInParent<Character>() != (Object)null) { return false; } Piece componentInParent = ((Component)((RaycastHit)(ref hit)).collider).GetComponentInParent<Piece>(); if ((Object)(object)componentInParent != (Object)null) { return componentInParent.GetCreator() != 0; } return false; } static PenDetector() { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //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_002c: 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_0038: Unknown result type (might be due to invalid IL or missing references) //IL_003d: 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_0047: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0060: 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_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006d: 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_0079: 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_0083: 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_008b: Unknown result type (might be due to invalid IL or missing references) //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_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: 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) Vector3[] obj = new Vector3[8] { Vector3.forward, Vector3.back, Vector3.left, Vector3.right, default(Vector3), default(Vector3), default(Vector3), default(Vector3) }; Vector3 val = Vector3.forward + Vector3.left; obj[4] = ((Vector3)(ref val)).normalized; val = Vector3.forward + Vector3.right; obj[5] = ((Vector3)(ref val)).normalized; val = Vector3.back + Vector3.left; obj[6] = ((Vector3)(ref val)).normalized; val = Vector3.back + Vector3.right; obj[7] = ((Vector3)(ref val)).normalized; Directions = (Vector3[])(object)obj; StructureMask = LayerMask.GetMask(new string[5] { "piece", "piece_nonsolid", "Default", "static_solid", "Default_small" }); } } internal static class PortalFollow { private static readonly Dictionary<long, List<ZDOID>> Pending = new Dictionary<long, List<ZDOID>>(); public static void CaptureFollowers(Player player, Vector3 from) { //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_0083: 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) if (!ModConfig.EnablePortalFollow.Value || CompatPlugins.SkipOurPortalFollow || (Object)(object)player == (Object)null || ((Object)(object)Player.m_localPlayer != (Object)null && (Object)(object)player != (Object)(object)Player.m_localPlayer)) { return; } List<ZDOID> list = new List<ZDOID>(); foreach (Character allCharacter in Character.GetAllCharacters()) { if (!TameEligibility.IsEligible(allCharacter) || !FollowCommands.IsFollowing(allCharacter, player)) { continue; } float num = ModConfig.PortalFollowRadius.Value + FollowCommands.GetFollowStopDistance(allCharacter) + 4f; if (!(Vector3.Distance(from, ((Component)allCharacter).transform.position) > num)) { CartAttachment.DetachFrom(allCharacter); ZDO zdo = allCharacter.GetZdo(); if (zdo != null) { list.Add(zdo.m_uid); } } } if (list.Count != 0) { Pending[player.GetPlayerID()] = list; LetsGoPlugin.Log.LogInfo((object)("Portal-follow captured " + list.Count + " tames for " + player.GetPlayerName())); } } public static void WarpPending(Player player, Vector3 dest, Quaternion rot) { //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_005c: 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_0070: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_0089: 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) //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)player == (Object)null || CompatPlugins.SkipOurPortalFollow) { if ((Object)(object)player != (Object)null) { Pending.Remove(player.GetPlayerID()); } } else { if (!Pending.TryGetValue(player.GetPlayerID(), out var value)) { return; } Pending.Remove(player.GetPlayerID()); Vector3 val = rot * Vector3.back; int num = 0; foreach (ZDOID item in value) { Vector3 position = dest + val * (2f + (float)num * 1.2f) + Vector3.up; PlaceAt(item, position, rot); num++; } } } private static void PlaceAt(ZDOID id, Vector3 position, Quaternion rotation) { //IL_0000: 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_003c: 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) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) Character val = TameEligibility.ResolveCharacter(id); if ((Object)(object)val != (Object)null) { ZNetView nview = val.GetNview(); if ((Object)(object)nview != (Object)null && nview.IsValid() && !nview.IsOwner()) { nview.ClaimOwnership(); } ((Component)val).transform.position = position; ((Component)val).transform.rotation = rotation; ZDO zdo = val.GetZdo(); if (zdo != null) { zdo.SetPosition(position); } ZDO zdo2 = val.GetZdo(); if (zdo2 != null) { zdo2.SetRotation(rotation); } } else { ZDOMan instance = ZDOMan.instance; ZDO val2 = ((instance != null) ? instance.GetZDO(id) : null); if (val2 != null && val2.IsValid()) { val2.SetPosition(position); val2.SetRotation(rotation); } } } } internal static class TameEligibility { public static bool IsEligible(Character character) { if ((Object)(object)character == (Object)null || character.IsPlayer() || character.IsDead()) { return false; } if (!character.IsTamed()) { return false; } if ((Object)(object)((Component)character).GetComponent<Tameable>() == (Object)null && !JuvenileSpecies.IsEligibleJuvenile(character)) { return false; } if (IsExcluded(character)) { return false; } if (!((Object)(object)((Component)character).GetComponent<MonsterAI>() != (Object)null)) { return (Object)(object)((Component)character).GetComponent<AnimalAI>() != (Object)null; } return true; } public static bool NeedsCrosshairAssist(Character character) { if (!IsEligible(character)) { return false; } if ((Object)(object)((Component)character).GetComponent<Growup>() != (Object)null || (Object)(object)((Component)character).GetComponent<AnimalAI>() != (Object)null) { return true; } return IsWolfCubByName(character); } public static bool IsWolfCubByName(Character character) { string prefabName = character.GetPrefabName(); if (!string.IsNullOrEmpty(prefabName)) { return prefabName.IndexOf("wolfcub", StringComparison.OrdinalIgnoreCase) >= 0; } return false; } public static bool IsExcluded(Character character) { string prefabName = character.GetPrefabName(); if (string.IsNullOrEmpty(prefabName)) { return false; } string text = ModConfig.ExcludePrefabs?.Value; if (string.IsNullOrWhiteSpace(text)) { return false; } string[] array = text.Split(new char[2] { ',', ';' }, StringSplitOptions.RemoveEmptyEntries); foreach (string text2 in array) { if (prefabName.Equals(text2.Trim(), StringComparison.OrdinalIgnoreCase)) { return true; } } return false; } public static Player ResolvePlayer(ZDOID playerId) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //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) if (playerId == ZDOID.None) { return null; } ZNetScene instance = ZNetScene.instance; GameObject val = ((instance != null) ? instance.FindInstance(playerId) : null); Player val2 = (((Object)(object)val != (Object)null) ? val.GetComponent<Player>() : null); if ((Object)(object)val2 != (Object)null) { return val2; } foreach (Player allPlayer in Player.GetAllPlayers()) { ZDO zdo = ((Character)(object)allPlayer).GetZdo(); if (zdo != null && zdo.m_uid == playerId) { return allPlayer; } } return null; } public static Character ResolveCharacter(ZDOID id) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) ZNetScene instance = ZNetScene.instance; GameObject val = ((instance != null) ? instance.FindInstance(id) : null); if (!((Object)(object)val != (Object)null)) { return null; } return val.GetComponent<Character>(); } } internal enum TameOrder { Stay, Follow } internal static class TameInteractHelper { private static readonly int InteractMask = LayerMask.GetMask(new string[10] { "item", "piece", "piece_nonsolid", "Default", "static_solid", "Default_small", "character", "character_net", "terrain", "vehicle" }); public static Character FindAssistTarget(Player player, float maxDistance = 6f) { return FindEligibleUnderCrosshair(player, maxDistance, assistOnly: true); } public static Character FindEligibleUnderCrosshair(Player player, float maxDistance, bool assistOnly) { //IL_0022: 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_0036: Unknown result type (might be due to invalid IL or missing references) //IL_003d: 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_0089: 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) //IL_0131: Unknown result type (might be due to invalid IL or missing references) //IL_0134: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)player == (Object)null || (Object)(object)GameCamera.instance == (Object)null) { return null; } Vector3 position = ((Component)GameCamera.instance).transform.position; Vector3 forward = ((Component)GameCamera.instance).transform.forward; Vector3 position2 = ((Character)player).m_eye.position; RaycastHit[] source = Physics.RaycastAll(position, forward, 50f, InteractMask); Character result = null; float num = maxDistance; foreach (RaycastHit item in source.OrderBy((RaycastHit h) => ((RaycastHit)(ref h)).distance)) { RaycastHit current = item; if ((Object)(object)((RaycastHit)(ref current)).collider == (Object)null || ((Object)(object)((RaycastHit)(ref current)).collider.attachedRigidbody != (Object)null && (Object)(object)((Component)((RaycastHit)(ref current)).collider.attachedRigidbody).gameObject == (Object)(object)((Component)player).gameObject)) { continue; } Character val = (((Object)(object)((RaycastHit)(ref current)).collider.attachedRigidbody != (Object)null) ? ((Component)((RaycastHit)(ref current)).collider.attachedRigidbody).GetComponent<Character>() : ((Component)((RaycastHit)(ref current)).collider).GetComponentInParent<Character>()); if (!((Object)(object)val == (Object)null) && !val.IsPlayer() && TameEligibility.IsEligible(val) && (!assistOnly || TameEligibility.NeedsCrosshairAssist(val))) { float num2 = Vector3.Distance(position2, ((RaycastHit)(ref current)).point); if (num2 <= num) { result = val; num = num2; } } } return result; } public static bool TryHandle(Player player, Character character, bool hold, bool alt) { if (JuvenileSpecies.IsEligibleJuvenile(character)) { return false; } if (!ModConfig.Enabled.Value || hold || (Object)(object)player == (Object)null || !TameEligibility.IsEligible(character)) { return false; } Tameable component = ((Component)character).GetComponent<Tameable>(); FollowCommands.LastHovered = character; AnimalFollowController.EnsureAttached(character); JuvenileFollowController.EnsureAttached(character); if (alt || ZInput.GetButton("AltPlace") || Input.GetKey((KeyCode)304) || Input.GetKey((KeyCode)303)) { if ((Object)(object)component != (Object)null) { component.m_commandable = false; } return false; } if (!ModConfig.EnableFollow.Value) { return false; } if ((Object)(object)component != (Object)null && !CompatPlugins.SkipOurCommandable) { component.m_commandable = true; } LetsGoRpc.RequestCycleOrder(character, player); return true; } } internal static class ValheimExtensions { public static ZNetView GetNview(this Character character) { if (!((Object)(object)character != (Object)null)) { return null; } return ((Component)character).GetComponent<ZNetView>(); } public static ZDO GetZdo(this Character character) { ZNetView nview = character.GetNview(); if (!((Object)(object)nview != (Object)null) || !nview.IsValid()) { return null; } return nview.GetZDO(); } public static string GetPrefabName(this Character character) { if ((Object)(object)character == (Object)null) { return string.Empty; } return Utils.GetPrefabName(((Object)((Component)character).gameObject).name); } } internal static class ZdoFields { public const string Order = "hw_letsgo_order"; public const string FollowTarget = "hw_letsgo_follow"; } } namespace LetsGo.Patches { [HarmonyPatch(typeof(Game), "Start")] internal static class GameStartPatch { private static void Postfix() { LetsGoRpc.Register(); } } [HarmonyPatch(typeof(Tameable), "Interact")] [HarmonyPriority(800)] internal static class TameableInteractPatch { private static bool Prefix(Tameable __instance, Humanoid user, bool hold, bool alt, ref bool __result) { Character component = ((Component)__instance).GetComponent<Character>(); if (JuvenileSpecies.IsEligibleJuvenile(component) && component.IsTamed()) { if (!hold && ModConfig.EnableFollow.Value) { __instance.m_commandable = true; } return true; } if (!TameInteractHelper.TryHandle((Player)(object)((user is Player) ? user : null), component, hold, alt)) { return true; } __result = true; return false; } } [HarmonyPatch(typeof(Tameable), "GetHoverText")] internal static class TameableHoverPatch { private static void Postfix(Tameable __instance, ref string __result) { Character component = ((Component)__instance).GetComponent<Character>(); if (JuvenileSpecies.IsEligibleJuvenile(component)) { JuvenileFollowDisplay.ApplyFollowHover(component, ref __result); } else { AppendFollowHover(component, ref __result); } } internal static void AppendFollowHover(Character character, ref string __result) { if (ModConfig.Enabled.Value && ModConfig.EnableFollow.Value && TameEligibility.IsEligible(character)) { FollowCommands.LastHovered = character; if (string.IsNullOrEmpty(__result)) { __result = character.GetHoverName(); } string text = ((FollowCommands.GetOrder(character) == TameOrder.Follow) ? "$hud_tamestay" : "$hud_tamefollow"); string text2 = Localization.instance.Localize("$hud_pet"); string text3 = Localization.instance.Localize(text); if (!string.IsNullOrEmpty(__result) && __result.Contains(text2)) { __result = __result.Replace(text2, text3); } else if (string.IsNullOrEmpty(__result) || !__result.Contains(text3)) { __result += Localization.instance.Localize("\n[<color=yellow><b>$KEY_Use</b></color>] " + text); } } } } [HarmonyPatch(typeof(AnimalAI), "UpdateAI")] internal static class AnimalAIFollowPatch { private static bool Prefix(AnimalAI __instance, float dt, ref bool __result) { if (JuvenileFollowController.TryApplyAnimalFollow(__instance, dt) || AnimalFollowController.TryApply(__instance, dt)) { __result = true; return false; } return true; } } [HarmonyPatch(typeof(BaseAI), "Follow")] internal static class BaseAIFollowPatch { private static bool Prefix(BaseAI __instance, GameObject go, float dt) { //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) if (!ModConfig.Enabled.Value || !ModConfig.EnableFollow.Value) { return true; } Character character = BaseAIAccess.GetCharacter(__instance); if ((Object)(object)character == (Object)null || (!TameEligibility.IsEligible(character) && !JuvenileSpecies.IsEligibleJuvenile(character))) { return true; } if ((Object)(object)go == (Object)null || (Object)(object)go.GetComponent<Player>() == (Object)null) { return true; } float num = Vector3.Distance(go.transform.position, ((Component)__instance).transform.position); float followStopDistance = FollowCommands.GetFollowStopDistance(character); bool run = num > followStopDistance * 3f; if (num < followStopDistance) { __instance.StopMoving(); } else { BaseAIAccess.MoveTo(__instance, dt, go.transform.position, 0f, run); } return false; } } [HarmonyPatch(typeof(Player), "FindHoverObject")] [HarmonyPriority(900)] internal static class PlayerFindHoverObjectPatch { private static void Postfix(Player __instance, ref GameObject hover, ref Character hoverCreature) { if (!ModConfig.Enabled.Value || !ModConfig.EnableFollow.Value) { return; } Character val = JuvenileInteractHelper.FindJuvenileUnderCrosshair(__instance, __instance.m_maxInteractDistance); if ((Object)(object)val != (Object)null) { hover = ((Component)val).gameObject; hoverCreature = val; FollowCommands.LastHovered = val; return; } Character val2 = TameInteractHelper.FindAssistTarget(__instance, __instance.m_maxInteractDistance); if (!((Object)(object)val2 == (Object)null)) { hover = ((Component)val2).gameObject; hoverCreature = val2; FollowCommands.LastHovered = val2; } } } [HarmonyPatch(typeof(Player), "Interact")] [HarmonyPriority(900)] internal static class PlayerTameInteractPatch { private static bool Prefix(Player __instance, GameObject go, bool hold, bool alt) { if (!ModConfig.Enabled.Value || hold) { return true; } if (!alt) { Character val = JuvenileInteractHelper.FindJuvenileUnderCrosshair(__instance) ?? __instance.GetHoverCreature(); if ((Object)(object)val != (Object)null && val.IsTamed() && JuvenileSpecies.IsEligibleJuvenile(val) && ModConfig.EnableFollow.Value) { JuvenileGroundSnapper.EnsureAttached(val); JuvenileFollowController.EnsureAttached(val); if (JuvenileFollow.TryCommand(val, __instance, showMessage: true)) { return false; } } } Character val2 = TameInteractHelper.FindAssistTarget(__instance) ?? __instance.GetHoverCreature(); if ((Object)(object)val2 == (Object)null || JuvenileSpecies.IsEligibleJuvenile(val2) || !TameEligibility.NeedsCrosshairAssist(val2)) { return true; } return !TameInteractHelper.TryHandle(__instance, val2, hold, alt); } } [HarmonyPatch(typeof(Character), "GetHoverText")] internal static class CharacterTameHoverPatch { private static void Postfix(Character __instance, ref string __result) { JuvenileFollowDisplay.ApplyFollowHover(__instance, ref __result); if (ModConfig.Enabled.Value && TameEligibility.NeedsCrosshairAssist(__instance) && !JuvenileSpecies.IsEligibleJuvenile(__instance) && (!((Object)(object)((Component)__instance).GetComponent<Tameable>() != (Object)null) || string.IsNullOrEmpty(__result) || !__result.Contains("$KEY_Use"))) { string __result2 = string.Empty; TameableHoverPatch.AppendFollowHover(__instance, ref __result2); if (!string.IsNullOrEmpty(__result2)) { __result = (string.IsNullOrEmpty(__result) ? __result2 : (__result + __result2)); } } } } [HarmonyPatch(typeof(Character), "Awake")] internal static class CharacterAwakePatch { private static void Postfix(Character __instance) { JuvenileGroundSnapper.EnsureAttached(__instance); JuvenileFollowController.EnsureAttached(__instance); if (TameEligibility.IsEligible(__instance)) { AnimalFollowController.EnsureAttached(__instance); } } } [HarmonyPatch(typeof(TeleportWorld), "Teleport")] internal static class TeleportWorldPatch { private static void Prefix(TeleportWorld __instance, Player player) { //IL_0038: Unknown result type (might be due to invalid IL or missing references) if (ModConfig.Enabled.Value && !((Object)(object)player == (Object)null) && (!((Object)(object)Player.m_localPlayer != (Object)null) || !((Object)(object)player != (Object)(object)Player.m_localPlayer))) { PortalFollow.CaptureFollowers(player, ((Component)player).transform.position); } } } [HarmonyPatch(typeof(Player), "TeleportTo")] internal static class PlayerTeleportToPatch { private static void Postfix(Player __instance, Vector3 pos, Quaternion rot, bool distantTeleport, bool __result) { //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_004a: 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) if (ModConfig.Enabled.Value && __result && distantTeleport && !((Object)(object)__instance == (Object)null) && (!((Object)(object)Player.m_localPlayer != (Object)null) || !((Object)(object)__instance != (Object)(object)Player.m_localPlayer))) { PortalFollow.CaptureFollowers(__instance, ((Component)__instance).transform.position); PortalFollow.WarpPending(__instance, pos, rot); } } } [HarmonyPatch(typeof(Vagon), "Detach")] internal static class VagonDetachPatch { private static void Prefix(Vagon __instance, out Character __state) { __state = CartAttachment.GetAttached(__instance); } private static void Postfix(Vagon __instance, Character __state) { CartAttachment.SetPullerCollision(__instance, __state, ignore: false); } } [HarmonyPatch(typeof(Vagon), "LateUpdate")] internal static class VagonLateUpdatePatch { private static void Prefix(Vagon __instance) { if (ModConfig.Enabled.Value && ModConfig.EnableCarts.Value) { ConfigurableJoint val = VagonAccess.GetJoin(__instance); if ((Object)(object)val != (Object)null && (Object)(object)((Joint)val).connectedBody == (Object)null) { VagonAccess.Detach(__instance); } } } } [HarmonyPatch(typeof(Vagon), "InUse")] internal static class VagonInUsePatch { private static bool Prefix(Vagon __instance, ref bool __result) { if (!ModConfig.Enabled.Value || !ModConfig.EnableCarts.Value) { return true; } if ((Object)(object)__instance.m_container != (Object)null && __instance.m_container.IsInUse()) { __result = true; return false; } if (__instance.IsAttached()) { Character attached = CartAttachment.GetAttached(__instance); __result = (Object)(object)attached != (Object)null && attached.IsPlayer(); return false; } __result = false; return false; } } [HarmonyPatch(typeof(Vagon), "Update")] internal static class VagonUpdatePatch { private static bool Prefix(Vagon __instance) { if (!ModConfig.Enabled.Value || !ModConfig.EnableCarts.Value) { return true; } ZNetView nview = VagonAccess.GetNview(__instance); if ((Object)(object)nview == (Object)null || !nview.IsValid()) { return false; } VagonAccess.UpdateAudio(__instance, Time.deltaTime); if (!nview.IsOwner()) { if (__instance.IsAttached()) { VagonAccess.Detach(__instance); } VagonAccess.UpdateSnow(__instance); return false; } Player useRequester = VagonAccess.GetUseRequester(__instance); if ((Object)(object)useRequester != (Object)null) { if (__instance.IsAttached()) { VagonAccess.Detach(__instance); } else { Character val = CartAttachment.FindClosestAttachable(__instance); if ((Object)(object)val != (Object)null) { CartAttachment.Attach(val, __instance); } else if (VagonAccess.CanAttach(__instance, ((Component)useRequester).gameObject)) { CartAttachment.Attach((Character)(object)useRequester, __instance); } else { ((Character)useRequester).Message((MessageType)2, "$msg_cart_incorrectposition", 0, (Sprite)null, false); } } VagonAccess.SetUseRequester(__instance, null); } if (__instance.IsAttached()) { Character attached = CartAttachment.GetAttached(__instance); __instance.m_detachDistance = CartAttachment.GetDetachDistance(attached); ConfigurableJoint val2 = VagonAccess.GetJoin(__instance); GameObject val3 = (((Object)(object)val2 != (Object)null && (Object)(object)((Joint)val2).connectedBody != (Object)null) ? ((Component)((Joint)val2).connectedBody).gameObject : null); if ((Object)(object)val3 == (Object)null || !VagonAccess.CanAttach(__instance, val3)) { VagonAccess.Detach(__instance); } } VagonAccess.UpdateSnow(__instance); return false; } } }