Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 42 additions & 0 deletions addons/sourcemod/gamedata/movementapi.games.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,24 @@
{
"csgo"
{
"Addresses"
{
"sm_pSingleton"
{
"windows"
{
"signature" "CGameMovement::TryPlayerMove"
"read" "718"
}
"linux"
{
"signature" "CGameMovement::TryPlayerMove"
"read" "483"
}

"read" "0"
}
}
"Keys"
{
"CGameMovement::player" "4"
Expand Down Expand Up @@ -90,6 +108,24 @@
"this" "address"
"return" "void"
}
"CGameMovement::TryPlayerMove"
{
"signature" "CGameMovement::TryPlayerMove"
"callconv" "thiscall"
"this" "address"
"return" "int"
"arguments"
{
"pFirstDest"
{
"type" "vectorptr"
}
"pFirstTrace"
{
"type" "objectptr"
}
}
}
}
"Offsets"
{
Expand Down Expand Up @@ -150,6 +186,12 @@
"windows" "\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\xF9\xC7\x45\x2A\x00\x00\x00\x00\x8B\x47\x2A\xC7\x80"
"linux" "\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x00\x00\x00\xC7\x45\x2A\x00\x00\x00\x00\x8B\x5D\x2A\x8B\x43\x2A\xC7"
}
"CGameMovement::TryPlayerMove"
{
"library" "server"
"windows" "\x55\x8B\xEC\x83\xE4\xF8\x81\xEC\x38\x01\x00\x00\xF3\x0F\x10\x35\x2A\x2A\x2A\x2A"
"linux" "\x55\x66\x0F\xEF\xDB\x89\xE5\x57\x56\x53\x81\xEC\x2A\x2A\x2A\x2A\x8B\x7D\x08"
}
}
}
}
77 changes: 76 additions & 1 deletion addons/sourcemod/scripting/include/movementapi.inc
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,28 @@ forward Action Movement_OnCategorizePositionPre(int client, float origin[3], flo
*/
forward Action Movement_OnCategorizePositionPost(int client, float origin[3], float velocity[3]);

/**
* Called before TryPlayerMove movement function is called.
* Modifying origin or velocity parameters will change player's origin and velocity accordingly.
*
* @param client Client index.
* @param origin Player origin.
* @param velocity Player velocity.
* @return Plugin_Changed if origin or velocity is changed, Plugin_Continue otherwise.
*/
forward Action Movement_OnTryPlayerMovePre(int client, float origin[3], float velocity[3]);

/**
* Called after TryPlayerMove movement function is called.
* Modifying origin or velocity parameters will change player's origin and velocity accordingly.
*
* @param client Client index.
* @param origin Player origin.
* @param velocity Player velocity.
* @return Plugin_Changed if origin or velocity is changed, Plugin_Continue otherwise.
*/
forward Action Movement_OnTryPlayerMovePost(int client, float origin[3], float velocity[3]);

// =====[ NATIVES ]=====

/**
Expand Down Expand Up @@ -484,13 +506,42 @@ native void Movement_SetTakeoffVelocity(int client, float velocity[3]);
*/
native void Movement_SetLandingOrigin(int client, float origin[3]);

/**
* Get the player's number of collisions during movement processing.
* This function should ideally be called after inside Movement_OnTryPlayerMovePost.
*
* @param client Client index.
* @param origin Desired velocity.
*/
native int Movement_GetCollisionCount(int client);

/**
* Set the player's landing velocity.
* This function should ideally be called after inside Movement_OnTryPlayerMovePost.
*
* @param client Client index.
* @param num Collision number, must not exceed Movement_GetCollisionCount's value.
* @param result Resultant vector.
*/
native void Movement_GetCollisionStartOrigin(int client, int num, float result[3]);

/**
* Set the player's landing velocity.
* This function should ideally be called after inside Movement_OnTryPlayerMovePost.
*
* @param client Client index.
* @param origin Desired velocity.
*/
native void Movement_GetCollisionEndOrigin(int client, int num, float result[3]);

/**
* Set the player's landing velocity.
* This function should ideally be called after inside Movement_OnTryPlayerMovePost.
*
* @param client Client index.
* @param origin Desired velocity.
*/
native void Movement_SetLandingVelocity(int client, float velocity[3]);
native void Movement_GetCollisionNormal(int client, int num, float result[3]);

// =====[ METHODMAP ]=====

Expand Down Expand Up @@ -608,6 +659,26 @@ methodmap MovementAPIPlayer < MovementPlayer {
}
}

