2
0
mirror of https://github.com/rehlds/reapi.git synced 2024-12-28 07:35:31 +03:00

Add new natives set_netchan/get_netchan (Close #322), rh_is_entity_fullpacked and rh_get_realtime

Minor refactoring/cleanup
This commit is contained in:
s1lentq 2024-07-13 19:52:39 +07:00
parent 439396fc96
commit 472d279c5a
8 changed files with 397 additions and 74 deletions

View File

@ -81,7 +81,8 @@ enum members_tables_e
mt_csplayerweapon,
mt_gib,
mt_netadr,
mt_csentity
mt_csentity,
mt_netchan
};
#define ReAPIFunc {EngineFunc, GamedllFunc, GamedllFunc_CBaseAnimating, GamedllFunc_CBasePlayer, GamedllFunc_CSGameRules, GamedllFunc_CGrenade, GamedllFunc_CWeaponBox, ReCheckerFunc, GamedllFunc_CBasePlayerWeapon, GamedllFunc_CGib, GamedllFunc_CBaseEntity, GamedllFunc_CBotManager}

View File

@ -30,6 +30,18 @@ native set_ucmd(const ucmd, const UCmd:var, any:...);
*/
native any:get_ucmd(const ucmd, const UCmd:var, any:...);
/*
* Sets netchan data.
* Use the net_* NetChan enum
*/
native set_netchan(const index, const NetChan:var, any:...);
/*
* Returns metchan data from an client.
* Use the net_* NetChan enum
*/
native any:get_netchan(const index, const NetChan:var, any:...);
/*
* Sets a NetAdr var.
*
@ -184,7 +196,7 @@ native CheckVisibilityInOrigin(const ent, Float:origin[3], CheckVisibilityType:t
/*
* Sets the name of the map.
*
* @param mapname New map name.
* @param mapname New map name.
*
* @noreturn
*/
@ -228,19 +240,19 @@ native rh_reset_mapname();
native bool:rh_emit_sound2(const entity, const recipient, const channel, const sample[], Float:vol = VOL_NORM, Float:attn = ATTN_NORM, const flags = 0, const pitch = PITCH_NORM, emitFlags = 0, const Float:origin[3] = {0.0,0.0,0.0});
/*
* Forces an userinfo update.
* Forces an userinfo update
*
* @param playerEntIndex Player entity index (starts from 1)
* @param index Client index
*
* @noreturn
*/
native rh_update_user_info(playerEntIndex);
native rh_update_user_info(const index);
/*
* Kicks a client from server with message
*
* @param index Client index
* @param message Message that will be sent to client when it is deleted from server
* @param index Client index
* @param message Message that will be sent to client when it is deleted from server
*
* @noreturn
*
@ -261,12 +273,30 @@ native rh_get_net_from(output[], len);
/*
* Returns client's netchan playing time in seconds.
*
* @param index Client index
* @param index Client index
*
* @return Netchan connection time in seconds or 0 if client index is invalid or client is not connected
* @return Netchan connection time in seconds or 0 if client index is invalid or client is not connected
*/
native rh_get_client_connect_time(const index);
/*
* Checks if a specific entity is fully packed in a given frame for a host client.
*
* @param index Client index for whom we are checking the entity.
* @param entity Entity index to find in the table of entities for the given frame.
* @param frame Frame index where to look. Default is -1, which checks the previous frame.
* @note To check in the current frame, this native should be called at the end of the server frame.
*
* @return Returns true if the entity is fully packed and ready to be sent to all clients in the given frame, otherwise false.
*/
native bool:rh_is_entity_fullpacked(const host, const entity, const frame = -1);
/*
* Get real game time throughout the entire server lifecycle.
*
* @return Real game time
*/
native Float:rh_get_realtime();
enum MessageHook
{

View File

@ -1191,96 +1191,96 @@ enum UCmd
/*
* Description: -
* Member type: short
* Get params: get_ucmd(const ucmd, UserCmd:var);
* Set params: set_ucmd(const ucmd, UserCmd:var, value);
* Get params: get_ucmd(const ucmd, UCmd:var);
* Set params: set_ucmd(const ucmd, UCmd:var, value);
*/
ucmd_lerp_msec = BEGIN_MEMBER_REGION(usercmd),
/*
* Description: -
* Member type: byte
* Get params: get_ucmd(const ucmd, UserCmd:var);
* Set params: set_ucmd(const ucmd, UserCmd:var, value);
* Get params: get_ucmd(const ucmd, UCmd:var);
* Set params: set_ucmd(const ucmd, UCmd:var, value);
*/
ucmd_msec,
/*
* Description: -
* Member type: vec3_t
* Get params: get_ucmd(const ucmd, UserCmd:var, Float:output[3]);
* Set params: set_ucmd(const ucmd, UserCmd:var, Float:dest[3]);
* Get params: get_ucmd(const ucmd, UCmd:var, Float:output[3]);
* Set params: set_ucmd(const ucmd, UCmd:var, Float:dest[3]);
*/
ucmd_viewangles,
/*
* Description: -
* Member type: float
* Get params: Float:get_ucmd(const ucmd, UserCmd:var);
* Set params: set_ucmd(const ucmd, UserCmd:var, Float:value);
* Get params: Float:get_ucmd(const ucmd, UCmd:var);
* Set params: set_ucmd(const ucmd, UCmd:var, Float:value);
*/
ucmd_forwardmove,
/*
* Description: -
* Member type: float
* Get params: Float:get_ucmd(const ucmd, UserCmd:var);
* Set params: set_ucmd(const ucmd, UserCmd:var, Float:value);
* Get params: Float:get_ucmd(const ucmd, UCmd:var);
* Set params: set_ucmd(const ucmd, UCmd:var, Float:value);
*/
ucmd_sidemove,
/*
* Description: -
* Member type: float
* Get params: Float:get_ucmd(const ucmd, UserCmd:var);
* Set params: set_ucmd(const ucmd, UserCmd:var, Float:value);
* Get params: Float:get_ucmd(const ucmd, UCmd:var);
* Set params: set_ucmd(const ucmd, UCmd:var, Float:value);
*/
ucmd_upmove,
/*
* Description: -
* Member type: byte
* Get params: get_ucmd(const ucmd, UserCmd:var);
* Set params: set_ucmd(const ucmd, UserCmd:var, value);
* Get params: get_ucmd(const ucmd, UCmd:var);
* Set params: set_ucmd(const ucmd, UCmd:var, value);
*/
ucmd_lightlevel,
/*
* Description: -
* Member type: unsigned short
* Get params: get_ucmd(const ucmd, UserCmd:var);
* Set params: set_ucmd(const ucmd, UserCmd:var, value);
* Get params: get_ucmd(const ucmd, UCmd:var);
* Set params: set_ucmd(const ucmd, UCmd:var, value);
*/
ucmd_buttons,
/*
* Description: -
* Member type: byte
* Get params: get_ucmd(const ucmd, UserCmd:var);
* Set params: set_ucmd(const ucmd, UserCmd:var, value);
* Get params: get_ucmd(const ucmd, UCmd:var);
* Set params: set_ucmd(const ucmd, UCmd:var, value);
*/
ucmd_impulse,
/*
* Description: -
* Member type: byte
* Get params: get_ucmd(const ucmd, UserCmd:var);
* Set params: set_ucmd(const ucmd, UserCmd:var, value);
* Get params: get_ucmd(const ucmd, UCmd:var);
* Set params: set_ucmd(const ucmd, UCmd:var, value);
*/
ucmd_weaponselect,
/*
* Description: -
* Member type: int
* Get params: get_ucmd(const ucmd, UserCmd:var);
* Set params: set_ucmd(const ucmd, UserCmd:var, value);
* Get params: get_ucmd(const ucmd, UCmd:var);
* Set params: set_ucmd(const ucmd, UCmd:var, value);
*/
ucmd_impact_index,
/*
* Description: -
* Member type: vec3_t
* Get params: get_ucmd(const ucmd, UserCmd:var, Float:output[3]);
* Set params: set_ucmd(const ucmd, UserCmd:var, Float:dest[3]);
* Get params: get_ucmd(const ucmd, UCmd:var, Float:output[3]);
* Set params: set_ucmd(const ucmd, UCmd:var, Float:dest[3]);
*/
ucmd_impact_position
};
@ -1322,6 +1322,134 @@ enum NetAdrVars
netadr_port
};
/**
* enum NetSrc
*/
enum NetSrc
{
NS_CLIENT,
NS_SERVER,
NS_MULTICAST // xxxMO
};
/**
* enum NetChan
*/
enum NetChan
{
/*
* Description: NS_SERVER or NS_CLIENT, depending on channel
* Member type: int
* Get params: NetSrc:get_netchan(const index, NetChan:var);
* Set params: set_netchan(const index, NetChan:var, NetSrc:value);
*/
net_sock = BEGIN_MEMBER_REGION(netchan),
/*
* Description: Address this channel is talking to
* Member type: NetAdr
* Get params: NetAdr:get_netchan(const index, NetChan:var);
* Set params: set_netchan(const index, NetChan:var, NetAdr:value);
*/
net_remote_address,
/*
* Description: -
* Member type: int
* Get params: get_netchan(const index, NetChan:var);
* Set params: set_netchan(const index, NetChan:var, value);
*/
net_player_slot,
/*
* Description: For timeouts. Time last message was received
* Member type: float
* Get params: Float:get_netchan(const index, NetChan:var);
* Set params: set_netchan(const index, NetChan:var, Float:value);
*/
net_last_received,
/*
* Description: Time when channel was connected
* Member type: float
* Get params: Float:get_netchan(const index, NetChan:var);
* Set params: set_netchan(const index, NetChan:var, Float:value);
*/
net_connect_time,
/*
* Description: Bandwidth choke. (Bytes per second)
* Member type: float
* Get params: Float:get_netchan(const index, NetChan:var);
* Set params: set_netchan(const index, NetChan:var, Float:value);
*/
net_rate,
/*
* Description: If rh_get_realtime() > cleartime, free to send next packet.
* Member type: float
* Get params: Float:get_netchan(const index, NetChan:var);
* Set params: set_netchan(const index, NetChan:var, Float:value);
*/
net_cleartime,
/*
* Description: A sequence number that increases with each incoming bunch of packets.
* Member type: int
* Get params: get_netchan(const index, NetChan:var);
* Set params: set_netchan(const index, NetChan:var, value);
*/
net_incoming_sequence,
/*
* Description: The number of last outgoing message that has been ack'd.
* Member type: int
* Get params: get_netchan(const index, NetChan:var);
* Set params: set_netchan(const index, NetChan:var, value);
*/
net_incoming_acknowledged,
/*
* Description: Single bit indicating the state of acknowledgment for the last reliable message.
* Member type: int
* Get params: get_netchan(const index, NetChan:var);
* Set params: set_netchan(const index, NetChan:var, value);
*/
net_incoming_reliable_acknowledged,
/*
* Description: Single bit, maintained local that toggles between 0 and 1 to track the sequence of reliable messages received
* Member type: int
* Get params: get_netchan(const index, NetChan:var);
* Set params: set_netchan(const index, NetChan:var, value);
*/
net_incoming_reliable_sequence,
/*
* Description: Message we are sending to remote
* Member type: int
* Get params: get_netchan(const index, NetChan:var);
* Set params: set_netchan(const index, NetChan:var, value);
*/
net_outgoing_sequence,
/*
* Description: Whether the message contains reliable payload, single bit
* Member type: int
* Get params: get_netchan(const index, NetChan:var);
* Set params: set_netchan(const index, NetChan:var, value);
*/
net_reliable_sequence,
/*
* Description: Outgoing sequence number of last send that had reliable data
* Member type: int
* Get params: get_netchan(const index, NetChan:var);
* Set params: set_netchan(const index, NetChan:var, value);
*/
net_last_reliable_sequence
};
/**
* Message argument types used with GetMessageArgType()
*/

