Initial import of IC.Rebuild
This commit is contained in:
@@ -0,0 +1,133 @@
|
||||
using Dalamud.Hooking;
|
||||
using ICRebuild.Core;
|
||||
|
||||
namespace ICRebuild.Runtime;
|
||||
|
||||
public sealed unsafe class MovementModules(GameContext game, Configuration config, ModuleManager modules)
|
||||
{
|
||||
private delegate nint Move(nuint actor, nint data, uint arg);
|
||||
private delegate float Speed(long actor);
|
||||
private delegate void Acceleration(long actor);
|
||||
private delegate long Permission(long a1, uint a2, int a3, int a4);
|
||||
private delegate long Knock(long actor, float angle, float distance, float seconds, byte a5, long a6);
|
||||
private delegate nint Fall(nuint a1, uint flags);
|
||||
private delegate long FallCheck(long a1, long a2, long a3);
|
||||
private delegate nint Forced(nint actor, float x, float y, float z, float movementParameter, nint options);
|
||||
[ThreadStatic] private static HashSet<nint>? adjusted;
|
||||
public HeightActivation Height { get; } = new();
|
||||
public float EffectiveHeight => !modules.IsEnabled(9) ? 0 : Policies.HeightDelta(game.Ready,modules.IsEnabled(10),game.ReadDungeon(),Height.Applied);
|
||||
|
||||
public void Register()
|
||||
{
|
||||
modules.Register(11, _ => { });
|
||||
modules.Register(10, _ => { }, 9);
|
||||
modules.Register(9, StartHeight);
|
||||
modules.Register(1, scope =>
|
||||
{
|
||||
Hook<Speed>? hook = null;
|
||||
hook = game.Hook<Speed>(scope, Signatures.SpeedAddress, actor =>
|
||||
{
|
||||
var original = hook!.Original(actor);
|
||||
try
|
||||
{
|
||||
if (!game.Ready || game.IsSlowed) return original;
|
||||
return float.IsFinite(original) ? Math.Max(0, original + config.Value(1)) : original;
|
||||
}
|
||||
catch(Exception ex) { game.Fault(1,ex); return original; }
|
||||
});
|
||||
hook.Enable();
|
||||
});
|
||||
modules.Register(2, scope =>
|
||||
{
|
||||
if(game.GameVersion!=AccelerationPolicy.AuditedVersion) throw new InvalidOperationException("最大加速度仅完成 2026.09.15 客户端的字段核对。");
|
||||
Hook<Acceleration>? hook = null;
|
||||
hook = game.Hook<Acceleration>(scope, "40 ?? 48 ?? ?? ?? 80 79 ?? ?? 48 ?? ?? 0f 84 ?? ?? ?? ?? 48 89 7c 24 ?? 48 ?? ?? ??", actor =>
|
||||
{
|
||||
var frame=game.Frames.Read();
|
||||
if(actor==0 || !frame.Ready || *(byte*)((nint)actor+0x3C)==0) { hook!.Original(actor); return; }
|
||||
var controller=*(nint*)((nint)actor+0x20);
|
||||
var owner=controller==0 ? 0 : *(nint*)(controller+0x3E0);
|
||||
ref var field=ref *(float*)((nint)actor+0x44);
|
||||
var prime=AccelerationPolicy.ShouldPrime(frame,owner,true,field);
|
||||
AccelerationPolicy.Run(ref field,prime,()=>hook!.Original(actor));
|
||||
});
|
||||
hook.Enable();
|
||||
});
|
||||
modules.Register(3, scope =>
|
||||
{
|
||||
Hook<Permission>? hook = null;
|
||||
hook = game.Hook<Permission>(scope, Signatures.MovePermissionAddress, (a1,a2,a3,a4) =>
|
||||
game.Ready && NativeIds.MovementPermissionChecks.Contains(a2) ? 1 : hook!.Original(a1,a2,a3,a4));
|
||||
hook.Enable();
|
||||
});
|
||||
modules.Register(4, scope =>
|
||||
{
|
||||
Hook<Knock>? hook = null;
|
||||
hook = game.Hook<Knock>(scope, Signatures.AntiKnockAddress, (actor,angle,distance,seconds,a5,a6) =>
|
||||
{
|
||||
if (actor != 0 && actor == game.LocalAddress)
|
||||
{ distance = config.Value(4); seconds = config.Published.KnockSeconds; }
|
||||
return hook!.Original(actor,angle,distance,seconds,a5,a6);
|
||||
});
|
||||
hook.Enable();
|
||||
});
|
||||
modules.Register(5, scope =>
|
||||
{
|
||||
Hook<Fall>? hook = null;
|
||||
hook = game.Hook<Fall>(scope, Signatures.OnSendFlag, (a1,flags) => hook!.Original(a1,game.Ready ? Policies.FallFlags(flags) : flags));
|
||||
hook.Enable();
|
||||
});
|
||||
modules.Register(6, scope =>
|
||||
{
|
||||
Hook<FallCheck>? hook = null;
|
||||
hook = game.Hook<FallCheck>(scope, Signatures.FallCheckPatch, (a1,a2,a3) => game.Ready ? -1 : hook!.Original(a1,a2,a3));
|
||||
hook.Enable();
|
||||
});
|
||||
modules.Register(7, scope =>
|
||||
{
|
||||
if(game.GameVersion!=AccelerationPolicy.AuditedVersion) throw new InvalidOperationException("强制移动入口参数仅核对了 2026.09.15 客户端");
|
||||
Hook<Forced>? hook = null;
|
||||
hook = game.Hook<Forced>(scope, Signatures.FuckBewithAction, (actor,x,y,z,movementParameter,options) =>
|
||||
{
|
||||
// This intercepts a forced-coordinate movement path; it does not remove a status.
|
||||
if(actor!=0 && actor==game.LocalAddress) return 0;
|
||||
return hook!.Original(actor,x,y,z,movementParameter,options);
|
||||
});
|
||||
hook.Enable();
|
||||
});
|
||||
}
|
||||
|
||||
private void StartHeight(ResourceScope scope)
|
||||
{
|
||||
Height.Reset();
|
||||
Hook<Move>? normal = null, combat = null;
|
||||
normal = game.Hook<Move>(scope, Signatures.OnSendNormalMove, (actor,data,arg) => ApplyHeight(normal!.Original,actor,data,arg,false));
|
||||
combat = game.Hook<Move>(scope, Signatures.OnSendCombatMove, (actor,data,arg) => ApplyHeight(combat!.Original,actor,data,arg,true));
|
||||
scope.Defer(Height.Reset);
|
||||
normal.Enable(); combat.Enable();
|
||||
}
|
||||
private nint ApplyHeight(Move original, nuint actor, nint data, uint arg, bool combat)
|
||||
{
|
||||
float delta;
|
||||
try
|
||||
{
|
||||
delta=EffectiveHeight;
|
||||
}
|
||||
catch(Exception ex) { game.Fault(9,ex); return original(actor,data,arg); }
|
||||
if (data == 0 || delta == 0) return original(actor,data,arg);
|
||||
adjusted ??= [];
|
||||
if (!adjusted.Add(data)) return original(actor,data,arg);
|
||||
var values = (float*)data;
|
||||
var first = combat ? 4 : 3;
|
||||
float old = values[first], old2 = combat ? values[7] : 0;
|
||||
try
|
||||
{
|
||||
if (!float.IsFinite(old) || (combat && !float.IsFinite(old2))) return original(actor,data,arg);
|
||||
values[first] = old + delta;
|
||||
if (combat) values[7] = old2 + delta;
|
||||
try { return original(actor,data,arg); }
|
||||
finally { values[first] = old; if (combat) values[7] = old2; }
|
||||
}
|
||||
finally { adjusted.Remove(data); }
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user