property int CollisionCount {
public get() {
return Movement_GetCollisionCount(this.ID);
}
}
public void GetCollisionStartOrigin(int num, float buffer[3])
{
Movement_GetCollisionStartOrigin(this.ID, num, buffer);
}

public void GetCollisionEndOrigin(int num, float buffer[3])
{
Movement_GetCollisionEndOrigin(this.ID, num, buffer);
}

public void GetCollisionNormal(int num, float buffer[3])
{
Movement_GetCollisionNormal(this.ID, num, buffer);
}

public void GetProcessingVelocity(float buffer[3])
{
Movement_GetProcessingVelocity(this.ID, buffer);
Expand Down Expand Up @@ -659,5 +730,9 @@ public void __pl_movementapi_SetNTVOptional()
MarkNativeAsOptional("Movement_SetTakeoffVelocity");
MarkNativeAsOptional("Movement_SetLandingOrigin");
MarkNativeAsOptional("Movement_SetLandingVelocity");
MarkNativeAsOptional("Movement_GetCollisionCount");
MarkNativeAsOptional("Movement_GetCollisionStartOrigin");
MarkNativeAsOptional("Movement_GetCollisionEndOrigin");
MarkNativeAsOptional("Movement_GetCollisionNormal");
}
#endif
25 changes: 25 additions & 0 deletions addons/sourcemod/scripting/movementapi/forwards.sp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ static Handle H_OnWalkMovePre;
static Handle H_OnWalkMovePost;
static Handle H_OnCategorizePositionPre;
static Handle H_OnCategorizePositionPost;
static Handle H_OnTryPlayerMovePre;
static Handle H_OnTryPlayerMovePost;

void CreateGlobalForwards()
{
Expand Down Expand Up @@ -54,6 +56,9 @@ void CreateGlobalForwards()

H_OnCategorizePositionPre = CreateGlobalForward("Movement_OnCategorizePositionPre", ET_Event, Param_Cell, Param_Array, Param_Array);
H_OnCategorizePositionPost = CreateGlobalForward("Movement_OnCategorizePositionPost", ET_Event, Param_Cell, Param_Array, Param_Array);

H_OnTryPlayerMovePre = CreateGlobalForward("Movement_OnTryPlayerMovePre", ET_Event, Param_Cell, Param_Array, Param_Array);
H_OnTryPlayerMovePost = CreateGlobalForward("Movement_OnTryPlayerMovePost", ET_Event, Param_Cell, Param_Array, Param_Array);
}

void Call_OnStartDucking(int client)
Expand Down Expand Up @@ -263,4 +268,24 @@ Action Call_OnCategorizePositionPost(int client, float origin[3], float velocity
Call_PushArrayEx(velocity, 3, SM_PARAM_COPYBACK);
Call_Finish(result);
return result;
}

Action Call_OnTryPlayerMovePre(int client, float origin[3], float velocity[3], Action &result)
{
Call_StartForward(H_OnTryPlayerMovePre);
Call_PushCell(client);
Call_PushArrayEx(origin, 3, SM_PARAM_COPYBACK);
Call_PushArrayEx(velocity, 3, SM_PARAM_COPYBACK);
Call_Finish(result);
return result;
}

