using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using Cleverous.Prodigy;
using Cleverous.Prodigy.Input;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Tableflip;
using UnityEngine;
using UnityEngine.AI;
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.Controls;
using UnityEngine.InputSystem.Utilities;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("PartGhost")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyCopyright("Copyright (c) 2026 PartGhost")]
[assembly: AssemblyFileVersion("0.1.1.0")]
[assembly: AssemblyInformationalVersion("0.1.1")]
[assembly: AssemblyProduct("PartGhost.FateWASD")]
[assembly: AssemblyTitle("PartGhost.FateWASD")]
[assembly: AssemblyVersion("0.1.1.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
[CompilerGenerated]
[Embedded]
internal sealed class EmbeddedAttribute : Attribute
{
}
}
namespace System.Runtime.CompilerServices
{
[CompilerGenerated]
[Embedded]
[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
internal sealed class RefSafetyRulesAttribute : Attribute
{
public readonly int Version;
public RefSafetyRulesAttribute(int P_0)
{
Version = P_0;
}
}
}
namespace PartGhost.FateControls
{
internal static class ControlsCommon
{
internal sealed class LegacyGate
{
private readonly MethodBase target;
private readonly string patch;
private float nextCheck = float.NegativeInfinity;
internal bool Owns { get; private set; } = true;
internal LegacyGate(Type gameType, string method, string patch)
{
target = AccessTools.Method(gameType, method, (Type[])null, (Type[])null);
this.patch = patch;
}
internal void Refresh()
{
if (!(Time.unscaledTime < nextCheck))
{
nextCheck = Time.unscaledTime + 1f;
Patches val = ((target == null) ? null : Harmony.GetPatchInfo(target));
Owns = val == null || !val.Prefixes.Concat(val.Postfixes).Any((Patch p) => p.owner == "local.fatecoop.prototype" && p.PatchMethod.Name == patch);
}
}
}
private static Type rebindApi;
private static Func<bool> rebindBlocked;
private static FieldInfo legacyActive;
private static FieldInfo legacyDowned;
private static bool dependenciesDirty;
internal static Type Api => rebindApi;
internal static bool Blocked
{
get
{
if (!InputBlocker.AnyBlockingUiMenuIsOpen && !InventoryUI.IsDraggingItem && !LegacyDowned)
{
return rebindBlocked?.Invoke() ?? false;
}
return true;
}
}
private static bool LegacyDowned
{
get
{
if (legacyActive == null || legacyDowned == null)
{
return false;
}
object value = legacyActive.GetValue(null);
if (value != null)
{
return (bool)legacyDowned.GetValue(value);
}
return false;
}
}
static ControlsCommon()
{
dependenciesDirty = true;
AppDomain.CurrentDomain.AssemblyLoad += AssemblyLoaded;
}
private static void AssemblyLoaded(object sender, AssemblyLoadEventArgs e)
{
dependenciesDirty = true;
}
internal static void Prepare()
{
if (dependenciesDirty)
{
dependenciesDirty = false;
Type type = null;
rebindApi = null;
Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
foreach (Assembly assembly in assemblies)
{
rebindApi = rebindApi ?? assembly.GetType("ZombieGhost.Rebind.RebindApi", throwOnError: false);
type = type ?? assembly.GetType("FateCoop.Prototype.Plugin", throwOnError: false);
}
MethodInfo methodInfo = rebindApi?.GetProperty("IsInputBlocked")?.GetGetMethod();
rebindBlocked = ((methodInfo == null) ? null : ((Func<bool>)Delegate.CreateDelegate(typeof(Func<bool>), methodInfo)));
legacyActive = ((type == null) ? null : AccessTools.Field(type, "Active"));
legacyDowned = ((type == null) ? null : AccessTools.Field(type, "downed"));
}
}
internal static object Register(string guid, string name, params (string id, InputAction action, string label, string category)[] actions)
{
Type api = Api;
if (api == null)
{
return null;
}
object obj = api.GetMethod("RegisterProvider").Invoke(null, new object[2] { guid, name });
try
{
for (int i = 0; i < actions.Length; i++)
{
(string, InputAction, string, string) tuple = actions[i];
obj.GetType().GetMethod("RegisterAction").Invoke(obj, new object[5] { tuple.Item1, tuple.Item2, tuple.Item3, tuple.Item4, null });
}
return obj;
}
catch
{
(obj as IDisposable)?.Dispose();
throw;
}
}
internal static void Hook(Harmony harmony, Type source, string targetType, string method, string prefix = null, string postfix = null)
{
//IL_0025: 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)
MethodInfo methodInfo = AccessTools.Method(AccessTools.TypeByName(targetType), method, (Type[])null, (Type[])null) ?? throw new MissingMethodException(targetType, method);
harmony.Patch((MethodBase)methodInfo, (prefix == null) ? ((HarmonyMethod)null) : new HarmonyMethod(source, prefix, (Type[])null), (postfix == null) ? ((HarmonyMethod)null) : new HarmonyMethod(source, postfix, (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
}
internal static InputAction Button(string name, string path)
{
//IL_000a: Unknown result type (might be due to invalid IL or missing references)
//IL_000f: Unknown result type (might be due to invalid IL or missing references)
//IL_0016: Expected O, but got Unknown
InputAction val = new InputAction(name, (InputActionType)1, path, (string)null, (string)null, "Button");
val.Enable();
return val;
}
}
[BepInPlugin("partghost.fate.wasd", "FATE WASD", "0.1.1")]
public sealed class MovementPlugin : BaseUnityPlugin
{
public const string Guid = "partghost.fate.wasd";
private static MovementPlugin active;
private Harmony harmony;
private InputAction up;
private InputAction down;
private InputAction left;
private InputAction right;
private object provider;
private bool moving;
private bool legacyWarned;
private ControlsCommon.LegacyGate legacy;
private InputAction[] movementActions;
private InputAction rotateAction;
private InputAction zoomAction;
private bool cameraBindingsDirty = true;
private readonly HashSet<string> usedKeys = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
private readonly Dictionary<InputAction, Dictionary<int, string>> suppressed = new Dictionary<InputAction, Dictionary<int, string>>();
private static readonly FieldRef<InputBroker, NavMeshAgent> Agent = AccessTools.FieldRefAccess<InputBroker, NavMeshAgent>("m_navMeshAgent");
private static readonly FieldRef<InputBroker, bool> Locked = AccessTools.FieldRefAccess<InputBroker, bool>("movementLocked");
private static readonly FieldRef<InputBroker, bool> Attack = AccessTools.FieldRefAccess<InputBroker, bool>("attackWhenInRange");
private static readonly FieldRef<InputBroker, bool> Interact = AccessTools.FieldRefAccess<InputBroker, bool>("interactWhenInRange");
private static readonly FieldRef<ProdigyPlayer, PlayerInput> PlayerInputRef = AccessTools.FieldRefAccess<ProdigyPlayer, PlayerInput>("m_currentInput");
private static readonly MethodInfo Behavior = AccessTools.PropertySetter(typeof(InputBroker), "LocalInputBehavior");
private void Awake()
{
//IL_00e3: Unknown result type (might be due to invalid IL or missing references)
//IL_00ed: Expected O, but got Unknown
if (!((BaseUnityPlugin)this).Config.Bind<bool>("Controls", "Enabled", true, "Enable camera-relative keyboard movement.").Value)
{
return;
}
active = this;
up = ControlsCommon.Button("move.up", "<Keyboard>/w");
down = ControlsCommon.Button("move.down", "<Keyboard>/s");
left = ControlsCommon.Button("move.left", "<Keyboard>/a");
right = ControlsCommon.Button("move.right", "<Keyboard>/d");
movementActions = (InputAction[])(object)new InputAction[4] { up, down, left, right };
legacy = new ControlsCommon.LegacyGate(typeof(InputBroker), "ParseClickToMove", "BeforeClickToMove");
InputSystem.onActionChange += ActionChanged;
harmony = new Harmony("partghost.fate.wasd");
try
{
ControlsCommon.Hook(harmony, typeof(MovementPlugin), typeof(InputBroker).FullName, "ReadPressedInputs", null, "Read");
ControlsCommon.Hook(harmony, typeof(MovementPlugin), typeof(InputBroker).FullName, "ParseClickToMove", "Move");
ControlsCommon.Hook(harmony, typeof(MovementPlugin), typeof(ProdigyPlayer).FullName, "LocalClientCollectInput", "Collect");
((BaseUnityPlugin)this).Logger.LogInfo((object)"FATE WASD 0.1.1 ready; standalone controls.");
}
catch (Exception ex)
{
harmony.UnpatchSelf();
Shutdown();
((BaseUnityPlugin)this).Logger.LogError((object)ex);
}
}
private bool Owns()
{
if (legacy.Owns)
{
return true;
}
if (!legacyWarned)
{
legacyWarned = true;
((BaseUnityPlugin)this).Logger.LogWarning((object)"Original co-op controls are installed. Standalone WASD suspended; set its Controls.KeyboardMovement=false and restart to use standalone controls.");
}
return false;
}
private static void Read(InputBroker __instance)
{
//IL_00e5: 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_0133: Unknown result type (might be due to invalid IL or missing references)
//IL_0138: 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_0142: 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)
MovementPlugin movementPlugin = active;
if (movementPlugin == null)
{
return;
}
ControlsCommon.Prepare();
movementPlugin.legacy.Refresh();
if (!movementPlugin.Owns())
{
return;
}
if (movementPlugin.provider == null && ControlsCommon.Api != null)
{
movementPlugin.provider = ControlsCommon.Register("partghost.fate.wasd", "WASD Movement", ("up", movementPlugin.up, "Move up", "Movement"), ("down", movementPlugin.down, "Move down", "Movement"), ("left", movementPlugin.left, "Move left", "Movement"), ("right", movementPlugin.right, "Move right", "Movement"));
}
movementPlugin.ReserveCameraKeys(__instance);
if ((int)__instance.LocalInputBehavior != 0)
{
return;
}
Keyboard current = Keyboard.current;
if (current == null || !((ButtonControl)current.anyKey).wasPressedThisFrame)
{
return;
}
Behavior.Invoke(__instance, new object[1] { (object)(InputBehavior)1 });
Enumerator<InputControlScheme> enumerator = __instance.Inputs.controlSchemes.GetEnumerator();
try
{
while (enumerator.MoveNext())
{
InputControlScheme current2 = enumerator.Current;
if (((InputControlScheme)(ref current2)).name.IndexOf("keyboard", StringComparison.OrdinalIgnoreCase) >= 0)
{
__instance.Inputs.bindingMask = InputBinding.MaskByGroup(((InputControlScheme)(ref current2)).bindingGroup);
break;
}
}
}
finally
{
((IDisposable)enumerator/*cast due to .constrained prefix*/).Dispose();
}
__instance.OnInputBehaviorChanged?.Invoke((InputBehavior)1);
}
private void ActionChanged(object changed, InputActionChange change)
{
//IL_0000: Unknown result type (might be due to invalid IL or missing references)
//IL_0002: Invalid comparison between Unknown and I4
if ((int)change == 8)
{
cameraBindingsDirty = true;
}
}
private void ReserveCameraKeys(InputBroker broker)
{
//IL_0006: 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_001a: Unknown result type (might be due to invalid IL or missing references)
//IL_001f: Unknown result type (might be due to invalid IL or missing references)
//IL_0073: Unknown result type (might be due to invalid IL or missing references)
//IL_0078: Unknown result type (might be due to invalid IL or missing references)
//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_0087: Unknown result type (might be due to invalid IL or missing references)
//IL_008c: Unknown result type (might be due to invalid IL or missing references)
CharacterInputsActions characterInputs = broker.Inputs.CharacterInputs;
InputAction cameraRotate = ((CharacterInputsActions)(ref characterInputs)).CameraRotate;
characterInputs = broker.Inputs.CharacterInputs;
InputAction cameraZoom = ((CharacterInputsActions)(ref characterInputs)).CameraZoom;
if (cameraRotate != rotateAction || cameraZoom != zoomAction)
{
rotateAction = cameraRotate;
zoomAction = cameraZoom;
cameraBindingsDirty = true;
}
if (!cameraBindingsDirty)
{
return;
}
usedKeys.Clear();
InputAction[] array = movementActions;
for (int i = 0; i < array.Length; i++)
{
Enumerator<InputBinding> enumerator = array[i].bindings.GetEnumerator();
try
{
while (enumerator.MoveNext())
{
InputBinding current = enumerator.Current;
if (!string.IsNullOrEmpty(((InputBinding)(ref current)).effectivePath))
{
usedKeys.Add(((InputBinding)(ref current)).effectivePath);
}
}
}
finally
{
((IDisposable)enumerator/*cast due to .constrained prefix*/).Dispose();
}
}
UpdateCameraAction(cameraRotate);
UpdateCameraAction(cameraZoom);
cameraBindingsDirty = false;
}
private void UpdateCameraAction(InputAction action)
{
//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
//IL_002b: Unknown result type (might be due to invalid IL or missing references)
//IL_0030: 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_003a: Unknown result type (might be due to invalid IL or missing references)
if (!suppressed.TryGetValue(action, out var value))
{
value = (suppressed[action] = new Dictionary<int, string>());
}
for (int i = 0; i < action.bindings.Count; i++)
{
InputBinding val = action.bindings[i];
string value2;
string text = (value.TryGetValue(i, out value2) ? (value2 ?? ((InputBinding)(ref val)).path) : ((InputBinding)(ref val)).effectivePath);
if (usedKeys.Contains(text ?? "") && (text ?? "").StartsWith("<Keyboard>", StringComparison.OrdinalIgnoreCase))
{
if (!value.ContainsKey(i))
{
value[i] = ((InputBinding)(ref val)).overridePath;
InputActionRebindingExtensions.ApplyBindingOverride(action, i, "");
}
}
else
{
if (!value.ContainsKey(i))
{
continue;
}
if (((InputBinding)(ref val)).overridePath == "")
{
if (value2 == null)
{
InputActionRebindingExtensions.RemoveBindingOverride(action, i);
}
else
{
InputActionRebindingExtensions.ApplyBindingOverride(action, i, value2);
}
}
value.Remove(i);
}
}
}
private static void Move(InputBroker __instance)
{
//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
//IL_00a7: Invalid comparison between Unknown and I4
//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
//IL_00b0: Invalid comparison between Unknown and I4
//IL_0111: Unknown result type (might be due to invalid IL or missing references)
//IL_0116: Unknown result type (might be due to invalid IL or missing references)
//IL_011b: Unknown result type (might be due to invalid IL or missing references)
//IL_0120: 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_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_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_0149: Unknown result type (might be due to invalid IL or missing references)
//IL_014e: 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)
//IL_0159: Unknown result type (might be due to invalid IL or missing references)
//IL_0163: Unknown result type (might be due to invalid IL or missing references)
//IL_0168: Unknown result type (might be due to invalid IL or missing references)
//IL_0170: Unknown result type (might be due to invalid IL or missing references)
//IL_0175: Unknown result type (might be due to invalid IL or missing references)
//IL_017c: Unknown result type (might be due to invalid IL or missing references)
//IL_0181: Unknown result type (might be due to invalid IL or missing references)
//IL_01b3: Unknown result type (might be due to invalid IL or missing references)
MovementPlugin movementPlugin = active;
if (movementPlugin == null || !movementPlugin.Owns())
{
return;
}
Player playerChar = Player.PlayerChar;
NavMeshAgent val = Agent.Invoke(__instance);
if ((Object)(object)playerChar == (Object)null || (Object)(object)val == (Object)null || !((Behaviour)val).enabled || !val.isOnNavMesh)
{
return;
}
Vector2 val2 = default(Vector2);
((Vector2)(ref val2))..ctor((float)((movementPlugin.right.IsPressed() ? 1 : 0) - (movementPlugin.left.IsPressed() ? 1 : 0)), (float)((movementPlugin.up.IsPressed() ? 1 : 0) - (movementPlugin.down.IsPressed() ? 1 : 0)));
if (!(((Vector2)(ref val2)).sqrMagnitude > 0.01f) || ControlsCommon.Blocked || (int)__instance.LocalInputBehavior != 1 || (int)__instance.ActiveInputMode != 2 || Locked.Invoke(__instance) || ((Character)playerChar).PerformingAttack() || ((Character)playerChar).PerformingCast() || ((Character)playerChar).Fishing())
{
if (movementPlugin.moving)
{
val.ResetPath();
}
movementPlugin.moving = false;
return;
}
Camera gameCamera = ProdigyCamera.GameCamera;
if (!((Object)(object)gameCamera == (Object)null))
{
Transform transform = ((Component)gameCamera).transform;
Vector3 val3 = Vector3.ProjectOnPlane(transform.forward, Vector3.up);
Vector3 val4 = ((Vector3)(ref val3)).normalized * val2.y;
val3 = Vector3.ProjectOnPlane(transform.right, Vector3.up);
Vector3 val5 = Vector3.ClampMagnitude(val4 + ((Vector3)(ref val3)).normalized * val2.x, 1f);
NavMeshHit val6 = default(NavMeshHit);
if (NavMesh.SamplePosition(((Component)playerChar).transform.position + val5 * 1.5f, ref val6, 1.5f, -1))
{
Attack.Invoke(__instance) = false;
Interact.Invoke(__instance) = false;
__instance.SetMoveDestination(((NavMeshHit)(ref val6)).position);
movementPlugin.moving = true;
}
}
}
private static bool Collect(ProdigyPlayer __instance)
{
//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_005d: 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)
//IL_005f: Unknown result type (might be due to invalid IL or missing references)
MovementPlugin movementPlugin = active;
if (movementPlugin == null || !movementPlugin.Owns() || !movementPlugin.moving || !InputBlocker.Blocked)
{
return true;
}
InputBroker instance = SingletonBehaviour<InputBroker>.Instance;
if ((Object)(object)instance == (Object)null)
{
return true;
}
NavMeshAgent val = Agent.Invoke(instance);
if ((Object)(object)val == (Object)null)
{
return true;
}
Vector3 desiredVelocity = val.desiredVelocity;
((PlayerInput)(ref PlayerInputRef.Invoke(__instance))).Set(desiredVelocity, desiredVelocity, desiredVelocity, false, false, false, false, false, false);
return false;
}
private void Shutdown()
{
//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
//IL_00be: Unknown result type (might be due to invalid IL or missing references)
//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
InputSystem.onActionChange -= ActionChanged;
(provider as IDisposable)?.Dispose();
provider = null;
InputAction[] array = (InputAction[])(object)new InputAction[4] { up, down, left, right };
foreach (InputAction obj in array)
{
if (obj != null)
{
obj.Dispose();
}
}
foreach (KeyValuePair<InputAction, Dictionary<int, string>> item in suppressed)
{
foreach (KeyValuePair<int, string> item2 in item.Value)
{
InputBinding val = item.Key.bindings[item2.Key];
if (((InputBinding)(ref val)).overridePath == "")
{
if (item2.Value == null)
{
InputActionRebindingExtensions.RemoveBindingOverride(item.Key, item2.Key);
}
else
{
InputActionRebindingExtensions.ApplyBindingOverride(item.Key, item2.Key, item2.Value);
}
}
}
}
suppressed.Clear();
active = null;
}
private void OnApplicationQuit()
{
Harmony obj = harmony;
if (obj != null)
{
obj.UnpatchSelf();
}
Shutdown();
}
}
}