8de369869f
Ground-up reimplementation of yox92/SmartAction targeting SPT 4.0.13 / EFT 0.16.9.0.40087. Only the walk-while-healing feature is implemented; see NOTES.md for status and the deferred sprint work. Design departures from upstream: - CanWalk is a guarded postfix, not a transpiler. Upstream rewrote the method body, which affects every MovementContext in the raid including bots, and is hard-incompatible with the three other mods already patching MovementContext in a typical load order (SAIN, ORBIT, maschine-DualSideDoorBreach). A postfix that only flips false -> true for IsYourPlayer is inert for other entities by construction. - The postfix re-tests ObstacleCollisionFacade_1.CanMove() before lifting. Upstream's transpiler dropped that check along with the HealingLegs check, silently disabling obstacle blocking. - Targets resolve by name via AccessTools.PropertyGetter + nameof rather than by GClass number, so they survive EFT version bumps. Verified in-game against 78 loaded plugins: both patches attach, the guard rejected 985 non-local MovementContext calls with zero leaks, and _player was never null across ~4000 guard calls. CanSprintPatch is parked in deferred/ rather than deleted: MovementContext.CanSprint does not gate sprinting (EnableSprint calls Physical.Sprint unconditionally), and forcing it true makes EnableSprint run ForceStopInteractions()/RemoveLeftHandItem() mid-heal. Details and the 3.11 -> 4.0.13 rename table are in NOTES.md. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
60 lines
2.0 KiB
C#
60 lines
2.0 KiB
C#
using System.Reflection;
|
|
using EFT;
|
|
using HarmonyLib;
|
|
using SPT.Reflection.Patching;
|
|
|
|
namespace SmartAction.Patch;
|
|
|
|
/// <summary>
|
|
/// Lets you walk while healing a leg.
|
|
///
|
|
/// Vanilla MovementContext.CanWalk (EFT 0.16.9.0.40087):
|
|
/// if (PhysicalConditionIs(HealingLegs)) return false;
|
|
/// if (!ObstacleCollisionFacade_1.CanMove()) return false;
|
|
/// return true;
|
|
///
|
|
/// Upstream SmartAction replaced this body with a transpiler, which rewrote the method for
|
|
/// every MovementContext in the raid — bots included — and dropped the obstacle check along
|
|
/// with the HealingLegs check. A postfix that only ever flips false -> true is per-instance,
|
|
/// composes with other movement mods, needs no IL matching, and keeps CanMove() intact.
|
|
/// </summary>
|
|
public class CanWalkPatch : ModulePatch
|
|
{
|
|
protected override MethodBase GetTargetMethod()
|
|
{
|
|
return AccessTools.PropertyGetter(typeof(MovementContext), nameof(MovementContext.CanWalk));
|
|
}
|
|
|
|
[PatchPostfix]
|
|
private static void Postfix(MovementContext __instance, ref bool __result)
|
|
{
|
|
// Never grant movement vanilla already allows, and never take it away.
|
|
if (__result) return;
|
|
|
|
if (!MovementPatchUtil.IsLocalPlayer(__instance)) return;
|
|
|
|
// Only intervene when healing is the reason we were blocked.
|
|
if (!__instance.PhysicalConditionIs(EPhysicalCondition.HealingLegs)) return;
|
|
|
|
// The other vanilla blocker still applies: if something is physically in the way,
|
|
// leave the false alone. (Null facade -> treat as blocked.)
|
|
if (__instance.ObstacleCollisionFacade_1?.CanMove() != true)
|
|
{
|
|
if (Diagnostics.Enabled)
|
|
{
|
|
Diagnostics.WalkHeldByObstacle++;
|
|
Diagnostics.OnceWalkHeldByObstacle();
|
|
}
|
|
return;
|
|
}
|
|
|
|
__result = true;
|
|
|
|
if (Diagnostics.Enabled)
|
|
{
|
|
Diagnostics.WalkLifted++;
|
|
Diagnostics.OnceWalkLifted();
|
|
}
|
|
}
|
|
}
|