Skip to content

Commit

Permalink
Fix crash with IsHindrance + CallBaseFunction, reformat includes (#36)
Browse files Browse the repository at this point in the history
- Fixes a case where the `IsHindrance` query callback fails to take into account a special `CBaseEntity*` value called `IS_ANY_HINDRANCE_POSSIBLE`.

- Fixes a case where using `CBaseNPC_Locomotion.CallBaseFunction` within `IsEntityTraversable` and `ShouldCollideWith` callbacks resulted in a crash.

- Reformated include guards to use `#endinput` and to use relative paths instead. This notably fix headers with the sourcepawn VSCode extension.

- Added examples to using `CBaseNPC_Locomotion` callbacks to the scout test bot.
  • Loading branch information
KitRifty authored Feb 19, 2023
1 parent bbc3fe2 commit b5503ae
Show file tree
Hide file tree
Showing 24 changed files with 229 additions and 109 deletions.
2 changes: 1 addition & 1 deletion extension/cbasenpc_behavior.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -265,7 +265,7 @@ BEGINQUERYCALLBACK(ShouldAttack, const CKnownEntity *them)
ENDQUERYCALLBACK()

BEGINQUERYCALLBACK(IsHindrance, CBaseEntity* blocker)
CBPUSHENTITY(blocker)
CBPUSHENTITY(blocker == IS_ANY_HINDRANCE_POSSIBLE ? nullptr : blocker)
ENDQUERYCALLBACK()

Vector CBaseNPCPluginAction::SelectTargetPoint( const INextBot *me, const CBaseCombatCharacterHack *subject ) const
Expand Down
4 changes: 2 additions & 2 deletions extension/cbasenpc_locomotion.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -415,7 +415,7 @@ bool CBaseNPC_Locomotion::V_IsEntityTraversable(CBaseEntity* pEntity, ILocomotio
IPluginFunction* pCallback = GetCallback(CallbackType_IsEntityTraversable);
if (pCallback && pCallback->IsRunnable())
{
cell_t entRef = gamehelpers->EntityToBCompatRef(const_cast<CBaseEntity*>(pEntity));
cell_t entRef = gamehelpers->EntityToBCompatRef(pEntity);
cell_t _result = 0;

pCallback->PushCell((cell_t)this);
Expand Down Expand Up @@ -465,7 +465,7 @@ bool CBaseNPC_Locomotion::V_ShouldCollideWith(const CBaseEntity* pEntity)

m_pCallbackTypeStack->pop();

RETURN_META_VALUE(MRES_SUPERCEDE, result);
return result;
}

float CBaseNPC_Locomotion::V_GetStepHeight()
Expand Down
74 changes: 66 additions & 8 deletions extension/natives/cbasenpc.h
Original file line number Diff line number Diff line change
Expand Up @@ -228,16 +228,30 @@ CBASENPCLOCONATIVE(SetCallback)
return 0;
}

inline bool ExpectParamCount(IPluginContext *pContext, const cell_t *params, cell_t expected, bool hasThis)
{
if (params[0] < expected)
{
pContext->ReportError("Not enough parameters (expected %d, got %d)",
hasThis ? expected - 1 : expected,
hasThis ? params[0] - 1 : params[0]);
return false;
}

return true;
}

CBASENPCLOCONATIVE(CallBaseFunction)
if (!loco->IsInCallback())
{
pContext->ThrowNativeError("CallBaseFunction() can only be used within a callback");
pContext->ReportError("CallBaseFunction() can only be used within a callback");
return 0;
}

CBaseNPC_Locomotion::CallbackType cbType = loco->GetCurrentCallbackType();

cell_t result = 0;
cell_t expectedParams = 0;

switch (cbType)
{
Expand All @@ -251,6 +265,11 @@ CBASENPCLOCONATIVE(CallBaseFunction)

case CBaseNPC_Locomotion::CallbackType_JumpAcrossGap:
{
if (!ExpectParamCount(pContext, params, 3, true))
{
return 0;
}

cell_t* goalAddr;
cell_t* forwardAddr;
pContext->LocalToPhysAddr(params[2], &goalAddr);
Expand All @@ -275,34 +294,73 @@ CBASENPCLOCONATIVE(CallBaseFunction)

case CBaseNPC_Locomotion::CallbackType_ClimbUpToLedge:
{
if (!ExpectParamCount(pContext, params, 4, true))
{
return 0;
}

cell_t* goalAddr;
cell_t* forwardAddr;
cell_t* entityAddr;
pContext->LocalToPhysAddr(params[2], &goalAddr);
pContext->LocalToPhysAddr(params[3], &forwardAddr);
CBaseEntity* pEntity = gamehelpers->ReferenceToEntity(params[4]);
pContext->LocalToPhysAddr(params[4], &entityAddr);
CBaseEntity* entity = gamehelpers->ReferenceToEntity(*entityAddr);

Vector vecGoal;
Vector vecForward;
PawnVectorToVector(goalAddr, &vecGoal);
PawnVectorToVector(forwardAddr, &vecForward);

result = loco->DefaultClimbUpToLedge(vecGoal, vecForward, pEntity);
result = loco->DefaultClimbUpToLedge(vecGoal, vecForward, entity);
break;
}

case CBaseNPC_Locomotion::CallbackType_ShouldCollideWith:
{
CBaseEntity* pOther = gamehelpers->ReferenceToEntity(params[2]);
result = loco->DefaultShouldCollideWith(pOther);
if (!ExpectParamCount(pContext, params, 2, true))
{
return 0;
}

cell_t *colliderAddr;
pContext->LocalToPhysAddr(params[2], &colliderAddr);

CBaseEntity* collider = gamehelpers->ReferenceToEntity(*colliderAddr);

if (!collider)
{
pContext->ReportError("Invalid entity index/reference %d", *colliderAddr);
return 0;
}

result = loco->DefaultShouldCollideWith(collider);
break;
}

case CBaseNPC_Locomotion::CallbackType_IsEntityTraversable:
{
CBaseEntity* pOther = gamehelpers->ReferenceToEntity(params[2]);
ILocomotion::TraverseWhenType when = (ILocomotion::TraverseWhenType)params[3];
if (!ExpectParamCount(pContext, params, 3, true))
{
return 0;
}

cell_t *obstacleAddr;
cell_t *whenAddr;
pContext->LocalToPhysAddr(params[2], &obstacleAddr);
pContext->LocalToPhysAddr(params[3], &whenAddr);

CBaseEntity* obstacle = gamehelpers->ReferenceToEntity(*obstacleAddr);

if (!obstacle)
{
pContext->ReportError("Invalid entity index/reference %d", *obstacleAddr);
return 0;
}

ILocomotion::TraverseWhenType when = (ILocomotion::TraverseWhenType)(*whenAddr);

result = loco->DefaultIsEntityTraversable(pOther, when);
result = loco->DefaultIsEntityTraversable(obstacle, when);
break;
}
}
Expand Down
2 changes: 1 addition & 1 deletion product.version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
1.8.2
1.8.3
43 changes: 43 additions & 0 deletions scripting/cbasenpc/actiontest/nb_test_scout.sp
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,49 @@ static void OnCreate(TestScoutBot ent)
SDKHook(ent.index, SDKHook_SpawnPost, SpawnPost);
SDKHook(ent.index, SDKHook_Think, Think);
SDKHook(ent.index, SDKHook_OnTakeDamageAlivePost, OnTakeDamageAlivePost);

CBaseNPC_Locomotion loco = npc.GetLocomotion();
loco.SetCallback(LocomotionCallback_ClimbUpToLedge, LocomotionClimbUpToLedge);
loco.SetCallback(LocomotionCallback_ShouldCollideWith, LocomotionShouldCollideWith);
loco.SetCallback(LocomotionCallback_IsEntityTraversable, LocomotionIsEntityTraversable);
}

static bool LocomotionClimbUpToLedge(CBaseNPC_Locomotion loco, const float goal[3], const float fwd[3], int entity)
{
float feet[3];
loco.GetFeet(feet);

if (GetVectorDistance(feet, goal) > loco.GetDesiredSpeed())
{
return false;
}

return loco.CallBaseFunction(goal, fwd, entity);
}

static bool LocomotionShouldCollideWith(CBaseNPC_Locomotion loco, CBaseEntity other)
{
if (other.index > 0 && other.index <= MaxClients)
{
return true;
}

if (CEntityFactory.GetFactoryOfEntity(other.index) == EntityFactory)
{
return true;
}

return loco.CallBaseFunction(other);
}

static bool LocomotionIsEntityTraversable(CBaseNPC_Locomotion loco, CBaseEntity obstacle, TraverseWhenType when)
{
if (CEntityFactory.GetFactoryOfEntity(obstacle.index) == EntityFactory)
{
return false;
}

return loco.CallBaseFunction(obstacle, when);
}

static void OnRemove(TestScoutBot ent)
Expand Down
44 changes: 29 additions & 15 deletions scripting/include/cbasenpc.inc
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
#if !defined _CBASENPC_EXTENSION_INC_
#if defined _CBASENPC_EXTENSION_INC_
#endinput
#endif
#define _CBASENPC_EXTENSION_INC_

#include <sdktools>
Expand Down Expand Up @@ -40,13 +42,13 @@ const NextBotAction NULL_ACTION = view_as<NextBotAction>(0);
const INextBot NULL_NEXT_BOT = view_as<INextBot>(0);
const Segment NULL_PATH_SEGMENT = view_as<Segment>(0);

#include <cbasenpc/nav>
#include <cbasenpc/baseentity>
#include <cbasenpc/baseanimating>
#include <cbasenpc/baseanimatingoverlay>
#include <cbasenpc/basecombatcharacter>
#include <cbasenpc/nextbot>
#include <cbasenpc/entityfactory>
#include "cbasenpc/nav.inc"
#include "cbasenpc/baseentity.inc"
#include "cbasenpc/baseanimating.inc"
#include "cbasenpc/baseanimatingoverlay.inc"
#include "cbasenpc/basecombatcharacter.inc"
#include "cbasenpc/nextbot.inc"
#include "cbasenpc/entityfactory.inc"

methodmap CExtNPC __nullable__
{
Expand Down Expand Up @@ -171,7 +173,8 @@ typeset LocomotionCallback
methodmap CBaseNPC_Locomotion < NextBotGroundLocomotion
{
/**
* Sets a callback function on the locomotion.
* Sets a callback function on the locomotion. This is used to override some
* functions on the locomotion.
*
* @param callbackType Type of callback
* @param callback Callback function
Expand All @@ -181,11 +184,24 @@ methodmap CBaseNPC_Locomotion < NextBotGroundLocomotion

/**
* Calls the base function of the current callback. This can only be used
* within a callback function.
* within a callback function. Calling this will call the original
* function that the callback is trying to override.
*
* You do not need to pass in the locomotion pointer again. Parameters
* must be passed in the same order as calling the overridden function.
* For example,
*
* bool LocomotionIsEntityTraversable(CBaseNPC_Locomotion loco, CBaseEntity obstacle, TraverseWhenType when)
* {
* // Custom code logic goes here
*
* return loco.CallBaseFunction(obstacle, when);
* }
*
* @param any Function arguments
* @param ... Variable number of function parameters
* @return Function return
* @error Locomotion is invalid or used outside of a callback function
* @error Locomotion is invalid, used outside of a callback function, too few parameters
* passed, or an entity parameter is invalid
*/
public native any CallBaseFunction(any ...);
};
Expand Down Expand Up @@ -215,6 +231,4 @@ public Extension __ext_cbasenpc =
#else
required = 0,
#endif
};

#endif
};
8 changes: 4 additions & 4 deletions scripting/include/cbasenpc/activity.inc
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
#if !defined _CBASENPC_ACTIVITY_INC_
#if defined _CBASENPC_ACTIVITY_INC_
#endinput
#endif
#define _CBASENPC_ACTIVITY_INC_

