sourcemod icon indicating copy to clipboard operation
sourcemod copied to clipboard

Add a new SDKType to manage some handles

Open ghost opened this issue 8 years ago • 4 comments

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.

ghost avatar Sep 01 '17 19:09 ghost

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.

Kenzzer avatar Sep 13 '17 14:09 Kenzzer

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);

ghost avatar Sep 13 '17 21:09 ghost

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

Kenzzer avatar Sep 13 '17 21:09 Kenzzer

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.

ghost avatar Sep 13 '17 23:09 ghost