mirror of
https://github.com/rehlds/reapi.git
synced 2025-01-12 22:57:58 +03:00
Implemented g/set_member safe version
This commit is contained in:
parent
9e16f2769a
commit
2491fb9865
@ -1,3 +1,3 @@
|
||||
majorVersion=5
|
||||
minorVersion=17
|
||||
minorVersion=18
|
||||
maintenanceVersion=0
|
||||
|
@ -94,6 +94,13 @@ enum members_tables_e
|
||||
#include <reapi_engine> // @note: only for ReHLDS
|
||||
#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
|
||||
#include <reapi_vtc>
|
||||
#include <reapi_reunion>
|
||||
|
@ -120,6 +120,28 @@ native set_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.
|
||||
*
|
||||
|
@ -14,9 +14,9 @@
|
||||
#define decltypefxdot(cx, pref, mx) decltype(cx::pref.mx)
|
||||
#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_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_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(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;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;ptr->pfnIsRefsToClass = [](CBaseEntity *pEntity){ return dynamic_cast<cx *>(pEntity) != nullptr;};}) : regmember(#pref"."#mx)
|
||||
|
||||
#define GM_MEMBERS(mx) CLASS_MEMBERS(CHalfLifeMultiplay, mx, mx)
|
||||
#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(euser2),
|
||||
EVAR_MEMBERS(euser3),
|
||||
EVAR_MEMBERS(euser4)
|
||||
EVAR_MEMBERS(euser4),
|
||||
};
|
||||
|
||||
member_t memberlist_playermove[] = {
|
||||
@ -723,7 +723,7 @@ member_t memberlist_usercmd[] = {
|
||||
UCMD_MEMBERS(impulse),
|
||||
UCMD_MEMBERS(weaponselect),
|
||||
UCMD_MEMBERS(impact_index),
|
||||
UCMD_MEMBERS(impact_position)
|
||||
UCMD_MEMBERS(impact_position),
|
||||
};
|
||||
|
||||
member_t memberlist_pmtrace[] = {
|
||||
@ -735,7 +735,7 @@ member_t memberlist_pmtrace[] = {
|
||||
PMTRACE_MEMBERS(endpos),
|
||||
PMTRACE_MEMBERS(ent),
|
||||
PMTRACE_MEMBERS(deltavelocity),
|
||||
PMTRACE_MEMBERS(hitgroup)
|
||||
PMTRACE_MEMBERS(hitgroup),
|
||||
};
|
||||
|
||||
member_t memberlist_csplayer[] = {
|
||||
@ -790,7 +790,7 @@ member_t memberlist_baseweapon[] = {
|
||||
BASEWPN_MEMBERS(usFireGlock18),
|
||||
BASEWPN_MEMBERS(usFireFamas),
|
||||
BASEWPN_MEMBERS(flPrevPrimaryAttack),
|
||||
BASEWPN_MEMBERS(flLastFireTime)
|
||||
BASEWPN_MEMBERS(flLastFireTime),
|
||||
};
|
||||
|
||||
member_t memberlist_weaponbox[] = {
|
||||
|
@ -95,6 +95,7 @@ struct member_t
|
||||
size_t offset;
|
||||
const char *name;
|
||||
MType type;
|
||||
bool (*pfnIsRefsToClass)(class CBaseEntity *pEntity);
|
||||
};
|
||||
|
||||
inline bool member_t::isTypeReturnable() const
|
||||
|
@ -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.
|
||||
*
|
||||
@ -617,6 +742,9 @@ AMX_NATIVE_INFO ReGameVars_Natives[] =
|
||||
{ "set_member", set_member },
|
||||
{ "get_member", get_member },
|
||||
|
||||
{ "set_member_s", set_member_s },
|
||||
{ "get_member_s", get_member_s },
|
||||
|
||||
{ "set_member_game", set_member_game },
|
||||
{ "get_member_game", get_member_game },
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user