enum Activity
Expand Down Expand Up @@ -2178,6 +2180,4 @@ enum Activity

// this is the end of the global activities, private per-monster activities start here.
LAST_SHARED_ACTIVITY,
};

#endif
};
10 changes: 5 additions & 5 deletions scripting/include/cbasenpc/baseanimating.inc
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
#if !defined _CBASENPC_BASEANIMATING_INC_
#if defined _CBASENPC_BASEANIMATING_INC_
#endinput
#endif
#define _CBASENPC_BASEANIMATING_INC_

#include <cbasenpc/activity>
#include "activity.inc"

methodmap CBaseAnimating < CBaseEntity
{
Expand Down Expand Up @@ -156,6 +158,4 @@ methodmap CBaseAnimating < CBaseEntity
* @error Invalid entity.
*/
public native float GetPoseParameter(int poseParam);
};

#endif
};
8 changes: 4 additions & 4 deletions scripting/include/cbasenpc/baseanimatingoverlay.inc
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
#if !defined _CBASENPC_BASEANIMATING_OVERLAY_INC_
#if defined _CBASENPC_BASEANIMATING_OVERLAY_INC_
#endinput
#endif
#define _CBASENPC_BASEANIMATING_OVERLAY_INC_

#define ANIM_LAYER_ACTIVE 0x0001
Expand Down Expand Up @@ -526,6 +528,4 @@ methodmap CBaseAnimatingOverlay < CBaseAnimating
return -1;
}

};

