Add a new SDKType to manage some handles
Hi,
This feature can answer the issue #675.
Currently with SDKCall there're:
SDKType_CBaseEntity
SDKType_CBasePlayer
SDKType_Vector
SDKType_QAngle
SDKType_PlainOldData
SDKType_Float
SDKType_Edict
SDKType_String
SDKType_Bool
What do you think about a new type 'SDKType_Handle'?
To start, only CGameTrace & CTakeDamageInfo could be supported (-> New natives would be needed to build a CTakeDamageInfo in a plugin).
Then we could do something like:
StartPrepSDKCall(SDKCall_Player);
PrepSDKCall_SetFromConf(hGameConf, SDKConf_Virtual, "TraceAttack");
PrepSDKCall_AddParameter(SDKType_Handle, SDKPass_ByRef); // CTakeDamageInfo &
PrepSDKCall_AddParameter(SDKType_Vector, SDKPass_ByRef); // Vector &
PrepSDKCall_AddParameter(SDKType_Handle, SDKPass_Pointer); // CGameTrace *
hTraceAttack = EndPrepSDKCall();
This could help in the future to call any function using CGameTrace / CTakeDamageInfo.
Remark: It forces to have in SourceMod CGameTrace & CTakeDamageInfo classes up to date, but I don't think they will change every day 😺.
Thanks.
EDIT:
For a better simplicity and readibility, SDKType_CGameTrace & SDKType_CTakeDamageInfo could be created instead of a generic SDKType_Handle.
SDKType_Handle
When CTakeDamageInfo & CGameTrace are not directly exposed to pawn there are no reasons for why a plugin would need that + to initiate such an object you need an extension, and if you make an extension you can also make that TraceAttack call inside and without the restrictions you may have in a plugin. If you really need to pass a pointer, using SDKType_PlainOldData will be enough, you can also use the pass methods https://sm.alliedmods.net/new-api/sdktools/SDKPassMethod and the enc/dec flags
#define VDECODE_FLAG_ALLOWNULL (1<<0) /**< Allow NULL for pointers */
#define VDECODE_FLAG_ALLOWNOTINGAME (1<<1) /**< Allow players not in game */
#define VDECODE_FLAG_ALLOWWORLD (1<<2) /**< Allow World entity */
#define VDECODE_FLAG_BYREF (1<<3) /**< Floats/ints by reference */
#define VENCODE_FLAG_COPYBACK (1<<0) /**< Copy back data once done */
If SDKType_CBaseEntity & SDKType_CBasePlayer exist it is just to create safe checks for plugins, There are no difference on the method on how they are passed, + they convert the entity index to its pointer, and because we have their entity index we can tell what's a player and what's not.
SDKType_CGameTrace SDKType_CTakeDamageInfo
Unlike mentioned above we have no real way on the extension end to tell that the passed pointer is a game trace or take damage info, checking their members or whatever could lead to false positive or worse.
I mean unless I'm missing your point, I don't see why we need these sdktypes.
Let's focus on SDKType_Handle first.
What I'm thinking is a new SDKType allowing to use the object hidden by a Handle.
If I use SDKType_PlainOldData + SDKPass_Pointer for a Handle, it will be the address of the Handle which will be used, not the address of the object hidden by this Handle!
Example
I can already use in a plugin:
Handle TR_TraceRayEx(const float pos[3], const float vec[3], int flags, RayType rtype);
This native returns a Handle containing a pointer to a CGameTrace.
I want to call this function:
void UTIL_DecalTrace(CGameTrace* pTrace, int iDecalNumber);
With this new SDKType, I will be able to do:
StartPrepSDKCall(SDKCall_Static);
PrepSDKCall_SetFromConf(hGameConf, SDKConf_Signature, "UTIL_DecalTrace");
PrepSDKCall_AddParameter(SDKType_Handle, SDKPass_Pointer); // CGameTrace *
PrepSDKCall_AddParameter(SDKType_PlainOldData, SDKPass_Plain); // int
hUtilDecalTrace = EndPrepSDKCall();
/* ------------------------------------------------ */
Handle hTrace = TR_TraceRayEx(vOrigin, vDirection, MASK_SOLID, RayType_Infinite);
SDKCall(hUtilDecalTrace, hTrace, 255); // <-- Reuse the Handle previously created
CloseHandle(hTrace);
Right i see what you mean, well then that's good but as for seperate type SDKType_CTakeDamageInfo and SDKType_CGameTrace shouldn't be made for the reasons i mentioned earlier and that would also mean we have to make one per new supported class. So just handle, that or we add a native on handles to return the object they cointain
Well I'm thinking about this for a harder case: to use a reference of an object hidden by a Handle. This requires to know what object is hidden by the Handle.
Some functions need references, like OnTakeDamage:
int CBasePlayer::OnTakeDamage(const CTakeDamageInfo &inputInfo)
I need to dig a little bit but I think two Handles can be differentiated in SourceMod looking at their "name". See here for instance (CGameTrace -> "TraceRay"): https://github.com/alliedmodders/sourcemod/blob/89c4be525b549dadf966b7946d3bea1d84149122/extensions/sdktools/extension.cpp#L140
More information can be found here, and it answers why we can't add a native to retrieve directly the address of the object hidden by a Handle.