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 Follower Commands v1.0.1
FollowerAdvance.dll
Decompiled a day agousing System; using System.Reflection; using System.Runtime.CompilerServices; using BepInEx; using BepInEx.Configuration; using HarmonyLib; using UnityEngine; [assembly: AssemblyFileVersion("1.0.1.0")] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: AssemblyVersion("1.0.1.0")] namespace Fai.FollowerCommands; [BepInPlugin("fai.FollowerAdvance", "Follower Advance", "1.0.1")] [BepInDependency(/*Could not decode attribute arguments.*/)] public sealed class FollowerAdvancePlugin : BaseUnityPlugin { public const string PluginGuid = "fai.FollowerAdvance"; private static FollowerAdvancePlugin instance; private ConfigEntry<KeyboardShortcut> advanceKey; private Harmony harmony; private static readonly MethodInfo MoveMethod = typeof(BaseAI).GetMethod("MoveTowards", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[2] { typeof(Vector3), typeof(bool) }, null); private static readonly MethodInfo WakeMethod = typeof(MonsterAI).GetMethod("Wakeup", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); private void Awake() { //IL_0023: 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_0072: Expected O, but got Unknown instance = this; CommandState.Reset(); advanceKey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("General", "AdvanceKey", new KeyboardShortcut((KeyCode)103, Array.Empty<KeyCode>()), "Advance tamed creatures following you for 3 seconds."); if (MoveMethod == null || WakeMethod == null) { throw new MissingMethodException("Valheim advance movement API was not found."); } harmony = new Harmony("fai.followercommands.advance"); harmony.PatchAll(typeof(FollowerAdvancePlugin).Assembly); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Follower Advance 1.0.1 loaded (G or LT+X; 3 seconds)."); } private void OnDestroy() { CommandState.Reset(); if (harmony != null) { harmony.UnpatchSelf(); } if ((Object)(object)instance == (Object)(object)this) { instance = null; } } private void Update() { //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) bool flag = NativeGamepad.ConsumeAdvance(); Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null || (Object)(object)ZNet.instance == (Object)null || ZDOMan.instance == null || ((Character)localPlayer).IsDead() || ((Character)localPlayer).IsTeleporting()) { CommandState.Reset(); return; } KeyboardShortcut value = advanceKey.Value; if ((!((KeyboardShortcut)(ref value)).IsDown() && !flag) || !NativeGamepad.CanTakeInput(localPlayer) || !CommandState.BeginAdvance(Time.frameCount, Time.unscaledTime)) { return; } foreach (Character allCharacter in Character.GetAllCharacters()) { if ((Object)(object)allCharacter == (Object)null || allCharacter.IsDead() || !allCharacter.IsTamed()) { continue; } MonsterAI component = ((Component)allCharacter).GetComponent<MonsterAI>(); if ((Object)(object)component == (Object)null || (Object)(object)component.GetFollowTarget() != (Object)(object)((Component)localPlayer).gameObject) { continue; } Tameable component2 = ((Component)allCharacter).GetComponent<Tameable>(); if ((Object)(object)component2 != (Object)null && component2.HaveRider()) { continue; } ZNetView component3 = ((Component)allCharacter).GetComponent<ZNetView>(); if (!((Object)(object)component3 == (Object)null) && component3.IsValid()) { try { component3.ClaimOwnership(); WakeMethod.Invoke(component, null); ApplyAdvance(component, Time.unscaledTime); } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogError((object)("Advance command failed for " + ((Object)allCharacter).name + ": " + ex.GetBaseException())); } } } } internal static void ApplyAdvance(MonsterAI ai, float now) { //IL_00ed: Unknown result type (might be due to invalid IL or missing references) //IL_00f2: Unknown result type (might be due to invalid IL or missing references) //IL_0102: Unknown result type (might be due to invalid IL or missing references) if (!CommandState.IsAdvanceActive(now) || (Object)(object)ai == (Object)null) { return; } Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null || ((Character)localPlayer).IsDead() || ((Character)localPlayer).IsTeleporting() || (Object)(object)ai.GetFollowTarget() != (Object)(object)((Component)localPlayer).gameObject) { return; } Character component = ((Component)ai).GetComponent<Character>(); ZNetView component2 = ((Component)ai).GetComponent<ZNetView>(); if (!((Object)(object)component == (Object)null) && !component.IsDead() && component.IsTamed() && !((Object)(object)component2 == (Object)null) && component2.IsValid() && component2.IsOwner()) { Tameable component3 = ((Component)component).GetComponent<Tameable>(); if ((!((Object)(object)component3 != (Object)null) || !component3.HaveRider()) && !((Object)(object)((BaseAI)ai).GetTargetCreature() != (Object)null) && !((Object)(object)ai.GetStaticTarget() != (Object)null)) { Vector3 lookDir = ((Character)localPlayer).GetLookDir(); MoveMethod.Invoke(ai, new object[2] { lookDir, true }); } } } internal static void AfterAiUpdate(MonsterAI ai, bool updated) { if (!updated || !CommandState.IsAdvanceActive(Time.unscaledTime)) { return; } try { ApplyAdvance(ai, Time.unscaledTime); } catch (Exception ex) { CommandState.Reset(); if ((Object)(object)instance != (Object)null) { ((BaseUnityPlugin)instance).Logger.LogError((object)("Advance AI update failed: " + ex.GetBaseException())); } } } } [HarmonyPatch(typeof(MonsterAI), "UpdateAI", new Type[] { typeof(float) })] internal static class AdvanceAiPatch { private static void Postfix(MonsterAI __instance, bool __result) { FollowerAdvancePlugin.AfterAiUpdate(__instance, __result); } }
FollowerRecall.dll
Decompiled a day agousing System; using System.Collections.Generic; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using BepInEx; using BepInEx.Configuration; using HarmonyLib; using UnityEngine; [assembly: AssemblyFileVersion("1.0.1.0")] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: AssemblyVersion("1.0.1.0")] namespace Fai.FollowerCommands; public static class CommandState { private static float advanceUntil; private static int recallFrame = -1; public static bool BeginAdvance(int frame, float now) { if (frame == recallFrame) { return false; } advanceUntil = now + 3f; return true; } public static bool IsAdvanceActive(float now) { return advanceUntil > 0f && now < advanceUntil; } public static void Recall(int frame) { advanceUntil = 0f; recallFrame = frame; } public static void Reset() { advanceUntil = 0f; recallFrame = -1; } } [BepInPlugin("fai.FollowerRecall", "Follower Recall", "1.0.1")] public sealed class FollowerRecallPlugin : BaseUnityPlugin { private sealed class Recall { internal ZDOID Id; internal ZDOID Player; internal Vector3 Destination; internal float Expires; internal bool Prepared; internal bool Applied; } internal sealed class RecallRequest { internal ZDOID Player; internal Vector3 Origin; internal List<Vector3> Points; internal HashSet<ZDOID> Loaded; } public const string PluginGuid = "fai.FollowerRecall"; internal const string RequestRpc = "Fai_FollowerCommands_RecallRequest_v100"; internal const string ApplyRpc = "Fai_FollowerCommands_RecallApply_v100"; internal const string ResultRpc = "Fai_FollowerCommands_RecallResult_v100"; internal const float Radius = 3f; internal static FollowerRecallPlugin Instance; private ConfigEntry<KeyboardShortcut> shortcut; private Harmony harmony; private ZRoutedRpc registeredRpc; private readonly Dictionary<ZDOID, Recall> recalls = new Dictionary<ZDOID, Recall>(); private readonly Dictionary<long, float> lastRequest = new Dictionary<long, float>(); private float awaitingSince = -1f; private float nextPress; private static readonly FieldInfo ObjectsField = FindField(typeof(ZDOMan), "m_objectsByID"); private static readonly FieldInfo TargetCreatureField = FindField(typeof(MonsterAI), "m_targetCreature"); private static readonly MethodInfo AlertMethod = FindMethod(typeof(MonsterAI), "SetAlerted"); private static readonly MethodInfo GroundMethod = FindMethod(typeof(Character), "ResetGroundContact"); private static readonly FieldInfo TargetStaticField = FindField(typeof(MonsterAI), "m_targetStatic"); private static readonly Dictionary<string, FieldInfo> CharacterFields = new string[6] { "m_maxAirAltitude", "m_lastGroundTouch", "m_fallTimer", "m_pushForce", "m_rootMotion", "m_moveDir" }.ToDictionary((string n) => n, (string n) => FindField(typeof(Character), n)); private static readonly Dictionary<string, FieldInfo> SyncFields = new string[5] { "m_targetPosTimer", "m_haveTempRelPos", "m_positionCached", "m_velocityCached", "m_lastLocalVelocity" }.ToDictionary((string n) => n, (string n) => FindField(typeof(ZSyncTransform), n)); private static FieldInfo FindField(Type type, string name) { Type type2 = type; while (type != null) { FieldInfo field = type.GetField(name, BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); if (field != null) { return field; } type = type.BaseType; } throw new MissingFieldException(type2.FullName, name); } private static MethodInfo FindMethod(Type type, string name) { Type type2 = type; while (type != null) { MethodInfo method = type.GetMethod(name, BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); if (method != null) { return method; } type = type.BaseType; } throw new MissingMethodException(type2.FullName, name); } internal static ZPackage EncodeRequest(ZDOID player, Vector3 origin, List<Vector3> points, List<ZDOID> loaded) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Expected O, but got Unknown //IL_0007: 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_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0035: 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_007a: 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) ZPackage val = new ZPackage(); val.Write(player); val.Write(origin); val.Write(points.Count); foreach (Vector3 point in points) { val.Write(point); } val.Write(loaded.Count); foreach (ZDOID item in loaded) { val.Write(item); } return val; } internal static RecallRequest DecodeRequest(ZPackage package) { //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_006b: 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_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_00fc: Unknown result type (might be due to invalid IL or missing references) if (package == null) { throw new ArgumentNullException("package"); } package.SetPos(0); RecallRequest recallRequest = new RecallRequest(); recallRequest.Player = package.ReadZDOID(); recallRequest.Origin = package.ReadVector3(); int num = package.ReadInt(); if (num < 1 || num > 64) { throw new ArgumentException("Invalid destination count."); } recallRequest.Points = new List<Vector3>(num); for (int i = 0; i < num; i++) { Vector3 val = package.ReadVector3(); if (!WithinRadius(recallRequest.Origin, val)) { throw new ArgumentException("Destination exceeds 3 metres."); } recallRequest.Points.Add(val); } int num2 = package.ReadInt(); if (num2 < 0 || num2 > 100000 || num2 > (package.Size() - package.GetPos()) / 12) { throw new ArgumentException("Invalid loaded follower count."); } recallRequest.Loaded = new HashSet<ZDOID>(); for (int j = 0; j < num2; j++) { recallRequest.Loaded.Add(package.ReadZDOID()); } return recallRequest; } private void Awake() { //IL_001e: 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_0042: Expected O, but got Unknown Instance = this; shortcut = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("General", "RecallShortcut", new KeyboardShortcut((KeyCode)104, Array.Empty<KeyCode>()), "Teleport every tamed creature following you into a 3 metre radius. No source-distance limit. Host/server must also install this version."); harmony = new Harmony("fai.followercommands.recall"); harmony.PatchAll(typeof(FollowerRecallPlugin).Assembly); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Follower Recall 1.0.1 loaded (H or LT+A; 3m; no on-screen recall notifications)."); } private void OnDestroy() { if (harmony != null) { harmony.UnpatchSelf(); } recalls.Clear(); NativeGamepad.Reset(); CommandState.Reset(); if ((Object)(object)Instance == (Object)(object)this) { Instance = null; } } private void Update() { //IL_0156: 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_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_01ea: Unknown result type (might be due to invalid IL or missing references) //IL_01ef: 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_0243: Unknown result type (might be due to invalid IL or missing references) //IL_02f7: Unknown result type (might be due to invalid IL or missing references) //IL_0303: Unknown result type (might be due to invalid IL or missing references) //IL_02cc: Unknown result type (might be due to invalid IL or missing references) bool flag = NativeGamepad.ConsumeRecall(); RegisterRpcs(); if ((Object)(object)ZNet.instance == (Object)null || ZDOMan.instance == null || (Object)(object)ZNetScene.instance == (Object)null) { recalls.Clear(); lastRequest.Clear(); awaitingSince = -1f; CommandState.Reset(); return; } Recall[] array = recalls.Values.ToArray(); foreach (Recall recall in array) { if (Time.unscaledTime >= recall.Expires) { recalls.Remove(recall.Id); } else { if (recall.Applied) { continue; } ZDO zDO = ZDOMan.instance.GetZDO(recall.Id); if (zDO == null) { continue; } try { PrepareRecall(zDO, recall); GameObject val = ZNetScene.instance.FindInstance(recall.Id); if (!((Object)(object)val == (Object)null)) { Character component = val.GetComponent<Character>(); if ((Object)(object)component == (Object)null || component.IsDead()) { recall.Applied = true; } else { ApplyLoadedRecall(component, recall); } } } catch (Exception ex) { recall.Applied = true; ((BaseUnityPlugin)this).Logger.LogError((object)string.Concat("Recall synchronization failed for ", recall.Id, ": ", ex.GetBaseException())); } } } Player localPlayer = Player.m_localPlayer; if (awaitingSince >= 0f && Time.unscaledTime - awaitingSince > 8f) { awaitingSince = -1f; ((BaseUnityPlugin)this).Logger.LogWarning((object)"Recall request timed out. Verify that the host has Follower Commands installed."); } if ((Object)(object)localPlayer == (Object)null) { return; } KeyboardShortcut value = shortcut.Value; if ((!((KeyboardShortcut)(ref value)).IsDown() && !flag) || Time.unscaledTime < nextPress || !NativeGamepad.CanTakeInput(localPlayer)) { return; } nextPress = Time.unscaledTime + 0.2f; CommandState.Recall(Time.frameCount); List<Vector3> points = BuildLandingPoints(((Component)localPlayer).transform.position); List<ZDOID> list = new List<ZDOID>(); foreach (Character allCharacter in Character.GetAllCharacters()) { if (!((Object)(object)allCharacter == (Object)null) && allCharacter.IsTamed() && !allCharacter.IsDead()) { MonsterAI component2 = ((Component)allCharacter).GetComponent<MonsterAI>(); if ((Object)(object)component2 != (Object)null && (Object)(object)component2.GetFollowTarget() == (Object)(object)((Component)localPlayer).gameObject) { list.Add(allCharacter.GetZDOID()); } } } ZPackage val2 = EncodeRequest(((Character)localPlayer).GetZDOID(), ((Component)localPlayer).transform.position, points, list); if (ZNet.instance.IsServer()) { HandleRequest(ZNet.GetUID(), val2); return; } awaitingSince = Time.unscaledTime; ZRoutedRpc.instance.InvokeRoutedRPC(GetServerId(), "Fai_FollowerCommands_RecallRequest_v100", new object[1] { val2 }); } private void RegisterRpcs() { ZRoutedRpc instance = ZRoutedRpc.instance; if (instance != null && !object.ReferenceEquals(instance, registeredRpc)) { registeredRpc = instance; instance.Register<ZPackage>("Fai_FollowerCommands_RecallRequest_v100", (Action<long, ZPackage>)HandleRequest); instance.Register<ZPackage>("Fai_FollowerCommands_RecallApply_v100", (Action<long, ZPackage>)HandleApply); instance.Register<int>("Fai_FollowerCommands_RecallResult_v100", (Action<long, int>)HandleResult); } } internal static bool IsFinite(Vector3 point) { return !float.IsNaN(point.x) && !float.IsNaN(point.y) && !float.IsNaN(point.z) && !float.IsInfinity(point.x) && !float.IsInfinity(point.y) && !float.IsInfinity(point.z); } internal static bool IsSavedFollower(ZDO zdo, string playerName) { return zdo != null && zdo.GetBool(ZDOVars.s_tamed, false) && !zdo.GetBool(ZDOVars.s_dead, false) && zdo.GetFloat(ZDOVars.s_health, 1f) > 0f && !string.IsNullOrEmpty(playerName) && string.Equals(zdo.GetString(ZDOVars.s_follow, string.Empty), playerName, StringComparison.Ordinal); } internal static bool WithinRadius(Vector3 origin, Vector3 point) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_000b: 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_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) int result; if (IsFinite(origin) && IsFinite(point)) { Vector3 val = point - origin; result = ((((Vector3)(ref val)).sqrMagnitude <= 9f) ? 1 : 0); } else { result = 0; } return (byte)result != 0; } private void HandleRequest(long sender, ZPackage package) { //IL_0415: Unknown result type (might be due to invalid IL or missing references) //IL_045e: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_008a: 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_0069: Unknown result type (might be due to invalid IL or missing references) //IL_031a: Unknown result type (might be due to invalid IL or missing references) //IL_031f: Unknown result type (might be due to invalid IL or missing references) //IL_032c: Unknown result type (might be due to invalid IL or missing references) //IL_0331: Unknown result type (might be due to invalid IL or missing references) //IL_0338: Unknown result type (might be due to invalid IL or missing references) //IL_0339: Unknown result type (might be due to invalid IL or missing references) //IL_0340: Unknown result type (might be due to invalid IL or missing references) //IL_0342: Unknown result type (might be due to invalid IL or missing references) //IL_03a1: Unknown result type (might be due to invalid IL or missing references) //IL_03b7: 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_0124: Unknown result type (might be due to invalid IL or missing references) //IL_0129: Unknown result type (might be due to invalid IL or missing references) //IL_012b: Unknown result type (might be due to invalid IL or missing references) //IL_0137: Unknown result type (might be due to invalid IL or missing references) //IL_013b: Unknown result type (might be due to invalid IL or missing references) //IL_0140: Unknown result type (might be due to invalid IL or missing references) //IL_0145: Unknown result type (might be due to invalid IL or missing references) //IL_0203: Unknown result type (might be due to invalid IL or missing references) //IL_026d: Unknown result type (might be due to invalid IL or missing references) //IL_0272: Unknown result type (might be due to invalid IL or missing references) //IL_02b0: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)ZNet.instance == (Object)null || !ZNet.instance.IsServer() || ZDOMan.instance == null) { return; } try { RecallRequest recallRequest = DecodeRequest(package); ZDOID player = recallRequest.Player; ZNetPeer peer = ZNet.instance.GetPeer(sender); if (sender == ZNet.GetUID()) { if ((Object)(object)Player.m_localPlayer == (Object)null || ((Character)Player.m_localPlayer).GetZDOID() != player) { return; } } else if (peer == null || peer.m_characterID != player) { return; } if (lastRequest.TryGetValue(sender, out var value) && Time.unscaledTime - value < 0.15f) { return; } lastRequest[sender] = Time.unscaledTime; ZDO zDO = ZDOMan.instance.GetZDO(player); if (zDO == null || zDO.GetBool(ZDOVars.s_dead, false)) { return; } string text = zDO.GetString(ZDOVars.s_playerName, string.Empty); if (string.IsNullOrEmpty(text)) { return; } Vector3 origin = recallRequest.Origin; if (!IsFinite(origin)) { return; } Vector3 val = origin - zDO.GetPosition(); if (((Vector3)(ref val)).sqrMagnitude > 100f) { return; } List<Vector3> points = recallRequest.Points; HashSet<ZDOID> loaded = recallRequest.Loaded; if (!(ObjectsField.GetValue(ZDOMan.instance) is Dictionary<ZDOID, ZDO> dictionary)) { throw new InvalidOperationException("Cannot enumerate world ZDOs."); } List<ZDO> list = new List<ZDO>(); foreach (ZDO value2 in dictionary.Values) { if (value2.GetBool(ZDOVars.s_tamed, false) && !value2.GetBool(ZDOVars.s_dead, false) && !(value2.GetFloat(ZDOVars.s_health, 1f) <= 0f)) { GameObject val2 = ZNetScene.instance.FindInstance(value2.m_uid); MonsterAI val3 = ((!((Object)(object)val2 == (Object)null)) ? val2.GetComponent<MonsterAI>() : null); GameObject val4 = ((!((Object)(object)val3 == (Object)null)) ? val3.GetFollowTarget() : null); bool flag = ((!((Object)(object)val4 != (Object)null)) ? IsSavedFollower(value2, text) : ((Object)(object)val4.GetComponent<Player>() != (Object)null && ((Character)val4.GetComponent<Player>()).GetZDOID() == player)); if (!flag && (Object)(object)val4 == (Object)null && value2.GetOwner() == sender && loaded.Contains(value2.m_uid)) { flag = true; } if (flag) { list.Add(value2); } } } List<Recall> list2 = new List<Recall>(); int num = 0; for (int i = 0; i < list.Count; i++) { ZDO val5 = list[i]; Vector3 destination = points[i % points.Count]; Recall recall = new Recall(); recall.Id = val5.m_uid; recall.Player = player; recall.Destination = destination; recall.Expires = Time.unscaledTime + 5f; Recall recall2 = recall; long owner = val5.GetOwner(); bool flag2 = false; try { val5.SetOwner(ZNet.GetUID()); PrepareRecall(val5, recall2); val5.Set(ZDOVars.s_follow, text); val5.Set(ZDOVars.s_patrol, false); recalls[recall2.Id] = recall2; flag2 = true; GameObject val6 = ZNetScene.instance.FindInstance(val5.m_uid); Character val7 = ((!((Object)(object)val6 == (Object)null)) ? val6.GetComponent<Character>() : null); if ((Object)(object)val7 != (Object)null) { ApplyLoadedRecall(val7, recall2); } } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogError((object)string.Concat("Recall failed for ", val5.m_uid, ": ", ex.GetBaseException())); } finally { val5.SetOwner((!flag2) ? owner : sender); ZDOMan.instance.ForceSendZDO(val5.m_uid); } if (flag2) { num++; list2.Add(recall2); if (list2.Count == 128) { Broadcast(list2); list2.Clear(); } } } if (list2.Count > 0) { Broadcast(list2); } if (sender == ZNet.GetUID()) { HandleResult(sender, num); } else { ZRoutedRpc.instance.InvokeRoutedRPC(sender, "Fai_FollowerCommands_RecallResult_v100", new object[1] { num }); } ((BaseUnityPlugin)this).Logger.LogInfo((object)("Recalled " + num + " tamed followers for " + text + " (world-wide, <=3m).")); } catch (Exception ex2) { ((BaseUnityPlugin)this).Logger.LogError((object)("Recall failed: " + ex2)); if (sender != ZNet.GetUID() && ZRoutedRpc.instance != null) { ZRoutedRpc.instance.InvokeRoutedRPC(sender, "Fai_FollowerCommands_RecallResult_v100", new object[1] { -1 }); } } } private void Broadcast(List<Recall> batch) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Expected O, but got Unknown //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_0034: 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) ZPackage val = new ZPackage(); val.Write(batch.Count); foreach (Recall item in batch) { val.Write(item.Id); val.Write(item.Player); val.Write(item.Destination); } ZRoutedRpc.instance.InvokeRoutedRPC(0L, "Fai_FollowerCommands_RecallApply_v100", new object[1] { val }); } private static long GetServerId() { if ((Object)(object)ZNet.instance == (Object)null) { return 0L; } if (ZNet.instance.IsServer()) { return ZNet.GetUID(); } return ZNet.instance.GetServerPeer()?.m_uid ?? 0; } private bool FromServer(long sender) { return (Object)(object)ZNet.instance != (Object)null && ZRoutedRpc.instance != null && sender == GetServerId(); } private void HandleApply(long sender, ZPackage packet) { //IL_0068: 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 (!FromServer(sender) || ZDOMan.instance == null) { return; } try { foreach (Recall item in DecodeApply(packet, Time.unscaledTime)) { if (!ZNet.instance.IsServer() || !recalls.TryGetValue(item.Id, out var _)) { recalls[item.Id] = item; } } } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Invalid recall synchronization: " + ex.Message)); } } private static List<Recall> DecodeApply(ZPackage packet, float now) { //IL_0061: 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_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_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_0077: 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_0099: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: 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) if (packet == null) { throw new ArgumentNullException("packet"); } packet.SetPos(0); int num = packet.ReadInt(); if (num < 0 || num > 128 || num > (packet.Size() - packet.GetPos()) / 36) { throw new ArgumentException("Invalid recall synchronization count."); } List<Recall> list = new List<Recall>(num); for (int i = 0; i < num; i++) { ZDOID id = packet.ReadZDOID(); ZDOID player = packet.ReadZDOID(); Vector3 val = packet.ReadVector3(); if (!IsFinite(val)) { throw new ArgumentException("Invalid recall destination."); } list.Add(new Recall { Id = id, Player = player, Destination = val, Expires = now + 5f }); } return list; } private void HandleResult(long sender, int count) { if (FromServer(sender)) { awaitingSince = -1f; if (count < 0) { ((BaseUnityPlugin)this).Logger.LogWarning((object)"Host reported a recall failure. See the host's BepInEx log."); } } } private static void PrepareRecall(ZDO zdo, Recall recall) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_0039: 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_0059: 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) //IL_0075: Unknown result type (might be due to invalid IL or missing references) if (!recall.Prepared) { zdo.SetPosition(recall.Destination); if (zdo.IsOwner()) { zdo.Set(ZDOVars.s_velHash, Vector3.zero); zdo.Set(ZDOVars.s_velRelHash, Vector3.zero); zdo.Set(ZDOVars.s_bodyVelHash, Vector3.zero); zdo.Set(ZDOVars.s_bodyAVelHash, Vector3.zero); zdo.Set(ZDOVars.s_bodyVelocity, Vector3.zero); zdo.SetConnection((ConnectionType)2, ZDOID.None); } recall.Prepared = true; } } private void ApplyLoadedRecall(Character creature, Recall recall) { //IL_002b: Unknown result type (might be due to invalid IL or missing references) recall.Applied = true; try { ApplyToInstance(creature, recall); } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogError((object)string.Concat("Recall instance update failed for ", recall.Id, ": ", ex.GetBaseException())); } } private static List<Vector3> BuildLandingPoints(Vector3 origin) { //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_0086: 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) //IL_008a: 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_0099: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: Unknown result type (might be due to invalid IL or missing references) //IL_00c2: Unknown result type (might be due to invalid IL or missing references) //IL_016b: 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_0176: Unknown result type (might be due to invalid IL or missing references) //IL_017b: Unknown result type (might be due to invalid IL or missing references) //IL_00de: Unknown result type (might be due to invalid IL or missing references) //IL_00e3: Unknown result type (might be due to invalid IL or missing references) //IL_00f7: Unknown result type (might be due to invalid IL or missing references) //IL_00f8: 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_010b: 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_011a: Unknown result type (might be due to invalid IL or missing references) //IL_011f: Unknown result type (might be due to invalid IL or missing references) //IL_0121: Unknown result type (might be due to invalid IL or missing references) //IL_012b: Unknown result type (might be due to invalid IL or missing references) //IL_0130: Unknown result type (might be due to invalid IL or missing references) //IL_014c: Unknown result type (might be due to invalid IL or missing references) List<Vector3> list = new List<Vector3>(); int mask = LayerMask.GetMask(new string[6] { "Default", "static_solid", "Default_small", "piece", "terrain", "vehicle" }); RaycastHit val2 = default(RaycastHit); for (int i = 0; i < 48; i++) { float num = (float)i * 2.3999631f; float num2 = 1.35f + (float)(i % 4) * 0.4f; Vector3 val = origin + new Vector3(Mathf.Cos(num) * num2, 0f, Mathf.Sin(num) * num2); if (Physics.Raycast(val + Vector3.up * 1.4f, Vector3.down, ref val2, 3.8f, mask, (QueryTriggerInteraction)1) && !(((RaycastHit)(ref val2)).normal.y < 0.5f)) { val.y = ((RaycastHit)(ref val2)).point.y + 0.1f; if (WithinRadius(origin, val) && !Physics.CheckCapsule(val + Vector3.up * 0.3f, val + Vector3.up * 0.9f, 0.25f, mask, (QueryTriggerInteraction)1)) { list.Add(val); } } } if (list.Count == 0) { list.Add(origin + Vector3.up * 0.15f); } return list; } private static void ApplyToInstance(Character creature, Recall recall) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_00e9: Unknown result type (might be due to invalid IL or missing references) //IL_0108: Unknown result type (might be due to invalid IL or missing references) //IL_0026: 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_0047: Unknown result type (might be due to invalid IL or missing references) //IL_01d0: Unknown result type (might be due to invalid IL or missing references) //IL_01ef: Unknown result type (might be due to invalid IL or missing references) //IL_020e: Unknown result type (might be due to invalid IL or missing references) //IL_0154: Unknown result type (might be due to invalid IL or missing references) ((Component)creature).transform.position = recall.Destination; Rigidbody component = ((Component)creature).GetComponent<Rigidbody>(); if ((Object)(object)component != (Object)null) { component.position = recall.Destination; if (!component.isKinematic) { component.linearVelocity = Vector3.zero; component.angularVelocity = Vector3.zero; } component.WakeUp(); } CharacterFields["m_maxAirAltitude"].SetValue(creature, recall.Destination.y); CharacterFields["m_lastGroundTouch"].SetValue(creature, 0f); CharacterFields["m_fallTimer"].SetValue(creature, 0f); CharacterFields["m_pushForce"].SetValue(creature, Vector3.zero); CharacterFields["m_rootMotion"].SetValue(creature, Vector3.zero); CharacterFields["m_moveDir"].SetValue(creature, Vector3.zero); GroundMethod.Invoke(creature, null); MonsterAI component2 = ((Component)creature).GetComponent<MonsterAI>(); if ((Object)(object)component2 != (Object)null) { if (creature.IsOwner()) { ClearTarget(component2); ((BaseAI)component2).ResetPatrolPoint(); } GameObject val = ZNetScene.instance.FindInstance(recall.Player); if ((Object)(object)val != (Object)null) { component2.SetFollowTarget(val); } } ZSyncTransform component3 = ((Component)creature).GetComponent<ZSyncTransform>(); if ((Object)(object)component3 != (Object)null) { SyncFields["m_targetPosTimer"].SetValue(component3, 0f); SyncFields["m_haveTempRelPos"].SetValue(component3, false); SyncFields["m_positionCached"].SetValue(component3, recall.Destination); SyncFields["m_velocityCached"].SetValue(component3, Vector3.zero); SyncFields["m_lastLocalVelocity"].SetValue(component3, Vector3.zero); if (creature.IsOwner()) { component3.SyncNow(); } } } internal static bool SuppressTarget(MonsterAI ai) { //IL_0059: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)Instance == (Object)null || (Object)(object)ai == (Object)null) { return false; } ZNetView component = ((Component)ai).GetComponent<ZNetView>(); if ((Object)(object)component == (Object)null || !component.IsValid() || !component.IsOwner()) { return false; } if (!Instance.recalls.TryGetValue(component.GetZDO().m_uid, out var value) || Time.unscaledTime >= value.Expires) { return false; } Character component2 = ((Component)ai).GetComponent<Character>(); if ((Object)(object)component2 == (Object)null || !component2.IsTamed()) { return false; } ClearTarget(ai); return true; } private static void ClearTarget(MonsterAI ai) { TargetCreatureField.SetValue(ai, null); TargetStaticField.SetValue(ai, null); AlertMethod.Invoke(ai, new object[1] { false }); } } [HarmonyPatch(typeof(MonsterAI), "UpdateTarget")] internal static class RecallCombatPatch { private static bool Prefix(MonsterAI __instance) { return !FollowerRecallPlugin.SuppressTarget(__instance); } } public static class NativeGamepad { private static readonly ComboState State = new ComboState(); private static readonly MethodInfo TakeInput = typeof(Player).GetMethod("TakeInput", BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); public static bool ConsumeAdvance() { SampleNative(); return State.TakeAdvance(); } public static bool ConsumeRecall() { SampleNative(); return State.TakeRecall(); } public static void Reset() { State.Reset(); } public static bool CanTakeInput(Player player) { if ((Object)(object)player == (Object)null || ((Character)player).IsDead() || ((Character)player).IsTeleporting() || (Object)(object)Hud.instance == (Object)null || TakeInput == null) { return false; } try { return (bool)TakeInput.Invoke(player, null); } catch (TargetInvocationException) { return false; } } internal static void SampleNative() { ReadPhysical(out var enabled, out var allowed, out var triggerHeld, out var advanceHeld, out var recallHeld); State.Sample(Time.frameCount, enabled, allowed, triggerHeld, advanceHeld, recallHeld); } private static void ReadPhysical(out bool enabled, out bool allowed, out bool triggerHeld, out bool advanceHeld, out bool recallHeld) { enabled = ZInput.instance != null && ZInput.IsGamepadEnabled(); allowed = false; triggerHeld = false; advanceHeld = false; recallHeld = false; if (enabled) { triggerHeld = ReadHeld("JoyLTrigger"); advanceHeld = ReadHeld("JoyButtonX"); recallHeld = ReadHeld("JoyButtonA"); allowed = CanTakeInput(Player.m_localPlayer); } } private static bool ReadHeld(string name) { ButtonDef buttonDef = ZInput.instance.GetButtonDef(name); return buttonDef != null && buttonDef.Held; } internal static bool SuppressNativeButton(string name) { if (string.IsNullOrEmpty(name)) { return false; } if (ZInput.instance == null || !ZInput.IsGamepadEnabled()) { return false; } ButtonDef buttonDef = ZInput.instance.GetButtonDef(name); string path; try { path = ((buttonDef != null) ? buttonDef.GetActionPath(true) : null); } catch (ArgumentOutOfRangeException) { return false; } catch (IndexOutOfRangeException) { return false; } if (!ComboState.BlocksPath(path, blockAdvance: true, blockRecall: true, triggerHeld: true)) { return false; } ReadPhysical(out var enabled, out var allowed, out var triggerHeld, out var advanceHeld, out var recallHeld); if (!enabled || !allowed) { return false; } bool blockAdvance = (triggerHeld && advanceHeld) || State.BlockAdvance(Time.frameCount); bool blockRecall = (triggerHeld && recallHeld) || State.BlockRecall(Time.frameCount); return ComboState.BlocksPath(path, blockAdvance, blockRecall, triggerHeld); } } internal sealed class ComboState { private bool previousAdvance; private bool previousRecall; private bool pendingAdvance; private bool pendingRecall; private bool consumedAdvance; private bool consumedRecall; private int advanceReleased = -1; private int recallReleased = -1; internal void Sample(int frame, bool enabled, bool allowed, bool triggerHeld, bool advanceHeld, bool recallHeld) { if (!enabled) { Reset(); return; } bool flag = triggerHeld && advanceHeld; bool flag2 = triggerHeld && recallHeld; if (!allowed) { pendingAdvance = false; pendingRecall = false; consumedAdvance = false; consumedRecall = false; advanceReleased = -1; recallReleased = -1; } else { if (flag && !recallHeld && !previousAdvance) { pendingAdvance = true; } if (flag2 && !advanceHeld && !previousRecall) { pendingRecall = true; } if (consumedAdvance && !advanceHeld) { advanceReleased = frame; } if (consumedRecall && !recallHeld) { recallReleased = frame; } consumedAdvance = advanceHeld && (consumedAdvance || triggerHeld); consumedRecall = recallHeld && (consumedRecall || triggerHeld); } previousAdvance = flag; previousRecall = flag2; } internal bool TakeAdvance() { bool result = pendingAdvance; pendingAdvance = false; return result; } internal bool TakeRecall() { bool result = pendingRecall; pendingRecall = false; return result; } internal bool BlockAdvance(int frame) { return consumedAdvance || advanceReleased == frame; } internal bool BlockRecall(int frame) { return consumedRecall || recallReleased == frame; } internal static bool BlocksPath(string path, bool blockAdvance, bool blockRecall, bool triggerHeld) { if (string.IsNullOrEmpty(path)) { return false; } return (blockAdvance && path.EndsWith("/buttonWest", StringComparison.OrdinalIgnoreCase)) || (blockRecall && path.EndsWith("/buttonSouth", StringComparison.OrdinalIgnoreCase)) || (triggerHeld && (blockAdvance || blockRecall) && path.EndsWith("/leftTrigger", StringComparison.OrdinalIgnoreCase)); } internal void Reset() { previousAdvance = false; previousRecall = false; pendingAdvance = false; pendingRecall = false; consumedAdvance = false; consumedRecall = false; advanceReleased = -1; recallReleased = -1; } } [HarmonyPatch(typeof(ZInput), "InternalUpdate")] internal static class NativeGamepadCapturePatch { private static void Postfix() { NativeGamepad.SampleNative(); } } [HarmonyPatch] internal static class NativeGamepadConflictPatch { private static IEnumerable<MethodBase> TargetMethods() { string[] array = new string[3] { "GetButton", "GetButtonDown", "GetButtonUp" }; foreach (string name in array) { yield return typeof(ZInput).GetMethod(name, BindingFlags.Static | BindingFlags.Public, null, new Type[1] { typeof(string) }, null); } } private static bool Prefix(string name, ref bool __result) { if (!NativeGamepad.SuppressNativeButton(name)) { return true; } __result = false; return false; } }