using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using SnailMaster.Patches;
using UnityEngine;
using UnityEngine.Audio;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: IgnoresAccessChecksTo("Assembly-CSharp")]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("com.github.Kirshoo.SnailMaster")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("0.5.0.0")]
[assembly: AssemblyInformationalVersion("0.5.0")]
[assembly: AssemblyProduct("com.github.Kirshoo.SnailMaster")]
[assembly: AssemblyTitle("SnailMaster")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.5.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
internal sealed class EmbeddedAttribute : Attribute
{
}
}
namespace System.Runtime.CompilerServices
{
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
internal sealed class NullableAttribute : Attribute
{
public readonly byte[] NullableFlags;
public NullableAttribute(byte P_0)
{
NullableFlags = new byte[1] { P_0 };
}
public NullableAttribute(byte[] P_0)
{
NullableFlags = P_0;
}
}
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
internal sealed class NullableContextAttribute : Attribute
{
public readonly byte Flag;
public NullableContextAttribute(byte P_0)
{
Flag = P_0;
}
}
[CompilerGenerated]
[Microsoft.CodeAnalysis.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 BepInEx
{
[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
[Conditional("CodeGeneration")]
internal sealed class BepInAutoPluginAttribute : Attribute
{
public BepInAutoPluginAttribute(string? id = null, string? name = null, string? version = null)
{
}
}
}
namespace BepInEx.Preloader.Core.Patching
{
[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
[Conditional("CodeGeneration")]
internal sealed class PatcherAutoPluginAttribute : Attribute
{
public PatcherAutoPluginAttribute(string? id = null, string? name = null, string? version = null)
{
}
}
}
namespace SnailMaster
{
[BepInPlugin("com.github.Kirshoo.SnailMaster", "SnailMaster", "0.5.0")]
public class Plugin : BaseUnityPlugin
{
public const string Id = "com.github.Kirshoo.SnailMaster";
internal static ManualLogSource Logger { get; private set; }
public static string Name => "SnailMaster";
public static string Version => "0.5.0";
private void Awake()
{
//IL_0034: Unknown result type (might be due to invalid IL or missing references)
//IL_003a: Expected O, but got Unknown
Logger = ((BaseUnityPlugin)this).Logger;
BindConfig();
Logger.LogInfo((object)("Plugin " + Name + " is loaded!"));
Harmony val = new Harmony("com.github.Kirshoo.SnailMaster");
val.PatchAll(typeof(ScoutMasterPatch));
val.PatchAll(typeof(RunStartPatch));
val.PatchAll(typeof(PickUpItemPatch));
val.PatchAll(typeof(SnailMasterMovementPatch));
Logger.LogInfo((object)"All patches were successful!");
}
private void BindConfig()
{
SnailMasterConfig.BindConfig(((BaseUnityPlugin)this).Config);
}
}
internal abstract class Singleton<T> where T : class, new()
{
private static T _instance = null;
private static readonly object _lock = new object();
public static T Instance
{
get
{
if (_instance == null)
{
lock (_lock)
{
_instance = new T();
}
}
return _instance;
}
}
}
public enum PlayerChaseSelection
{
Highest,
Closest,
Random
}
public enum TeleportModeSelection
{
Default,
OnTargetSwitch,
Never
}
internal class SnailMasterConfig
{
public static ConfigEntry<float> ClimbSpeed;
public static ConfigEntry<float> WalkSpeed;
public static ConfigEntry<PlayerChaseSelection> ChaseMode;
public static ConfigEntry<float> RetargetCooldown;
public static ConfigEntry<float> GraceTime;
public static ConfigEntry<TeleportModeSelection> TeleportMode;
public static ConfigEntry<float> TeleportDistance;
public static ConfigEntry<float> SpawnMinDistance;
public static ConfigEntry<float> SpawnMaxDistance;
public static ConfigEntry<float> SpawnMaxHeightDifference;
public static void BindConfig(ConfigFile configfile)
{
WalkSpeed = configfile.Bind<float>("SnailMaster", "WalkSpeed", 1f, "Speed at which snailmaster will walk towards players.");
ClimbSpeed = configfile.Bind<float>("SnailMaster", "ClimbSpeed", 1f, "Speed at which snailmaster will climb the walls and obstacles.");
ChaseMode = configfile.Bind<PlayerChaseSelection>("SnailMaster", "PlayerToChase", PlayerChaseSelection.Random, "Determines which player will be targeted by the snailmaster.\r\nAnyone but the target will be ignored by the snailmaster.\r\nHighest - player that is nearest to the peak will become the target of a snailmaster.\r\nClosest - player closest to the snailmaster.\r\nRandom - completely random player will become the target.");
RetargetCooldown = configfile.Bind<float>("SnailMaster", "TargetCooldown", 30f, "Time in seconds how often will the snailmaster switch targets.\r\nMinimum is 5 seconds for optimization reasons.");
if (RetargetCooldown.Value < 5f)
{
RetargetCooldown.Value = 5f;
}
GraceTime = configfile.Bind<float>("SnailMaster", "GraceTime", 30f, "Time after the snailmaster is spawned and before he starts chasing players.");
TeleportMode = configfile.Bind<TeleportModeSelection>("SnailMaster", "TeleportMode", TeleportModeSelection.Default, "Determines the mode at which SnailMaster's teleportation operates.\r\nDefault - teleports if distance to target exceeds the value of TeleportDistance.\r\nOnTargetSwitch - teleports only to the target the exceeds the value of TeleportDistance when switching targets, otherwise wont teleport.\r\nNever - completely shuts down the teleportation mechanic.");
TeleportDistance = configfile.Bind<float>("SnailMaster", "TeleportDistance", 80f * CharacterStats.unitsToMeters, "If distance to target exceeds this value, forces SnailMaster to teleport closer.\r\nValue is in in-game meters.\r\nIf TeleportMode is set to 'Never', this setting is ignored.");
SpawnMinDistance = configfile.Bind<float>("SnailMaster", "MinSpawnDistance", 50f * CharacterStats.unitsToMeters, "Minimum distance away from the target snailmaster is allowed to spawn/teleport to.\r\nRange is from 0 - infinity.\r\nIf set to 0, SM will be allowed to teleport right on top of the player.");
if (SpawnMinDistance.Value < 0f)
{
SpawnMinDistance.Value = 0f;
}
SpawnMaxDistance = configfile.Bind<float>("SnailMaster", "MaxSpawnDistance", 70f * CharacterStats.unitsToMeters, "Maximum distance away from the target snailmaster is allowed to spawn/teleport to.\r\nRange is from MinSpawnDistance - infinity.");
if (SpawnMaxDistance.Value < SpawnMinDistance.Value)
{
SpawnMaxDistance.Value = SpawnMinDistance.Value;
}
SpawnMaxHeightDifference = configfile.Bind<float>("SnailMaster", "MaxSpawnHeightDifference", 15f * CharacterStats.unitsToMeters, "Denotes how how high or below the target snailmaster is allowed to spawn/teleport.\r\nRange is 1 - infinity.\r\nRecommended to keep within 20-30 meter range, otherwise SM might not spawn at all.");
if (SpawnMaxHeightDifference.Value < 1f)
{
SpawnMaxHeightDifference.Value = 1f;
}
}
}
internal class SnailMasterManager : Singleton<SnailMasterManager>
{
private bool _snailmode;
public void EnableSnailMode()
{
if (!IsSnailActivated())
{
Scoutmaster val = default(Scoutmaster);
if (Scoutmaster.GetPrimaryScoutmaster(ref val))
{
_snailmode = true;
ScoutMasterPatch.AssignNewTarget(val);
val.chillForSeconds = SnailMasterConfig.GraceTime.Value;
val.TeleportCloseToTarget();
}
Plugin.Logger.LogDebug((object)$"Attempting to enable snail mode. IsSuccessful? {_snailmode}");
}
}
public void DisableSnailMode()
{
Plugin.Logger.LogDebug((object)"Disabling snail mode.");
_snailmode = false;
}
public bool IsSnailActivated()
{
return _snailmode;
}
}
}
namespace SnailMaster.Patches
{
internal class PickUpItemPatch
{
private const ushort CONCH_ITEM_ID = 69;
private const string SummonInteract = "INTERACT_SUMMON";
[HarmonyPatch(typeof(Item), "GetItemActions")]
[HarmonyPrefix]
private static void AddSnailMasterAction(Item __instance)
{
if (__instance.itemID == 69 && !Singleton<SnailMasterManager>.Instance.IsSnailActivated())
{
AddInteractTranslations();
LoadBugleSFX(((Component)__instance).gameObject);
__instance.totalUses = 1;
Action_ReduceUses reduceUsesAction = ((Component)__instance).gameObject.AddComponent<Action_ReduceUses>();
CallSnailMaster callSnailMaster = ((Component)__instance).gameObject.AddComponent<CallSnailMaster>();
__instance.usingTimePrimary = 5f;
__instance.showUseProgress = true;
callSnailMaster.reduceUsesAction = reduceUsesAction;
__instance.UIData.hasMainInteract = true;
__instance.UIData.mainInteractPrompt = "INTERACT_SUMMON";
}
}
private static void LoadBugleSFX(GameObject target)
{
//IL_0005: Unknown result type (might be due to invalid IL or missing references)
//IL_000b: Expected O, but got Unknown
//IL_007a: Unknown result type (might be due to invalid IL or missing references)
//IL_0080: Expected O, but got Unknown
GameObject val = new GameObject("SM Audio Play");
val.transform.SetParent(target.transform, false);
AudioSource val2 = val.GetComponent<AudioSource>();
if ((Object)(object)val2 == (Object)null)
{
val2 = val.AddComponent<AudioSource>();
}
val2.playOnAwake = false;
val2.maxDistance = 2000f;
val2.minDistance = 25f;
val2.pitch = 1f;
val2.loop = false;
val2.rolloffMode = (AudioRolloffMode)0;
val2.outputAudioMixerGroup = GetSFXMixer();
GameObject val3 = new GameObject("SM Audio End");
val3.transform.SetParent(target.transform, false);
AudioSource val4 = val3.GetComponent<AudioSource>();
if ((Object)(object)val4 == (Object)null)
{
val4 = val3.AddComponent<AudioSource>();
}
val4.playOnAwake = false;
val4.maxDistance = 500f;
val4.minDistance = 1f;
val4.pitch = 1f;
val4.rolloffMode = (AudioRolloffMode)2;
val4.clip = GetBugleStopClip();
val4.outputAudioMixerGroup = GetSFXMixer();
BugleSFX val5 = target.GetComponent<BugleSFX>();
if ((Object)(object)val5 == (Object)null)
{
val5 = target.AddComponent<BugleSFX>();
}
val5.bugleEnd = val4;
val5.buglePlayer = val2;
val5.bugle = GetBugleSFXs();
}
private static AudioMixerGroup? GetSFXMixer()
{
GameObject val = GameObject.Find("Audio End");
if ((Object)(object)val == (Object)null)
{
Plugin.Logger.LogWarning((object)"Unable to locate BugleStop audio clip");
return null;
}
return val.GetComponent<AudioSource>().outputAudioMixerGroup;
}
private static AudioClip? GetBugleStopClip()
{
GameObject val = GameObject.Find("Audio End");
if ((Object)(object)val == (Object)null)
{
Plugin.Logger.LogWarning((object)"Unable to locate BugleStop audio clip");
return null;
}
return val.GetComponent<AudioSource>().clip;
}
private static AudioClip[] GetBugleSFXs()
{
GameObject val = Resources.Load<GameObject>("0_Items/Bugle_Scoutmaster Variant");
if ((Object)(object)val == (Object)null)
{
Plugin.Logger.LogWarning((object)"Unable to load Scoutmaster bugle SFXs");
return Array.Empty<AudioClip>();
}
return val.GetComponent<BugleSFX>().bugle;
}
private static void AddInteractTranslations()
{
if (!LocalizedText.mainTable.ContainsKey("INTERACT_SUMMON".ToUpperInvariant()))
{
List<string> value = new List<string>(Enum.GetValues(typeof(Language)).Length)
{
"summon", "invoquer", "evocare", "beschwören", "invocar", "invocar", "invocar", "призывать", "призвати", "召唤",
"召喚", "召喚する", "소환하다", "przyzwać", "çağırmak"
};
LocalizedText.mainTable.Add("INTERACT_SUMMON".ToUpperInvariant(), value);
}
}
}
internal class CallSnailMaster : Action_CallScoutmaster
{
public Action_ReduceUses reduceUsesAction;
public CallSnailMaster()
{
((ItemAction)this).OnCastFinished = true;
}
public override void RunAction()
{
Singleton<SnailMasterManager>.Instance.EnableSnailMode();
if (Singleton<SnailMasterManager>.Instance.IsSnailActivated())
{
((ItemActionBase)this).item.UIData.hasMainInteract = false;
((ItemActionBase)reduceUsesAction).RunAction();
}
}
}
internal class RunStartPatch
{
[HarmonyPatch(typeof(RunManager), "StartRun")]
[HarmonyPrefix]
private static void DisableSnailMode()
{
Singleton<SnailMasterManager>.Instance.DisableSnailMode();
}
}
internal class ScoutMasterPatch
{
[ThreadStatic]
private static bool CanSwitchTeleport;
[HarmonyPatch(typeof(Scoutmaster), "Chase")]
[HarmonyTranspiler]
private static IEnumerable<CodeInstruction> RemoveSprint(IEnumerable<CodeInstruction> instructions, ILGenerator il)
{
//IL_00fc: Unknown result type (might be due to invalid IL or missing references)
//IL_0102: Expected O, but got Unknown
//IL_010b: Unknown result type (might be due to invalid IL or missing references)
//IL_0111: Expected O, but got Unknown
//IL_011e: Unknown result type (might be due to invalid IL or missing references)
//IL_0124: Expected O, but got Unknown
List<CodeInstruction> list = new List<CodeInstruction>(instructions);
int num = -1;
int num2 = -1;
for (int i = 0; i < list.Count; i++)
{
if (list[i].opcode == OpCodes.Ldarg_0)
{
num = i;
}
else if (list[i].opcode == OpCodes.Stfld && (FieldInfo)list[i].operand == AccessTools.Field(typeof(CharacterInput), "sprintIsPressed"))
{
num2 = i;
break;
}
}
if (num == -1 || num2 == -1)
{
Plugin.Logger.LogError((object)"[Transpiler] Failed to find sprintIsSpressed assignment...");
return instructions;
}
Label label = il.DefineLabel();
list[num2 + 1].labels.Add(label);
MethodInfo methodInfo = AccessTools.PropertyGetter(typeof(SnailMasterManager), "Instance");
MethodInfo methodInfo2 = AccessTools.Method(typeof(SnailMasterManager), "IsSnailActivated", (Type[])null, (Type[])null);
list.InsertRange(num, (IEnumerable<CodeInstruction>)(object)new CodeInstruction[3]
{
new CodeInstruction(OpCodes.Call, (object)methodInfo),
new CodeInstruction(OpCodes.Call, (object)methodInfo2),
new CodeInstruction(OpCodes.Brtrue, (object)label)
});
return list;
}
[HarmonyPatch(typeof(Scoutmaster), "Update")]
[HarmonyTranspiler]
private static IEnumerable<CodeInstruction> SetTeleportDistance(IEnumerable<CodeInstruction> instructions)
{
//IL_010d: Unknown result type (might be due to invalid IL or missing references)
//IL_0113: Expected O, but got Unknown
//IL_011c: Unknown result type (might be due to invalid IL or missing references)
//IL_0122: Expected O, but got Unknown
//IL_0139: Unknown result type (might be due to invalid IL or missing references)
//IL_013f: Expected O, but got Unknown
//IL_0147: Unknown result type (might be due to invalid IL or missing references)
//IL_014d: Expected O, but got Unknown
//IL_015a: Unknown result type (might be due to invalid IL or missing references)
//IL_0160: Expected O, but got Unknown
List<CodeInstruction> list = new List<CodeInstruction>(instructions);
int num = -1;
for (int i = 2; i < list.Count; i++)
{
if (list[i].opcode == OpCodes.Ldc_R4 && list[i - 1].opcode == OpCodes.Ldfld && (FieldInfo)list[i - 1].operand == AccessTools.Field(typeof(Scoutmaster), "distanceToTarget"))
{
num = i;
break;
}
}
if (num == -1)
{
Plugin.Logger.LogError((object)"[Transpiler] Failed to find distanceCheck...");
return instructions;
}
list[num].operand = SnailMasterConfig.TeleportDistance.Value / CharacterStats.unitsToMeters;
Label label = (Label)list[num + 1].operand;
FieldInfo fieldInfo = AccessTools.Field(typeof(SnailMasterConfig), "TeleportMode");
MethodInfo methodInfo = AccessTools.PropertyGetter(typeof(ConfigEntry<TeleportModeSelection>), "Value");
list.InsertRange(num + 2, (IEnumerable<CodeInstruction>)(object)new CodeInstruction[5]
{
new CodeInstruction(OpCodes.Ldsfld, (object)fieldInfo),
new CodeInstruction(OpCodes.Callvirt, (object)methodInfo),
new CodeInstruction(OpCodes.Ldc_I4, (object)Convert.ToInt32(TeleportModeSelection.Never)),
new CodeInstruction(OpCodes.Ceq, (object)null),
new CodeInstruction(OpCodes.Brtrue, (object)label)
});
return list;
}
[HarmonyPatch(typeof(Scoutmaster), "TeleportCloseToTarget")]
[HarmonyPrefix]
private static bool TeleportMasterPrefix(Scoutmaster __instance)
{
if (!EnforceTeleportModes(__instance))
{
return false;
}
bool flag = ConfigureTeleportDistance(__instance);
if (!flag)
{
return false;
}
return flag;
}
private static bool EnforceTeleportModes(Scoutmaster __instance)
{
if (!Singleton<SnailMasterManager>.Instance.IsSnailActivated())
{
return true;
}
if (SnailMasterConfig.TeleportMode.Value != TeleportModeSelection.OnTargetSwitch || CanSwitchTeleport)
{
CanSwitchTeleport = false;
return true;
}
__instance.Chase();
return false;
}
private static bool ConfigureTeleportDistance(Scoutmaster __instance)
{
if (!Singleton<SnailMasterManager>.Instance.IsSnailActivated())
{
return true;
}
__instance.Teleport(__instance.currentTarget, SnailMasterConfig.SpawnMinDistance.Value / CharacterStats.unitsToMeters, SnailMasterConfig.SpawnMaxDistance.Value / CharacterStats.unitsToMeters, SnailMasterConfig.SpawnMaxHeightDifference.Value / CharacterStats.unitsToMeters);
return false;
}
[HarmonyPatch(typeof(Scoutmaster), "ClimbTowards")]
[HarmonyPrefix]
private static void ModifyClimbSpeed(ref float mult)
{
if (Singleton<SnailMasterManager>.Instance.IsSnailActivated())
{
mult *= SnailMasterConfig.ClimbSpeed.Value;
}
}
[HarmonyPatch(typeof(Scoutmaster), "EvasiveBehaviour")]
[HarmonyPrefix]
private static bool ForceAlwaysFollowing()
{
if (!Singleton<SnailMasterManager>.Instance.IsSnailActivated())
{
return true;
}
return false;
}
[HarmonyPatch(typeof(Scoutmaster), "VerifyTarget")]
[HarmonyPrefix]
private static bool ResetTarget(Scoutmaster __instance)
{
CanSwitchTeleport = false;
return SwitchTargets(__instance);
}
[HarmonyPatch(typeof(Scoutmaster), "LookForTarget")]
[HarmonyPrefix]
private static bool SwitchTargets(Scoutmaster __instance)
{
if (!Singleton<SnailMasterManager>.Instance.IsSnailActivated())
{
return true;
}
if (__instance.sinceLookForTarget < SnailMasterConfig.RetargetCooldown.Value || __instance.isThrowing)
{
return false;
}
AssignNewTarget(__instance);
return false;
}
public static void AssignNewTarget(Scoutmaster __instance)
{
//IL_003c: Unknown result type (might be due to invalid IL or missing references)
__instance.sinceLookForTarget = 0f;
Character val = null;
switch (SnailMasterConfig.ChaseMode.Value)
{
case PlayerChaseSelection.Highest:
val = __instance.GetHighestCharacter((Character)null);
break;
case PlayerChaseSelection.Closest:
val = GetClosestCharacter(__instance.character.Center);
break;
case PlayerChaseSelection.Random:
val = GetRandomCharacter();
break;
}
CanSwitchTeleport = (Object)(object)val != (Object)(object)__instance.currentTarget;
Plugin.Logger.LogDebug((object)$"New target selected. Teleport is allowed? {CanSwitchTeleport}");
__instance.SetCurrentTarget(val, 0f);
}
public static Character? GetClosestCharacter(Vector3 position)
{
//IL_006a: 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_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_004e: 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_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)
List<Character> allCharacters = Character.AllCharacters;
Character val = null;
float num = float.MaxValue;
foreach (Character item in allCharacters)
{
if (item.isBot || item.data.dead || item.data.fullyPassedOut)
{
continue;
}
Vector3 val2;
if (!((Object)(object)val == (Object)null))
{
val2 = position - item.Center;
if (!(((Vector3)(ref val2)).sqrMagnitude < num))
{
continue;
}
}
val = item;
val2 = position - item.Center;
num = ((Vector3)(ref val2)).sqrMagnitude;
}
return val;
}
public static Character? GetRandomCharacter()
{
List<Character> list = Character.AllCharacters.Where((Character player) => !player.isBot && !player.data.dead && !player.data.fullyPassedOut).ToList();
if (list.Count <= 0)
{
return null;
}
int index = Random.Range(0, list.Count);
return list[index];
}
}
internal class SnailMasterMovementPatch
{
[HarmonyPatch(typeof(Character), "CalculateWorldMovementDir")]
[HarmonyTranspiler]
private static IEnumerable<CodeInstruction> ScaleSnailMovement(IEnumerable<CodeInstruction> instructions, ILGenerator il)
{
List<CodeInstruction> list = new List<CodeInstruction>(instructions);
int num = -1;
for (int i = 10; i < list.Count; i++)
{
if (IsLerpAssignment(list, i))
{
num = i - 10;
break;
}
}
if (num == -1)
{
Plugin.Logger.LogError((object)"[Transpiler] Failed to find movement assignment");
return instructions;
}
if (list[num - 1].opcode != OpCodes.Stloc && list[num - 1].opcode != OpCodes.Stloc_S)
{
Plugin.Logger.LogError((object)$"[Transpiler] Failed to find local movement vector assignment (have {list[num - 1]})");
return instructions;
}
LocalBuilder movementVector = (LocalBuilder)list[num - 1].operand;
Label label = il.DefineLabel();
List<Label> collection = new List<Label>(list[num].labels);
list[num].labels.RemoveAll((Label lbl) => true);
list[num].labels.Add(label);
list.InsertRange(num, CreateVectorScaler(movementVector));
IEnumerable<CodeInstruction> enumerable = CreateSnailCheck(label);
enumerable.First().labels.AddRange(collection);
list.InsertRange(num, enumerable);
return list;
}
private static IEnumerable<CodeInstruction> CreateVectorScaler(LocalBuilder movementVector)
{
//IL_006e: Unknown result type (might be due to invalid IL or missing references)
//IL_0074: Expected O, but got Unknown
//IL_007c: Unknown result type (might be due to invalid IL or missing references)
//IL_0082: Expected O, but got Unknown
//IL_008a: Unknown result type (might be due to invalid IL or missing references)
//IL_0090: Expected O, but got Unknown
//IL_0098: Unknown result type (might be due to invalid IL or missing references)
//IL_009e: Expected O, but got Unknown
//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
//IL_00ac: Expected O, but got Unknown
FieldInfo fieldInfo = AccessTools.Field(typeof(SnailMasterConfig), "WalkSpeed");
MethodInfo methodInfo = AccessTools.PropertyGetter(typeof(ConfigEntry<float>), "Value");
MethodInfo methodInfo2 = AccessTools.Method(typeof(Vector3), "op_Multiply", new Type[2]
{
typeof(Vector3),
typeof(float)
}, (Type[])null);
return (IEnumerable<CodeInstruction>)(object)new CodeInstruction[5]
{
new CodeInstruction(OpCodes.Ldloc_S, (object)movementVector),
new CodeInstruction(OpCodes.Ldsfld, (object)fieldInfo),
new CodeInstruction(OpCodes.Callvirt, (object)methodInfo),
new CodeInstruction(OpCodes.Call, (object)methodInfo2),
new CodeInstruction(OpCodes.Stloc_S, (object)movementVector)
};
}
private static IEnumerable<CodeInstruction> CreateSnailCheck(Label labelToEscapeTo)
{
//IL_004f: Unknown result type (might be due to invalid IL or missing references)
//IL_0055: Expected O, but got Unknown
//IL_005d: Unknown result type (might be due to invalid IL or missing references)
//IL_0063: Expected O, but got Unknown
//IL_0070: Unknown result type (might be due to invalid IL or missing references)
//IL_0076: Expected O, but got Unknown
//IL_007e: Unknown result type (might be due to invalid IL or missing references)
//IL_0084: Expected O, but got Unknown
//IL_008c: Unknown result type (might be due to invalid IL or missing references)
//IL_0092: Expected O, but got Unknown
//IL_009f: Unknown result type (might be due to invalid IL or missing references)
//IL_00a5: Expected O, but got Unknown
FieldInfo fieldInfo = AccessTools.Field(typeof(Character), "isBot");
MethodInfo methodInfo = AccessTools.PropertyGetter(typeof(SnailMasterManager), "Instance");
MethodInfo methodInfo2 = AccessTools.Method(typeof(SnailMasterManager), "IsSnailActivated", (Type[])null, (Type[])null);
return (IEnumerable<CodeInstruction>)(object)new CodeInstruction[6]
{
new CodeInstruction(OpCodes.Ldarg_0, (object)null),
new CodeInstruction(OpCodes.Ldfld, (object)fieldInfo),
new CodeInstruction(OpCodes.Brfalse, (object)labelToEscapeTo),
new CodeInstruction(OpCodes.Call, (object)methodInfo),
new CodeInstruction(OpCodes.Call, (object)methodInfo2),
new CodeInstruction(OpCodes.Brfalse, (object)labelToEscapeTo)
};
}
private static bool IsLerpAssignment(List<CodeInstruction> code, int index)
{
if (code.Count < 10 || index < 10)
{
return false;
}
FieldInfo fieldInfo = AccessTools.Field(typeof(CharacterData), "worldMovementInput_Lerp");
if (code[index].opcode == OpCodes.Stfld && (FieldInfo)code[index].operand == fieldInfo && code[index - 10].opcode == OpCodes.Ldarg_0)
{
return code[index - 8].opcode == OpCodes.Ldarg_0;
}
return false;
}
}
}
namespace System.Runtime.CompilerServices
{
[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
internal sealed class IgnoresAccessChecksToAttribute : Attribute
{
public IgnoresAccessChecksToAttribute(string assemblyName)
{
}
}
}