Action Call_OnTryPlayerMovePost(int client, float origin[3], float velocity[3], Action &result)
{
Call_StartForward(H_OnTryPlayerMovePost);
Call_PushCell(client);
Call_PushArrayEx(origin, 3, SM_PARAM_COPYBACK);
Call_PushArrayEx(velocity, 3, SM_PARAM_COPYBACK);
Call_Finish(result);
return result;
}
84 changes: 83 additions & 1 deletion addons/sourcemod/scripting/movementapi/hooks.sp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ static DynamicDetour H_OnJump;
static DynamicDetour H_OnAirAccelerate;
static DynamicDetour H_OnWalkMove;
static DynamicDetour H_OnCategorizePosition;
static DynamicDetour H_OnTryPlayerMove;
static Address moveHelperAddr;
static bool tryPlayerMoveThisTick;

float gF_Origin[MAXPLAYERS + 1][3];
float gF_Velocity[MAXPLAYERS + 1][3];
Expand All @@ -31,6 +34,12 @@ float gF_PostAAVelocity[MAXPLAYERS + 1][3];

bool gB_OldWalkMoved[MAXPLAYERS + 1];

int gI_CollisionCount[MAXPLAYERS + 1];

float gF_TraceStartOrigin[MAXPLAYERS + 1][MAX_BUMPS][3];
float gF_TraceEndOrigin[MAXPLAYERS + 1][MAX_BUMPS][3];
float gF_TraceNormal[MAXPLAYERS + 1][MAX_BUMPS][3];

void HookGameMovementFunctions()
{
HookGameMovementFunction(H_OnDuck, "CCSGameMovement::Duck", DHooks_OnDuck_Pre, DHooks_OnDuck_Post);
Expand All @@ -41,6 +50,13 @@ void HookGameMovementFunctions()
HookGameMovementFunction(H_OnJump, "CCSGameMovement::OnJump", DHooks_OnJump_Pre, DHooks_OnJump_Post);
HookGameMovementFunction(H_OnPlayerMove, "CCSGameMovement::PlayerMove", DHooks_OnPlayerMove_Pre, DHooks_OnPlayerMove_Post);
HookGameMovementFunction(H_OnCategorizePosition, "CGameMovement::CategorizePosition", DHooks_OnCategorizePosition_Pre, DHooks_OnCategorizePosition_Post);
HookGameMovementFunction(H_OnTryPlayerMove, "CGameMovement::TryPlayerMove", DHooks_OnTryPlayerMove_Pre, DHooks_OnTryPlayerMove_Post);

moveHelperAddr = GameConfGetAddress(gH_GameData, "sm_pSingleton");
if (!moveHelperAddr)
{
SetFailState("Failed to find IMoveHelper::sm_pSingleton.");
}
}

Action UpdateMoveData(Address pThis, int client, Function func)
Expand Down Expand Up @@ -429,7 +445,7 @@ public MRESReturn DHooks_OnPlayerMove_Post(Address pThis)
return MRES_Ignored;
}
Action result = UpdateMoveData(pThis, client, Call_OnPlayerMovePost);

tryPlayerMoveThisTick = false;
if (result != Plugin_Continue)
{
return MRES_Handled;
Expand Down Expand Up @@ -512,8 +528,74 @@ public MRESReturn DHooks_OnCategorizePosition_Post(Address pThis)
}
}

public MRESReturn DHooks_OnTryPlayerMove_Pre(Address pThis, DHookReturn hReturn, DHookParam hParams)
{
int client = GetClientFromGameMovementAddress(pThis);
if (!IsPlayerAlive(client) || IsFakeClient(client))
{
return MRES_Ignored;
}
Action result = UpdateMoveData(pThis, client, Call_OnTryPlayerMovePre);

for (int i = 0; i < MAX_BUMPS; i++)
{
gF_TraceStartOrigin[client][i] = NULL_VECTOR;
gF_TraceEndOrigin[client][i] = NULL_VECTOR;
gF_TraceNormal[client][i] = NULL_VECTOR;
}

if (result != Plugin_Continue)
{
return MRES_Handled;
}
else
{
return MRES_Ignored;
}
}

