2
0
mirror of https://github.com/s1lentq/reapi.git synced 2024-10-16 15:27:06 +03:00

Implemented g/set_member safe version

This commit is contained in:
s1lentq 2020-12-16 18:34:43 +07:00
parent 9e16f2769a
commit 2491fb9865
6 changed files with 166 additions and 8 deletions

View File

@ -1,3 +1,3 @@
majorVersion=5 majorVersion=5
minorVersion=17 minorVersion=18
maintenanceVersion=0 maintenanceVersion=0

View File

@ -94,6 +94,13 @@ enum members_tables_e
#include <reapi_engine> // @note: only for ReHLDS #include <reapi_engine> // @note: only for ReHLDS
#include <reapi_gamedll> // @note: only for gamedll Counter-Strike (ReGameDLL_CS) #include <reapi_gamedll> // @note: only for gamedll Counter-Strike (ReGameDLL_CS)
// If you want to use s/get_member unsafe version,
// then macro MEMBER_UNSAFE must be defined before including header reapi.inc
#if !defined(MEMBER_UNSAFE)
#define set_member set_member_s
#define get_member get_member_s
#endif
// addons // addons
#include <reapi_vtc> #include <reapi_vtc>
#include <reapi_reunion> #include <reapi_reunion>

View File

@ -120,6 +120,28 @@ native set_member(const index, any:member, any:...);
*/ */
native any:get_member(const index, any:member, any:...); native any:get_member(const index, any:member, any:...);
/*
* Sets a value to an entity's member.
* Safe version, can guarantee that the present member is refers to derived class of the entity.
*
* @param index Entity index
* @param member The specified member, look at the enums with name *_Members
*
* @return 1 on success.
*/
native set_member_s(const index, any:member, any:...);
/*
* Returns a value from an entity's member.
* Safe version, can guarantee that the present member is refers to derived class of the entity.
*
* @param index Entity index
* @param member The specified member, look at the enums with name *_Members
*
* @return If an integer or boolean or one byte, array or everything else is passed via the 3rd argument and more, look at the argument list for the specified member
*/
native any:get_member_s(const index, any:member, any:...);
/* /*
* Sets playermove var. * Sets playermove var.
* *

View File

@ -14,9 +14,9 @@
#define decltypefxdot(cx, pref, mx) decltype(cx::pref.mx) #define decltypefxdot(cx, pref, mx) decltype(cx::pref.mx)
#endif #endif
#define CLASS_MEMBERS(cx, mx, postf) ((!(postf & (MAX_REGION_RANGE - 1)) ? regmember::current_cell = 1, true : false) || (postf & (MAX_REGION_RANGE - 1)) == regmember::current_cell++) ? regmember([](member_t* ptr){ decltypefx(cx, , mx) f = {};ptr->size = getTypeSize(f);ptr->max_size = sizeof(f);ptr->offset = offsetof(cx, mx);ptr->type = getMemberType(f);ptr->name = #postf;}) : regmember(#mx) #define CLASS_MEMBERS(cx, mx, postf) ((!(postf & (MAX_REGION_RANGE - 1)) ? regmember::current_cell = 1, true : false) || (postf & (MAX_REGION_RANGE - 1)) == regmember::current_cell++) ? regmember([](member_t* ptr){ decltypefx(cx, , mx) f = {};ptr->size = getTypeSize(f);ptr->max_size = sizeof(f);ptr->offset = offsetof(cx, mx);ptr->type = getMemberType(f);ptr->name = #postf;ptr->pfnIsRefsToClass = [](CBaseEntity *pEntity){ return dynamic_cast<cx *>(pEntity) != nullptr;};}) : regmember(#mx)
#define CLASS_MEMBERS_PREF(cx, mx, postf, pref) ((!(postf & (MAX_REGION_RANGE - 1)) ? regmember::current_cell = 1, true : false) || (postf & (MAX_REGION_RANGE - 1)) == regmember::current_cell++) ? regmember([](member_t* ptr){ decltypefx(cx, pref, mx) f = {};ptr->size = getTypeSize(f);ptr->max_size = sizeof(f);ptr->offset = offsetof(cx, pref##mx);ptr->type = getMemberType(f);ptr->name = #postf;}) : regmember(#pref#mx) #define CLASS_MEMBERS_PREF(cx, mx, postf, pref) ((!(postf & (MAX_REGION_RANGE - 1)) ? regmember::current_cell = 1, true : false) || (postf & (MAX_REGION_RANGE - 1)) == regmember::current_cell++) ? regmember([](member_t* ptr){ decltypefx(cx, pref, mx) f = {};ptr->size = getTypeSize(f);ptr->max_size = sizeof(f);ptr->offset = offsetof(cx, pref##mx);ptr->type = getMemberType(f);ptr->name = #postf;ptr->pfnIsRefsToClass = [](CBaseEntity *pEntity){ return dynamic_cast<cx *>(pEntity) != nullptr;};}) : regmember(#pref#mx)
#define CLASS_MEMBERS_DOT(cx, mx, postf, pref) ((!(postf & (MAX_REGION_RANGE - 1)) ? regmember::current_cell = 1, true : false) || (postf & (MAX_REGION_RANGE - 1)) == regmember::current_cell++) ? regmember([](member_t* ptr){ decltypefxdot(cx, pref, mx) f = {};ptr->size = getTypeSize(f);ptr->max_size = sizeof(f);ptr->offset = offsetof(cx, pref.mx);ptr->type = getMemberType(f);ptr->name = #postf;}) : regmember(#pref"."#mx) #define CLASS_MEMBERS_DOT(cx, mx, postf, pref) ((!(postf & (MAX_REGION_RANGE - 1)) ? regmember::current_cell = 1, true : false) || (postf & (MAX_REGION_RANGE - 1)) == regmember::current_cell++) ? regmember([](member_t* ptr){ decltypefxdot(cx, pref, mx) f = {};ptr->size = getTypeSize(f);ptr->max_size = sizeof(f);ptr->offset = offsetof(cx, pref.mx);ptr->type = getMemberType(f);ptr->name = #postf;ptr->pfnIsRefsToClass = [](CBaseEntity *pEntity){ return dynamic_cast<cx *>(pEntity) != nullptr;};}) : regmember(#pref"."#mx)
#define GM_MEMBERS(mx) CLASS_MEMBERS(CHalfLifeMultiplay, mx, mx) #define GM_MEMBERS(mx) CLASS_MEMBERS(CHalfLifeMultiplay, mx, mx)
#define GM_VOICE_MEMBERS(mx) CLASS_MEMBERS_DOT(CHalfLifeMultiplay, mx, mx, m_VoiceGameMgr) #define GM_VOICE_MEMBERS(mx) CLASS_MEMBERS_DOT(CHalfLifeMultiplay, mx, mx, m_VoiceGameMgr)
@ -616,7 +616,7 @@ member_t memberlist_entvars[] = {
EVAR_MEMBERS(euser1), EVAR_MEMBERS(euser1),
EVAR_MEMBERS(euser2), EVAR_MEMBERS(euser2),
EVAR_MEMBERS(euser3), EVAR_MEMBERS(euser3),
EVAR_MEMBERS(euser4) EVAR_MEMBERS(euser4),
}; };
member_t memberlist_playermove[] = { member_t memberlist_playermove[] = {
@ -723,7 +723,7 @@ member_t memberlist_usercmd[] = {
UCMD_MEMBERS(impulse), UCMD_MEMBERS(impulse),
UCMD_MEMBERS(weaponselect), UCMD_MEMBERS(weaponselect),
UCMD_MEMBERS(impact_index), UCMD_MEMBERS(impact_index),
UCMD_MEMBERS(impact_position) UCMD_MEMBERS(impact_position),
}; };
member_t memberlist_pmtrace[] = { member_t memberlist_pmtrace[] = {
@ -735,7 +735,7 @@ member_t memberlist_pmtrace[] = {
PMTRACE_MEMBERS(endpos), PMTRACE_MEMBERS(endpos),
PMTRACE_MEMBERS(ent), PMTRACE_MEMBERS(ent),
PMTRACE_MEMBERS(deltavelocity), PMTRACE_MEMBERS(deltavelocity),
PMTRACE_MEMBERS(hitgroup) PMTRACE_MEMBERS(hitgroup),
}; };
member_t memberlist_csplayer[] = { member_t memberlist_csplayer[] = {
@ -790,7 +790,7 @@ member_t memberlist_baseweapon[] = {
BASEWPN_MEMBERS(usFireGlock18), BASEWPN_MEMBERS(usFireGlock18),
BASEWPN_MEMBERS(usFireFamas), BASEWPN_MEMBERS(usFireFamas),
BASEWPN_MEMBERS(flPrevPrimaryAttack), BASEWPN_MEMBERS(flPrevPrimaryAttack),
BASEWPN_MEMBERS(flLastFireTime) BASEWPN_MEMBERS(flLastFireTime),
}; };
member_t memberlist_weaponbox[] = { member_t memberlist_weaponbox[] = {

View File

@ -95,6 +95,7 @@ struct member_t
size_t offset; size_t offset;
const char *name; const char *name;
MType type; MType type;
bool (*pfnIsRefsToClass)(class CBaseEntity *pEntity);
}; };
inline bool member_t::isTypeReturnable() const inline bool member_t::isTypeReturnable() const

View File

@ -108,6 +108,131 @@ cell AMX_NATIVE_CALL get_member(AMX *amx, cell *params)
); );
} }
/*
* Sets a value to an entity's member.
* Safe version, can guarantee that the present member is refers to derived class of the entity.
*
* @param index Entity index
* @param member The specified member, look at the enums with name *_Members
*
* @return 1 on success.
* native set_member_safe(const index, any:member, any:...);
*/
cell AMX_NATIVE_CALL set_member_s(AMX *amx, cell *params)
{
enum args_e { arg_count, arg_index, arg_member, arg_value, arg_elem };
member_t *member = memberlist[params[arg_member]];
if (unlikely(member == nullptr)) {
AMXX_LogError(amx, AMX_ERR_NATIVE, "%s: unknown member id %i", __FUNCTION__, params[arg_member]);
return FALSE;
}
edict_t *pEdict = edictByIndexAmx(params[arg_index]);
if (unlikely(pEdict == nullptr || pEdict->pvPrivateData == nullptr)) {
AMXX_LogError(amx, AMX_ERR_NATIVE, "%s: invalid or uninitialized entity", __FUNCTION__);
return FALSE;
}
cell* value = getAmxAddr(amx, params[arg_value]);
size_t element = (PARAMS_COUNT == 4) ? *getAmxAddr(amx, params[arg_elem]) : 0;
CBaseEntity *pEntity = getPrivate<CBaseEntity>(pEdict);
if (!member->pfnIsRefsToClass(pEntity))
{
AMXX_LogError(amx, AMX_ERR_NATIVE, "%s: '%s' has no refs to the base class of an entity '%s'", __FUNCTION__, member->name, STRING(pEdict->v.classname));
return FALSE;
}
return set_member(
get_pdata_custom(pEntity, params[arg_member]),
member,
value,
element
);
}
/*
* Returns a value from an entity's member.
* Safe version, can guarantee that the present member is refers to derived class of the entity.
*
* @param index Entity index
* @param member The specified member, look at the enums with name *_Members
*
* @return If an integer or boolean or one byte, array or everything else is passed via the 3rd argument and more, look at the argument list for the specified member
*
* native any:get_member_safe(const index, any:member, any:...);
*/
cell AMX_NATIVE_CALL get_member_s(AMX *amx, cell *params)
{
enum args_e { arg_count, arg_index, arg_member, arg_3, arg_4, arg_5 };
member_t *member = memberlist[params[arg_member]];
if (unlikely(member == nullptr)) {
AMXX_LogError(amx, AMX_ERR_NATIVE, "%s: unknown member id %i", __FUNCTION__, params[arg_member]);
return FALSE;
}
edict_t *pEdict = edictByIndexAmx(params[arg_index]);
if (unlikely(pEdict == nullptr || pEdict->pvPrivateData == nullptr)) {
AMXX_LogError(amx, AMX_ERR_NATIVE, "%s: invalid or uninitialized entity", __FUNCTION__);
return FALSE;
}
cell* dest;
size_t element;
size_t length;
switch (PARAMS_COUNT)
{
case 5:
dest = getAmxAddr(amx, params[arg_3]);
length = *getAmxAddr(amx, params[arg_4]);
element = *getAmxAddr(amx, params[arg_5]);
break;
case 4:
dest = getAmxAddr(amx, params[arg_3]);
length = *getAmxAddr(amx, params[arg_4]);
element = 0;
break;
case 3:
{
cell* arg3 = getAmxAddr(amx, params[arg_3]);
if (member->isTypeReturnable()) {
dest = nullptr;
element = *arg3;
}
else {
dest = arg3;
element = 0;
}
length = 0;
break;
}
default:
dest = nullptr;
element = 0;
length = 0;
break;
}
CBaseEntity *pEntity = getPrivate<CBaseEntity>(pEdict);
if (!member->pfnIsRefsToClass(pEntity))
{
AMXX_LogError(amx, AMX_ERR_NATIVE, "%s: '%s' has no refs to the base class of an entity '%s'", __FUNCTION__, member->name, STRING(pEdict->v.classname));
return FALSE;
}
return get_member(
get_pdata_custom(pEntity, params[arg_member]),
member,
dest,
element,
length
);
}
/* /*
* Sets a value to CSGameRules_Members members. * Sets a value to CSGameRules_Members members.
* *
@ -617,6 +742,9 @@ AMX_NATIVE_INFO ReGameVars_Natives[] =
{ "set_member", set_member }, { "set_member", set_member },
{ "get_member", get_member }, { "get_member", get_member },
{ "set_member_s", set_member_s },
{ "get_member_s", get_member_s },
{ "set_member_game", set_member_game }, { "set_member_game", set_member_game },
{ "get_member_game", get_member_game }, { "get_member_game", get_member_game },