View File

@ -29,6 +29,7 @@
#define PMOVE_MEMBERS(mx) STRUCT_MEMBERS(com_playermove, mx, pm_##mx)
#define MOVEVAR_MEMBERS(mx) STRUCT_MEMBERS(movevars_t, mx, mv_##mx)
#define UCMD_MEMBERS(mx) STRUCT_MEMBERS(usercmd_s, mx, ucmd_##mx)
#define NETCHAN_MEMBERS(mx) STRUCT_MEMBERS(netchan_t, mx, net_##mx)
#define PMTRACE_MEMBERS(mx) STRUCT_MEMBERS(pmtrace_s, mx, pmt_##mx)
#define NETADR_MEMBERS(mx) STRUCT_MEMBERS(netadr_t, mx, netadr_##mx)
#define CSPL_MEMBERS(mx) CLASS_MEMBERS(CCSPlayer, mx, mx)
@ -115,6 +116,8 @@ inline MType getMemberType(ArmouryItemPack) { return MEMBER_INTEGER; }
inline MType getMemberType(InfoMapBuyParam) { return MEMBER_INTEGER; }
inline MType getMemberType(SecondaryAtkState) { return MEMBER_INTEGER; }
inline MType getMemberType(netadrtype_t) { return MEMBER_INTEGER; }
inline MType getMemberType(netsrc_t) { return MEMBER_INTEGER; }
inline MType getMemberType(netadr_t) { return MEMBER_NETADR; }
inline MType getMemberType(TraceResult) { return MEMBER_TRACERESULT; }
@ -753,6 +756,23 @@ member_t memberlist_pmtrace[] = {
PMTRACE_MEMBERS(hitgroup),
};
member_t memberlist_netchan[] = {
NETCHAN_MEMBERS(sock),
NETCHAN_MEMBERS(remote_address),
NETCHAN_MEMBERS(player_slot),
NETCHAN_MEMBERS(last_received),
NETCHAN_MEMBERS(connect_time),
NETCHAN_MEMBERS(rate),
NETCHAN_MEMBERS(cleartime),
NETCHAN_MEMBERS(incoming_sequence),
NETCHAN_MEMBERS(incoming_acknowledged),
NETCHAN_MEMBERS(incoming_reliable_acknowledged),
NETCHAN_MEMBERS(incoming_reliable_sequence),
NETCHAN_MEMBERS(outgoing_sequence),
NETCHAN_MEMBERS(reliable_sequence),
NETCHAN_MEMBERS(last_reliable_sequence)
};
member_t memberlist_csplayer[] = {
CSPL_MEMBERS(m_szModel),
CSPL_MEMBERS(m_bForceShowMenu),
@ -1094,6 +1114,7 @@ member_t *memberlist_t::operator[](size_t members) const
CASE(movevars)
CASE(usercmd)
CASE(pmtrace)
CASE(netchan)
CASE(csplayer)
CASE(baseitem)
CASE(baseweapon)

View File

@ -26,6 +26,7 @@ enum MType
MEMBER_PMTRACE, // struct pmtrace_t
MEBMER_USERCMD, // struct usercmd_s
MEMBER_TRACERESULT, // struct TraceResult
MEMBER_NETADR // struct netadr_t
};
struct memberlist_t
@ -84,7 +85,8 @@ struct memberlist_t
mt_csplayerweapon,
mt_gib,
mt_netadr,
mt_csentity
mt_csentity,
mt_netchan
};
};
@ -772,6 +774,24 @@ enum PMTrace
pmt_hitgroup
};
enum NetChan
{
net_sock = BEGIN_MEMBER_REGION(netchan),
net_remote_address,
net_player_slot,
net_last_received,
net_connect_time,
net_rate,
net_cleartime,
net_incoming_sequence,
net_incoming_acknowledged,
net_incoming_reliable_acknowledged,
net_incoming_reliable_sequence,
net_outgoing_sequence,
net_reliable_sequence,
net_last_reliable_sequence
};
enum NetAdr
{
netadr_type = BEGIN_MEMBER_REGION(netadr),

View File

@ -2,12 +2,14 @@
#define PARAMS_COUNT (params[0] / sizeof(cell))
#define CHECK_ISPLAYER(x) if (unlikely(params[x] <= 0 || params[x] > gpGlobals->maxClients)) { AMXX_LogError(amx, AMX_ERR_NATIVE, "%s: invalid player index %i [%s]", __FUNCTION__, params[x], #x); return FALSE; }
#define CHECK_ISENTITY(x) if (unlikely(params[x] < 0 || params[x] > gpGlobals->maxEntities)) { AMXX_LogError(amx, AMX_ERR_NATIVE, "%s: invalid entity index %i [%s]", __FUNCTION__, params[x], #x); return FALSE; }
#define CHECK_GAMERULES() if (unlikely(!g_pGameRules)) { AMXX_LogError(amx, AMX_ERR_NATIVE, "%s: gamerules not initialized", __FUNCTION__); return FALSE; }
#define CHECK_CONNECTED(x, y) if (unlikely(x == nullptr || x->has_disconnected)) { AMXX_LogError(amx, AMX_ERR_NATIVE, "%s: player %i is not connected", __FUNCTION__, params[y]); return FALSE; }
#define CHECK_INSTANCE_OF(x, y) if (unlikely(dynamic_cast<x *>((x::BaseClass *)y) == nullptr)) { AMXX_LogError(amx, AMX_ERR_NATIVE, "%s: invalid entity %d ('%s'), is not an instance of the base class '%s'", __FUNCTION__, indexOfEdict(y->pev), STRING(y->pev->classname), #x); return FALSE; }
#define CHECK_REQUIREMENTS(x) if (unlikely(!api_cfg.has##x())) { AMXX_LogError(amx, AMX_ERR_NATIVE, "Native '%s' is not available, %s required.", __FUNCTION__, #x); return FALSE; } if (!g_RehldsMessageManager) { AMXX_LogError(amx, AMX_ERR_NATIVE, "%s: %s message manager not initialized.", __FUNCTION__, #x); return FALSE; }
#define CHECK_ISPLAYER(x) if (unlikely(params[x] <= 0 || params[x] > gpGlobals->maxClients)) { AMXX_LogError(amx, AMX_ERR_NATIVE, "%s: invalid player index %i [%s]", __FUNCTION__, params[x], #x); return FALSE; }
#define CHECK_ISENTITY(x) if (unlikely(params[x] < 0 || params[x] > gpGlobals->maxEntities)) { AMXX_LogError(amx, AMX_ERR_NATIVE, "%s: invalid entity index %i [%s]", __FUNCTION__, params[x], #x); return FALSE; }
#define CHECK_GAMERULES() if (unlikely(!g_pGameRules)) { AMXX_LogError(amx, AMX_ERR_NATIVE, "%s: gamerules not initialized", __FUNCTION__); return FALSE; }
#define CHECK_CONNECTED(x, y) if (unlikely(x == nullptr || x->has_disconnected)) { AMXX_LogError(amx, AMX_ERR_NATIVE, "%s: player %i is not connected", __FUNCTION__, params[y]); return FALSE; }
#define CHECK_CLIENT_CONNECTED(x, y) if (unlikely(x == nullptr || !(x->active || x->spawned || x->connected))) { AMXX_LogError(amx, AMX_ERR_NATIVE, "%s: player %i is not connected", __FUNCTION__, params[y]); return FALSE; }
#define CHECK_APICLIENT_CONNECTED(x, y) if (unlikely(x == nullptr || !(x->IsActive() || x->IsSpawned() || x->IsConnected()))) { AMXX_LogError(amx, AMX_ERR_NATIVE, "%s: player %i is not connected", __FUNCTION__, params[y]); return FALSE; }
#define CHECK_INSTANCE_OF(x, y) if (unlikely(dynamic_cast<x *>((x::BaseClass *)y) == nullptr)) { AMXX_LogError(amx, AMX_ERR_NATIVE, "%s: invalid entity %d ('%s'), is not an instance of the base class '%s'", __FUNCTION__, indexOfEdict(y->pev), STRING(y->pev->classname), #x); return FALSE; }
#define CHECK_REQUIREMENTS(x) if (unlikely(!api_cfg.has##x())) { AMXX_LogError(amx, AMX_ERR_NATIVE, "Native '%s' is not available, %s required.", __FUNCTION__, #x); return FALSE; } if (!g_RehldsMessageManager) { AMXX_LogError(amx, AMX_ERR_NATIVE, "%s: %s message manager not initialized.", __FUNCTION__, #x); return FALSE; }
class CAmxArg
{

View File

@ -670,6 +670,67 @@ cell AMX_NATIVE_CALL get_pmtrace(AMX *amx, cell *params)
return get_member(amx, tr, member, dest, element);
}
/*
* Sets netchan data.
* Use the net_* NetChan enum
*
* native set_netchan(const index, const NetChan:var, any:...);
*/
cell AMX_NATIVE_CALL set_netchan(AMX *amx, cell *params)
{
enum args_e { arg_count, arg_index, arg_var, arg_value };
CHECK_ISPLAYER(arg_index);
client_t *pClient = clientOfIndex(params[arg_index]);
CHECK_CLIENT_CONNECTED(pClient, arg_index);
member_t *member = memberlist[params[arg_var]];
if (unlikely(member == nullptr)) {
AMXX_LogError(amx, AMX_ERR_NATIVE, "%s: unknown member id %i", __FUNCTION__, params[arg_var]);
return FALSE;
}
cell* value = getAmxAddr(amx, params[arg_value]);
return set_member(amx, &pClient->netchan, member, value, 0);
}
/*
* Returns metchan data from an client.
* Use the net_* NetChan enum
*
* native any:get_netchan(const index, const NetChan:var, any:...);
*/
cell AMX_NATIVE_CALL get_netchan(AMX *amx, cell *params)
{
enum args_e { arg_count, arg_index, arg_var, arg_3 };
CHECK_ISPLAYER(arg_index);
client_t *pClient = clientOfIndex(params[arg_index]);
CHECK_CLIENT_CONNECTED(pClient, arg_index);
member_t *member = memberlist[params[arg_var]];
if (unlikely(member == nullptr)) {
AMXX_LogError(amx, AMX_ERR_NATIVE, "%s: unknown member id %i", __FUNCTION__, params[arg_var]);
return FALSE;
}
cell* dest;
size_t element;
if (PARAMS_COUNT == 3) {
dest = getAmxAddr(amx, params[arg_3]);
element = 0;
}
else {
dest = nullptr;
element = 0;
}
return get_member(amx, &pClient->netchan, member, dest, element);
}
/*
* Sets a NetAdr var.
*
@ -824,6 +885,12 @@ AMX_NATIVE_INFO EngineVars_Natives[] =
{ "set_ucmd", set_ucmd },
{ "get_ucmd", get_ucmd },
{ "set_netchan", set_netchan },
{ "get_netchan", get_netchan },
{ "set_netadr", set_netadr },
{ "get_netadr", get_netadr },
{ "set_rebuy", set_rebuy },
{ "get_rebuy", get_rebuy },
@ -850,9 +917,6 @@ AMX_NATIVE_INFO ReGameVars_Natives[] =
{ "set_pmtrace", set_pmtrace },
{ "get_pmtrace", get_pmtrace },
{ "set_netadr", set_netadr },
{ "get_netadr", get_netadr },
{ nullptr, nullptr }
};
@ -1125,6 +1189,8 @@ cell get_member(AMX *amx, void* pdata, const member_t *member, cell* dest, size_
return (cell)get_member_direct<pmtrace_s>(pdata, member->offset, element);
case MEBMER_USERCMD:
return (cell)get_member_direct<usercmd_s>(pdata, member->offset, element);
case MEMBER_NETADR:
return (cell)get_member_direct<netadr_t>(pdata, member->offset, element);
default: break;
}

View File

@ -3466,7 +3466,7 @@ AMX_NATIVE_INFO Misc_Natives_RG[] =
/*
* Sets the name of the map.
*
* @param mapname New map name.
* @param mapname New map name.
*
* @noreturn
*
@ -3579,16 +3579,23 @@ cell AMX_NATIVE_CALL rh_emit_sound2(AMX *amx, cell *params)
);
}
// TODO: should we duplicate documentation for native here and in include?
/*
* Forces an userinfo update
*
* @param index Client index
*
* @noreturn
*/
cell AMX_NATIVE_CALL rh_update_user_info(AMX *amx, cell *params)
{
enum args_e { arg_count, arg_playerEntIndex };
enum args_e { arg_count, arg_index };
CBasePlayer *pPlayer = getPrivate<CBasePlayer>(params[arg_playerEntIndex]);
CHECK_CONNECTED(pPlayer, arg_playerEntIndex);
CHECK_ISPLAYER(arg_index);
CAmxArgs args(amx, params);
g_RehldsFuncs->SV_UpdateUserInfo(args[arg_playerEntIndex]);
IGameClient *pClient = clientByIndex(params[arg_index]);
CHECK_APICLIENT_CONNECTED(pClient, arg_index);
g_RehldsFuncs->SV_UpdateUserInfo(pClient);
return TRUE;
}
@ -3596,8 +3603,8 @@ cell AMX_NATIVE_CALL rh_update_user_info(AMX *amx, cell *params)
/*
* Kicks a client from server with message
*
* @param index Client index
* @param message Message that will be sent to client when it is deleted from server
* @param index Client index
* @param message Message that will be sent to client when it is deleted from server
*
* @noreturn
*
@ -3609,15 +3616,11 @@ cell AMX_NATIVE_CALL rh_drop_client(AMX *amx, cell *params)
CHECK_ISPLAYER(arg_index);
client_t *pClient = clientOfIndex(params[arg_index]);
if (unlikely(pClient == nullptr || !(pClient->active | pClient->spawned | pClient->connected)))
{
AMXX_LogError(amx, AMX_ERR_NATIVE, "%s: player %i is not connected", __FUNCTION__, params[arg_index]);
return FALSE;
}
IGameClient *pClient = clientByIndex(params[arg_index]);
CHECK_APICLIENT_CONNECTED(pClient, arg_index);
char messagebuf[256];
g_RehldsFuncs->DropClient(g_RehldsSvs->GetClient(params[arg_index] - 1), false, getAmxString(amx, params[arg_msg], messagebuf));
g_RehldsFuncs->DropClient(pClient, false, getAmxString(amx, params[arg_msg], messagebuf));
return TRUE;
}
@ -3643,12 +3646,27 @@ cell AMX_NATIVE_CALL rh_get_net_from(AMX* amx, cell* params)
return TRUE;
}
/*
* Get real game time throughout the entire server lifecycle.
*
* @return Real game time
*
* native Float:rh_get_realtime();
*/
cell AMX_NATIVE_CALL rh_get_realtime(AMX* amx, cell* params)
{
enum args_e { arg_count };
float realtime = static_cast<float>(g_RehldsFuncs->GetRealTime());
return *(cell *)&realtime;
}
/*
* Returns client's netchan playing time in seconds.
*
* @param index Client index
* @param index Client index
*
* @return Netchan connection time in seconds or 0 if client index is invalid or client is not connected
* @return Netchan connection time in seconds or 0 if client index is invalid or client is not connected
*
* native rh_get_client_connect_time(const index);
*/
@ -3659,25 +3677,62 @@ cell AMX_NATIVE_CALL rh_get_client_connect_time(AMX *amx, cell *params)
CHECK_ISPLAYER(arg_index);
client_t *pClient = clientOfIndex(params[arg_index]);
if (unlikely(pClient == nullptr || !(pClient->active | pClient->spawned | pClient->connected)))
{
AMXX_LogError(amx, AMX_ERR_NATIVE, "%s: player %i is not connected", __FUNCTION__, params[arg_index]);
return FALSE;
}
CHECK_CLIENT_CONNECTED(pClient, arg_index);
return (cell)(g_RehldsFuncs->GetRealTime() - pClient->netchan.connect_time);
}
/*
* Checks if a specific entity is fully packed in a given frame for a host client.
*
* @param index Client index for whom we are checking the entity.
* @param entity Entity index to find in the table of entities for the given frame.
* @param frame Frame index where to look. Default is -1, which checks the previous frame.
* @note To check in the current frame, this native should be called at the end of the server frame.
*
* @return Returns true if the entity is fully packed and ready to be sent to all clients in the given frame, otherwise false.
*
* native bool:rh_is_entity_fullpacked(const host, const entity, const frame = -1);
*/
cell AMX_NATIVE_CALL rh_is_entity_fullpacked(AMX *amx, cell *params)
{
enum args_e { arg_count, arg_index, arg_entity, arg_frame };
const int SV_UPDATE_BACKUP = (gpGlobals->maxClients == 1) ? SINGLEPLAYER_BACKUP : MULTIPLAYER_BACKUP;
const int SV_UPDATE_MASK = (SV_UPDATE_BACKUP - 1);
CHECK_ISPLAYER(arg_index);
client_t *pClient = clientOfIndex(params[arg_index]);
CHECK_CLIENT_CONNECTED(pClient, arg_index);
int iEntity = params[arg_entity];
int iFrame = params[arg_frame];
client_frame_t *frame = &pClient->frames[(pClient->netchan.outgoing_sequence + iFrame) & SV_UPDATE_MASK];
packet_entities_t *fullpack = &frame->entities;
for (int i = 0; i < fullpack->num_entities; i++)
{
const entity_state_t *es = &fullpack->entities[i];
if (es->number == iEntity)
return TRUE; // GOTCHA! The given entity was found in the fullpack of entities
}
return FALSE;
}
AMX_NATIVE_INFO Misc_Natives_RH[] =
{
{ "rh_set_mapname", rh_set_mapname },
{ "rh_get_mapname", rh_get_mapname },
{ "rh_reset_mapname", rh_reset_mapname },
{ "rh_emit_sound2", rh_emit_sound2 },
{ "rh_update_user_info", rh_update_user_info },
{ "rh_drop_client", rh_drop_client },
{ "rh_get_net_from", rh_get_net_from },
{ "rh_set_mapname", rh_set_mapname },
{ "rh_get_mapname", rh_get_mapname },
{ "rh_reset_mapname", rh_reset_mapname },
{ "rh_emit_sound2", rh_emit_sound2 },
{ "rh_update_user_info", rh_update_user_info },
{ "rh_drop_client", rh_drop_client },
{ "rh_get_net_from", rh_get_net_from },
{ "rh_get_realtime", rh_get_realtime },
{ "rh_is_entity_fullpacked", rh_is_entity_fullpacked },
{ "rh_get_client_connect_time", rh_get_client_connect_time },
{ nullptr, nullptr }