public MRESReturn DHooks_OnTryPlayerMove_Post(Address pThis, DHookReturn hReturn, DHookParam hParams)
{
int client = GetClientFromGameMovementAddress(pThis);
if (!IsPlayerAlive(client) || IsFakeClient(client))
{
return MRES_Ignored;
}

tryPlayerMoveThisTick = true;
gI_CollisionCount[client] = LoadFromAddress(moveHelperAddr + view_as<Address>(8) + view_as<Address>(12), NumberType_Int32);

Address m_TouchList_m_pElements = LoadFromAddress(moveHelperAddr + view_as<Address>(8) + view_as<Address>(16), NumberType_Int32);

for (int i = 0; i < gI_CollisionCount[client]; i++)
{
Trace trace = Trace(m_TouchList_m_pElements + view_as<Address>(i*96) + view_as<Address>(12));
trace.startpos.ToArray(gF_TraceStartOrigin[client][i]);
trace.endpos.ToArray(gF_TraceEndOrigin[client][i]);
trace.plane.normal.ToArray(gF_TraceNormal[client][i]);
}

Action result = UpdateMoveData(pThis, client, Call_OnTryPlayerMovePost);
if (result != Plugin_Continue)
{
return MRES_Handled;
}
else
{
return MRES_Ignored;
}
}

static void NobugLandingOrigin(int client, float landingOrigin[3])
{
// Jump is bugged, try to use the trace result of TryPlayerMove if possible.
if (tryPlayerMoveThisTick && gI_CollisionCount[client] > 0)
{
landingOrigin = gF_TraceEndOrigin[client][0];
return;
}
// Fallback when no collision happened during TryPlayerMove, or that function was not called.

// NOTE: Get ground position and distance to ground.
float groundEndPoint[3];
groundEndPoint = gF_Origin[client];
Expand Down
28 changes: 28 additions & 0 deletions addons/sourcemod/scripting/movementapi/natives.sp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,11 @@ void CreateNatives()
CreateNative("Movement_SetTakeoffVelocity", Native_SetTakeoffVelocity);
CreateNative("Movement_SetLandingOrigin", Native_SetLandingOrigin);
CreateNative("Movement_SetLandingVelocity", Native_SetLandingVelocity);

CreateNative("Movement_GetCollisionCount", Native_GetCollisionCount);
CreateNative("Movement_GetCollisionStartOrigin", Native_GetCollisionStartOrigin);
CreateNative("Movement_GetCollisionEndOrigin", Native_GetCollisionEndOrigin);
CreateNative("Movement_GetCollisionNormal", Native_GetCollisionNormal);
}

public int Native_GetJumped(Handle plugin, int numParams)
Expand Down Expand Up @@ -180,4 +185,27 @@ public int Native_SetLandingVelocity(Handle plugin, int numParams)
}

return 0;
}

public int Native_GetCollisionCount(Handle plugin, int numParams)
{
return gI_CollisionCount[GetNativeCell(1)];
}

public int Native_GetCollisionStartOrigin(Handle plugin, int numParams)
{
SetNativeArray(3, gF_TraceStartOrigin[GetNativeCell(1)][GetNativeCell(2)], sizeof(gF_TraceStartOrigin[][]));
return 0;
}

public int Native_GetCollisionEndOrigin(Handle plugin, int numParams)
{
SetNativeArray(3, gF_TraceEndOrigin[GetNativeCell(1)][GetNativeCell(2)], sizeof(gF_TraceEndOrigin[][]));
return 0;
}

public int Native_GetCollisionNormal(Handle plugin, int numParams)
{
SetNativeArray(3, gF_TraceNormal[GetNativeCell(1)][GetNativeCell(2)], sizeof(gF_TraceNormal[][]));
return 0;
}
Loading