#endif
};
8 changes: 4 additions & 4 deletions scripting/include/cbasenpc/basecombatcharacter.inc
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
#if !defined _CBASENPC_BASECOMBATCHARACTER_INC
#if defined _CBASENPC_BASECOMBATCHARACTER_INC
#endinput
#endif
#define _CBASENPC_BASECOMBATCHARACTER_INC

methodmap CBaseCombatCharacter < CBaseAnimatingOverlay
Expand All @@ -23,6 +25,4 @@ methodmap CBaseCombatCharacter < CBaseAnimatingOverlay
* @error Invalid entity.
*/
public native CNavArea GetLastKnownArea();
};

#endif
};
8 changes: 4 additions & 4 deletions scripting/include/cbasenpc/baseentity.inc
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
#if !defined _CBASENPC_BASEENTITY_INC_
#if defined _CBASENPC_BASEENTITY_INC_
#endinput
#endif
#define _CBASENPC_BASEENTITY_INC_

methodmap CBaseEntity
Expand Down Expand Up @@ -908,6 +910,4 @@ methodmap CBaseEntity
{
SetEntityMoveType(this.index, val);
}
}

#endif
}
8 changes: 4 additions & 4 deletions scripting/include/cbasenpc/entityfactory.inc
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
#if !defined _CBASENPC_ENTITYFACTORY_INC_
#if defined _CBASENPC_ENTITYFACTORY_INC_
#endinput
#endif
#define _CBASENPC_ENTITYFACTORY_INC_

typeset InputFuncCallback
Expand Down Expand Up @@ -417,6 +419,4 @@ forward void CEntityFactory_OnInstalled(const char[] classname, CEntityFactory f
* @param classname The classname of the factory
* @param factory Factory that was uninstalled
*/
forward void CEntityFactory_OnUninstalled(const char[] classname, CEntityFactory factory);

#endif
forward void CEntityFactory_OnUninstalled(const char[] classname, CEntityFactory factory);
Loading

0 comments on commit b5503ae

Please sign in to comment.