mirror of
https://github.com/rehlds/reapi.git
synced 2025-01-30 15:37:56 +03:00
Add natives SetThink, SetTouch, SetUse, SetBlocked, SetMoveDone
Minor refactoring
This commit is contained in:
parent
69669ef6ce
commit
e636819f02
@ -6,6 +6,62 @@
|
||||
|
||||
#include <reapi_gamedll_const>
|
||||
|
||||
/*
|
||||
* Sets callback for entity
|
||||
*
|
||||
* @param entity Entity index
|
||||
* @param callback The forward to call
|
||||
* @note Use "" to reset callback
|
||||
*
|
||||
* @noreturn
|
||||
*/
|
||||
native SetThink(const ent, const callback[]);
|
||||
|
||||
/*
|
||||
* Sets callback for entity
|
||||
*
|
||||
* @param entity Entity index
|
||||
* @param callback The forward to call
|
||||
* @note Use "" to reset callback
|
||||
*
|
||||
* @noreturn
|
||||
*/
|
||||
native SetTouch(const ent, const callback[]);
|
||||
|
||||
/*
|
||||
* Sets callback for entity
|
||||
*
|
||||
* @param entity Entity index
|
||||
* @param callback The forward to call
|
||||
* @note Use "" to reset callback
|
||||
*
|
||||
* @noreturn
|
||||
*/
|
||||
native SetUse(const ent, const callback[]);
|
||||
|
||||
/*
|
||||
* Sets callback for entity
|
||||
*
|
||||
* @param entity Entity index
|
||||
* @param callback The forward to call
|
||||
* @note Use "" to reset callback
|
||||
*
|
||||
* @noreturn
|
||||
*/
|
||||
native SetBlocked(const ent, const callback[]);
|
||||
|
||||
/*
|
||||
* Sets callback for entity
|
||||
* @note Entity should be inherited from CBaseToggle, otherwise server can crash
|
||||
*
|
||||
* @param entity Entity index
|
||||
* @param callback The forward to call
|
||||
* @note Use "" to reset callback
|
||||
*
|
||||
* @noreturn
|
||||
*/
|
||||
native SetMoveDone(const ent, const callback[]);
|
||||
|
||||
/*
|
||||
* Sets a value to CSGameRules_Members members.
|
||||
*
|
||||
|
@ -110,6 +110,23 @@ public:
|
||||
void (CBaseEntity::*m_pfnUse)(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value);
|
||||
void (CBaseEntity::*m_pfnBlocked)(CBaseEntity *pOther);
|
||||
|
||||
void EXT_FUNC DLLEXPORT SUB_Think();
|
||||
void EXT_FUNC DLLEXPORT SUB_Touch(CBaseEntity *pOther);
|
||||
void EXT_FUNC DLLEXPORT SUB_Use(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value);
|
||||
void EXT_FUNC DLLEXPORT SUB_Blocked(CBaseEntity *pOther);
|
||||
|
||||
using thinkfn_t = decltype(m_pfnThink);
|
||||
inline void SetThink(thinkfn_t pfn) { m_pfnThink = pfn; }
|
||||
|
||||
using touchfn_t = decltype(m_pfnTouch);
|
||||
inline void SetTouch(touchfn_t pfn) { m_pfnTouch = pfn; }
|
||||
|
||||
using usefn_t = decltype(m_pfnUse);
|
||||
inline void SetUse(usefn_t pfn) { m_pfnUse = pfn; }
|
||||
|
||||
using blockedfn_t = decltype(m_pfnBlocked);
|
||||
inline void SetBlocked(blockedfn_t pfn) { m_pfnBlocked = pfn; }
|
||||
|
||||
virtual void Think() = 0;
|
||||
virtual void Touch(CBaseEntity *pOther) = 0;
|
||||
virtual void Use(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType = USE_OFF, float value = 0.0f) = 0;
|
||||
@ -230,6 +247,8 @@ public:
|
||||
virtual int Restore(CRestore &restore) = 0;
|
||||
virtual int GetToggleState() = 0;
|
||||
virtual float GetDelay() = 0;
|
||||
|
||||
void EXT_FUNC DLLEXPORT SUB_MoveDone();
|
||||
public:
|
||||
TOGGLE_STATE m_toggle_state;
|
||||
float m_flActivateFinished; // like attack_finished, but for doors
|
||||
@ -247,7 +266,11 @@ public:
|
||||
int m_cTriggersLeft; // trigger_counter only, # of activations remaining
|
||||
float m_flHeight;
|
||||
EHANDLE m_hActivator;
|
||||
|
||||
void (CBaseToggle::*m_pfnCallWhenMoveDone)();
|
||||
using movedonefn_t = decltype(m_pfnCallWhenMoveDone);
|
||||
inline void SetMoveDone(movedonefn_t pfn) { m_pfnCallWhenMoveDone = pfn; }
|
||||
|
||||
Vector m_vecFinalDest;
|
||||
Vector m_vecFinalAngle;
|
||||
|
||||
|
@ -202,7 +202,9 @@
|
||||
<ClInclude Include="..\include\reunion_api.h" />
|
||||
<ClInclude Include="..\include\vtc_api.h" />
|
||||
<ClInclude Include="..\src\amxxmodule.h" />
|
||||
<ClInclude Include="..\src\amx_hook.h" />
|
||||
<ClInclude Include="..\src\api_config.h" />
|
||||
<ClInclude Include="..\src\entity_callback.h" />
|
||||
<ClInclude Include="..\src\hook_manager.h" />
|
||||
<ClInclude Include="..\src\hook_callback.h" />
|
||||
<ClInclude Include="..\src\hook_list.h" />
|
||||
@ -246,6 +248,7 @@
|
||||
<ClCompile Include="..\src\api_config.cpp" />
|
||||
<ClCompile Include="..\src\dllapi.cpp" />
|
||||
<ClCompile Include="..\src\engine_api.cpp" />
|
||||
<ClCompile Include="..\src\entity_callback.cpp" />
|
||||
<ClCompile Include="..\src\hook_manager.cpp" />
|
||||
<ClCompile Include="..\src\hook_callback.cpp" />
|
||||
<ClCompile Include="..\src\hook_list.cpp" />
|
||||
|
@ -696,6 +696,12 @@
|
||||
<ClInclude Include="..\common\info.h">
|
||||
<Filter>common</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\src\entity_callback.h">
|
||||
<Filter>src</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\src\amx_hook.h">
|
||||
<Filter>src</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\include\cssdk\common\parsemsg.cpp">
|
||||
@ -797,6 +803,9 @@
|
||||
<ClCompile Include="..\common\info.cpp">
|
||||
<Filter>common</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\src\entity_callback.cpp">
|
||||
<Filter>src</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="..\extra\amxmodx\scripting\include\reapi.inc">
|
||||
|
83
reapi/src/amx_hook.h
Normal file
83
reapi/src/amx_hook.h
Normal file
@ -0,0 +1,83 @@
|
||||
#pragma once
|
||||
|
||||
enum fwdstate
|
||||
{
|
||||
FSTATE_INVALID = 0,
|
||||
FSTATE_ENABLED,
|
||||
FSTATE_PAUSED,
|
||||
FSTATE_STOPPED
|
||||
};
|
||||
|
||||
template <typename T = int>
|
||||
class CAmxxHook
|
||||
{
|
||||
public:
|
||||
~CAmxxHook()
|
||||
{
|
||||
if (m_index != -1) {
|
||||
g_amxxapi.UnregisterSPForward(m_index);
|
||||
m_index = -1;
|
||||
}
|
||||
}
|
||||
|
||||
CAmxxHook(AMX *amx, const char *funcname, int index, T data = (T)0) :
|
||||
m_index(index),
|
||||
m_state(FSTATE_ENABLED),
|
||||
m_amx(amx),
|
||||
m_uniqueData(data)
|
||||
{
|
||||
Q_strlcpy(m_CallbackName, funcname);
|
||||
};
|
||||
|
||||
T GetUnique() const;
|
||||
int GetIndex() const;
|
||||
fwdstate GetState() const;
|
||||
AMX *GetAmx() const;
|
||||
const char *GetCallbackName() const;
|
||||
|
||||
void SetState(fwdstate st);
|
||||
|
||||
private:
|
||||
T m_uniqueData;
|
||||
int m_index;
|
||||
char m_CallbackName[64];
|
||||
fwdstate m_state;
|
||||
AMX *m_amx;
|
||||
};
|
||||
|
||||
// Inlines
|
||||
template <typename T>
|
||||
inline T CAmxxHook<T>::GetUnique() const
|
||||
{
|
||||
return m_uniqueData;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline AMX *CAmxxHook<T>::GetAmx() const
|
||||
{
|
||||
return m_amx;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline const char *CAmxxHook<T>::GetCallbackName() const
|
||||
{
|
||||
return m_CallbackName;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline int CAmxxHook<T>::GetIndex() const
|
||||
{
|
||||
return m_index;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline fwdstate CAmxxHook<T>::GetState() const
|
||||
{
|
||||
return m_state;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline void CAmxxHook<T>::SetState(fwdstate st)
|
||||
{
|
||||
m_state = st;
|
||||
}
|
@ -502,24 +502,4 @@ inline cell* getAmxAddr(AMX *amx, cell amx_addr)
|
||||
return (cell *)(amx->base + (int)(((AMX_HEADER *)amx->base)->dat + amx_addr));
|
||||
}
|
||||
|
||||
struct getAmxString
|
||||
{
|
||||
getAmxString(cell* src, size_t* len = nullptr)
|
||||
{
|
||||
getAmxStringTemp(src, temp, sizeof temp - 1, len);
|
||||
}
|
||||
|
||||
getAmxString(AMX* amx, cell addr, size_t* len = nullptr)
|
||||
{
|
||||
getAmxStringTemp(getAmxAddr(amx, addr), temp, sizeof temp - 1, len);
|
||||
}
|
||||
|
||||
operator char *()
|
||||
{
|
||||
return temp;
|
||||
}
|
||||
|
||||
char temp[1024];
|
||||
};
|
||||
|
||||
#endif // __AMXXMODULE_H__
|
||||
|
@ -109,6 +109,15 @@ DLL_FUNCTIONS gFunctionTable_Post =
|
||||
NULL, // pfnAllowLagCompensation
|
||||
};
|
||||
|
||||
NEW_DLL_FUNCTIONS g_NewDLLFuncTable =
|
||||
{
|
||||
&OnFreeEntPrivateData, //! pfnOnFreeEntPrivateData() Called right before the object's memory is freed. Calls its destructor.
|
||||
NULL, //! pfnGameShutdown()
|
||||
NULL, //! pfnShouldCollide()
|
||||
NULL, //! pfnCvarValue()
|
||||
NULL, //! pfnCvarValue2()
|
||||
};
|
||||
|
||||
C_DLLEXPORT int GetEntityAPI2(DLL_FUNCTIONS *pFunctionTable, int *interfaceVersion)
|
||||
{
|
||||
if (!pFunctionTable)
|
||||
@ -149,3 +158,23 @@ C_DLLEXPORT int GetEntityAPI2_Post(DLL_FUNCTIONS *pFunctionTable, int *interface
|
||||
memcpy(pFunctionTable, &gFunctionTable_Post, sizeof(DLL_FUNCTIONS));
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
C_DLLEXPORT int GetNewDLLFunctions(NEW_DLL_FUNCTIONS *pNewFunctionTable, int *interfaceVersion)
|
||||
{
|
||||
if (!pNewFunctionTable)
|
||||
{
|
||||
ALERT(at_logged, "GetNewDLLFunctions called with null pNewFunctionTable");
|
||||
return(FALSE);
|
||||
}
|
||||
|
||||
if (*interfaceVersion != NEW_DLL_FUNCTIONS_VERSION)
|
||||
{
|
||||
ALERT(at_logged, "GetNewDLLFunctions version mismatch; requested=%d ours=%d", *interfaceVersion, NEW_DLL_FUNCTIONS_VERSION);
|
||||
//! Tell metamod what version we had, so it can figure out who is out of date.
|
||||
*interfaceVersion = NEW_DLL_FUNCTIONS_VERSION;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
memcpy(pNewFunctionTable, &g_NewDLLFuncTable, sizeof(NEW_DLL_FUNCTIONS));
|
||||
return TRUE;
|
||||
}
|
||||
|
154
reapi/src/entity_callback.cpp
Normal file
154
reapi/src/entity_callback.cpp
Normal file
@ -0,0 +1,154 @@
|
||||
#include "precompiled.h"
|
||||
|
||||
CEntityCallback g_entCallback;
|
||||
|
||||
void CEntityCallback::PurgeCallbacks(CBaseEntity *pEntity, CallbackType_e type)
|
||||
{
|
||||
auto it = m_callbacks.begin();
|
||||
while (it != m_callbacks.end())
|
||||
{
|
||||
EntityCallback_t data = (*it)->GetUnique();
|
||||
|
||||
// this callback was already sets, need to unregister the current forward
|
||||
if (data.m_callbackType == type && data.m_entity == pEntity) {
|
||||
delete (*it);
|
||||
it = m_callbacks.erase(it);
|
||||
} else {
|
||||
it++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CEntityCallback::Clear(CBaseEntity *pEntity)
|
||||
{
|
||||
if (pEntity)
|
||||
{
|
||||
auto it = m_callbacks.begin();
|
||||
while (it != m_callbacks.end())
|
||||
{
|
||||
EntityCallback_t data = (*it)->GetUnique();
|
||||
if (data.m_entity == pEntity) {
|
||||
delete (*it);
|
||||
it = m_callbacks.erase(it);
|
||||
} else {
|
||||
it++;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (auto h : m_callbacks) {
|
||||
delete h;
|
||||
}
|
||||
|
||||
m_callbacks.clear();
|
||||
}
|
||||
}
|
||||
|
||||
bool CEntityCallback::SetThink(AMX *amx, CBaseEntity *pEntity, const char *pszCallback)
|
||||
{
|
||||
PurgeCallbacks(pEntity, CType_Think);
|
||||
|
||||
int fwdid = g_amxxapi.RegisterSPForwardByName(amx, pszCallback, FP_CELL, FP_DONE);
|
||||
if (fwdid == -1) {
|
||||
MF_LogError(amx, AMX_ERR_NATIVE, "%s: failed to register forward.", __FUNCTION__);
|
||||
return false;
|
||||
}
|
||||
|
||||
EntityCallback_t entry(pEntity, CType_Think);
|
||||
m_callbacks.push_back(new CAmxxHook<EntityCallback_t>(amx, pszCallback, fwdid, entry));
|
||||
pEntity->SetThink(&CBaseEntity::SUB_Think);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CEntityCallback::SetTouch(AMX *amx, CBaseEntity *pEntity, const char *pszCallback)
|
||||
{
|
||||
PurgeCallbacks(pEntity, CType_Touch);
|
||||
|
||||
int fwdid = g_amxxapi.RegisterSPForwardByName(amx, pszCallback, FP_CELL, FP_CELL, FP_DONE);
|
||||
if (fwdid == -1) {
|
||||
MF_LogError(amx, AMX_ERR_NATIVE, "%s: failed to register forward.", __FUNCTION__);
|
||||
return false;
|
||||
}
|
||||
|
||||
EntityCallback_t entry(pEntity, CType_Touch);
|
||||
m_callbacks.push_back(new CAmxxHook<EntityCallback_t>(amx, pszCallback, fwdid, entry));
|
||||
pEntity->SetTouch(&CBaseEntity::SUB_Touch);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CEntityCallback::SetUse(AMX *amx, CBaseEntity *pEntity, const char *pszCallback)
|
||||
{
|
||||
PurgeCallbacks(pEntity, CType_Use);
|
||||
|
||||
int fwdid = g_amxxapi.RegisterSPForwardByName(amx, pszCallback, FP_CELL, FP_CELL, FP_CELL, FP_CELL, FP_FLOAT, FP_DONE);
|
||||
if (fwdid == -1) {
|
||||
MF_LogError(amx, AMX_ERR_NATIVE, "%s: failed to register forward.", __FUNCTION__);
|
||||
return false;
|
||||
}
|
||||
|
||||
EntityCallback_t entry(pEntity, CType_Use);
|
||||
m_callbacks.push_back(new CAmxxHook<EntityCallback_t>(amx, pszCallback, fwdid, entry));
|
||||
pEntity->SetUse(&CBaseEntity::SUB_Use);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CEntityCallback::SetBlocked(AMX *amx, CBaseEntity *pEntity, const char *pszCallback)
|
||||
{
|
||||
PurgeCallbacks(pEntity, CType_Blocked);
|
||||
|
||||
int fwdid = g_amxxapi.RegisterSPForwardByName(amx, pszCallback, FP_CELL, FP_CELL, FP_DONE);
|
||||
if (fwdid == -1) {
|
||||
MF_LogError(amx, AMX_ERR_NATIVE, "%s: failed to register forward.", __FUNCTION__);
|
||||
return false;
|
||||
}
|
||||
|
||||
EntityCallback_t entry(pEntity, CType_Blocked);
|
||||
m_callbacks.push_back(new CAmxxHook<EntityCallback_t>(amx, pszCallback, fwdid, entry));
|
||||
pEntity->SetTouch(&CBaseEntity::SUB_Blocked);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CEntityCallback::SetMoveDone(AMX *amx, CBaseEntity *pEntity, const char *pszCallback)
|
||||
{
|
||||
PurgeCallbacks(pEntity, CType_MoveDone);
|
||||
|
||||
int fwdid = g_amxxapi.RegisterSPForwardByName(amx, pszCallback, FP_CELL, FP_DONE);
|
||||
if (fwdid == -1) {
|
||||
MF_LogError(amx, AMX_ERR_NATIVE, "%s: failed to register forward.", __FUNCTION__);
|
||||
return false;
|
||||
}
|
||||
|
||||
EntityCallback_t entry(pEntity, CType_MoveDone);
|
||||
m_callbacks.push_back(new CAmxxHook<EntityCallback_t>(amx, pszCallback, fwdid, entry));
|
||||
|
||||
// TODO: Make sure that the entity actually inherited from CBaseToggle
|
||||
((CBaseToggle *)pEntity)->SetMoveDone(&CBaseToggle::SUB_MoveDone);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Fundamental callbacks
|
||||
void CBaseEntity::SUB_Think()
|
||||
{
|
||||
g_entCallback.FireCallbacks(this, CEntityCallback::CType_Think, indexOfEdict(pev));
|
||||
}
|
||||
|
||||
void CBaseEntity::SUB_Touch(CBaseEntity *pOther)
|
||||
{
|
||||
g_entCallback.FireCallbacks(this, CEntityCallback::CType_Touch, indexOfEdict(pev), indexOfEdict(pOther->pev));
|
||||
}
|
||||
|
||||
void CBaseEntity::SUB_Use(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value)
|
||||
{
|
||||
g_entCallback.FireCallbacks(this, CEntityCallback::CType_Use, indexOfEdict(pev), indexOfEdict(pActivator->pev), indexOfEdict(pCaller->pev), useType, value);
|
||||
}
|
||||
|
||||
void CBaseEntity::SUB_Blocked(CBaseEntity *pOther)
|
||||
{
|
||||
g_entCallback.FireCallbacks(this, CEntityCallback::CType_Blocked, indexOfEdict(pev), indexOfEdict(pOther->pev));
|
||||
}
|
||||
|
||||
void CBaseToggle::SUB_MoveDone()
|
||||
{
|
||||
g_entCallback.FireCallbacks(this, CEntityCallback::CType_MoveDone, indexOfEdict(pev));
|
||||
}
|
49
reapi/src/entity_callback.h
Normal file
49
reapi/src/entity_callback.h
Normal file
@ -0,0 +1,49 @@
|
||||
#pragma once
|
||||
|
||||
#include "amx_hook.h"
|
||||
|
||||
class CEntityCallback
|
||||
{
|
||||
public:
|
||||
void Clear(CBaseEntity *pEntity = nullptr);
|
||||
|
||||
bool SetThink (AMX *amx, CBaseEntity *pEntity, const char *pszCallback);
|
||||
bool SetTouch (AMX *amx, CBaseEntity *pEntity, const char *pszCallback);
|
||||
bool SetUse (AMX *amx, CBaseEntity *pEntity, const char *pszCallback);
|
||||
bool SetBlocked (AMX *amx, CBaseEntity *pEntity, const char *pszCallback);
|
||||
bool SetMoveDone(AMX *amx, CBaseEntity *pEntity, const char *pszCallback);
|
||||
|
||||
enum CallbackType_e
|
||||
{
|
||||
CType_Think,
|
||||
CType_Touch,
|
||||
CType_Use,
|
||||
CType_Blocked,
|
||||
CType_MoveDone,
|
||||
};
|
||||
|
||||
template <typename ...f_args>
|
||||
void FireCallbacks(CBaseEntity *pEntity, CallbackType_e type, volatile f_args... args)
|
||||
{
|
||||
for (auto fwd : m_callbacks) {
|
||||
if (fwd->GetUnique().m_entity == pEntity && fwd->GetUnique().m_callbackType == type) {
|
||||
g_amxxapi.ExecuteForward(fwd->GetIndex(), args...);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
void PurgeCallbacks(CBaseEntity *pEntity, CallbackType_e type);
|
||||
struct EntityCallback_t
|
||||
{
|
||||
EntityCallback_t(CBaseEntity *pEntity, CallbackType_e type) :
|
||||
m_entity(pEntity), m_callbackType(type) {};
|
||||
|
||||
CBaseEntity *m_entity;
|
||||
CallbackType_e m_callbackType;
|
||||
};
|
||||
|
||||
std::vector<CAmxxHook<EntityCallback_t> *> m_callbacks;
|
||||
};
|
||||
|
||||
extern CEntityCallback g_entCallback;
|
@ -5,14 +5,14 @@
|
||||
|
||||
#define BEGIN_FUNC_REGION(x) (MAX_REGION_RANGE * hooklist_t::hooks_tables_e::ht_##x)
|
||||
|
||||
typedef bool (*reqfunc_t)();
|
||||
typedef int (*regfunc_t)(AMX *, const char *);
|
||||
typedef bool (*reqfunc_t) ();
|
||||
typedef int (*regfunc_t) (AMX *, const char *);
|
||||
typedef void (*regchain_t)();
|
||||
|
||||
struct hook_t
|
||||
{
|
||||
std::vector<class CAmxxHook *> pre; // pre forwards
|
||||
std::vector<class CAmxxHook *> post; // post forwards
|
||||
std::vector<class CAmxxHook<> *> pre; // pre forwards
|
||||
std::vector<class CAmxxHook<> *> post; // post forwards
|
||||
|
||||
const char *func_name; // function name
|
||||
const char *depend_name; // platform dependency
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
CHookManager g_hookManager;
|
||||
|
||||
int CHookManager::addHandler(AMX* amx, int func, const char *funcname, int forward, bool post) const
|
||||
int CHookManager::addHandler(AMX *amx, int func, const char *funcname, int forward, bool post) const
|
||||
{
|
||||
auto hook = m_hooklist.getHookSafe(func);
|
||||
|
||||
@ -13,47 +13,22 @@ int CHookManager::addHandler(AMX* amx, int func, const char *funcname, int forwa
|
||||
}
|
||||
|
||||
auto& dest = post ? hook->post : hook->pre;
|
||||
dest.push_back(new CAmxxHook(amx, funcname, forward));
|
||||
dest.push_back(new CAmxxHook<>(amx, funcname, forward));
|
||||
int id = func * MAX_HOOK_FORWARDS + dest.size();
|
||||
return post ? -id : id; // use unsigned ids for post hooks
|
||||
}
|
||||
|
||||
AMX* CAmxxHook::GetAmx() const
|
||||
{
|
||||
return m_amx;
|
||||
}
|
||||
|
||||
const char *CAmxxHook::GetCallbackName() const
|
||||
{
|
||||
return m_CallbackName;
|
||||
}
|
||||
|
||||
int CAmxxHook::GetIndex() const
|
||||
{
|
||||
return m_index;
|
||||
}
|
||||
|
||||
fwdstate CAmxxHook::GetState() const
|
||||
{
|
||||
return m_state;
|
||||
}
|
||||
|
||||
void CAmxxHook::SetState(fwdstate st)
|
||||
{
|
||||
m_state = st;
|
||||
}
|
||||
|
||||
void CHookManager::Clear() const
|
||||
{
|
||||
m_hooklist.clear();
|
||||
}
|
||||
|
||||
hook_t* CHookManager::getHook(size_t func) const
|
||||
hook_t *CHookManager::getHook(size_t func) const
|
||||
{
|
||||
return m_hooklist.getHookSafe(func);
|
||||
}
|
||||
|
||||
CAmxxHook* CHookManager::getAmxxHook(cell handle) const
|
||||
CAmxxHook<> *CHookManager::getAmxxHook(cell handle) const
|
||||
{
|
||||
bool post = handle < 0;
|
||||
|
||||
|
@ -1,46 +1,17 @@
|
||||
#pragma once
|
||||
|
||||
#include "amx_hook.h"
|
||||
#include "hook_list.h"
|
||||
|
||||
enum fwdstate
|
||||
{
|
||||
FSTATE_INVALID = 0,
|
||||
FSTATE_ENABLED,
|
||||
FSTATE_PAUSED,
|
||||
FSTATE_STOPPED
|
||||
};
|
||||
|
||||
class CAmxxHook
|
||||
{
|
||||
public:
|
||||
CAmxxHook(AMX* amx, const char *funcname, int index) : m_index(index), m_state(FSTATE_ENABLED), m_amx(amx)
|
||||
{
|
||||
strncpy(m_CallbackName, funcname, sizeof(m_CallbackName) - 1);
|
||||
m_CallbackName[sizeof(m_CallbackName) - 1] = '\0';
|
||||
};
|
||||
|
||||
int GetIndex() const;
|
||||
fwdstate GetState() const;
|
||||
AMX* GetAmx() const;
|
||||
const char *GetCallbackName() const;
|
||||
|
||||
void SetState(fwdstate st);
|
||||
|
||||
private:
|
||||
int m_index;
|
||||
char m_CallbackName[64];
|
||||
fwdstate m_state;
|
||||
AMX* m_amx;
|
||||
};
|
||||
|
||||
class CHookManager
|
||||
{
|
||||
public:
|
||||
void Clear() const;
|
||||
cell addHandler(AMX* amx, int func, const char *funcname, int forward, bool post) const;
|
||||
hook_t* getHook(size_t func) const;
|
||||
CAmxxHook* getAmxxHook(cell hook) const;
|
||||
cell addHandler(AMX *amx, int func, const char *funcname, int forward, bool post) const;
|
||||
hook_t *getHook(size_t func) const;
|
||||
CAmxxHook<> *getAmxxHook(cell hook) const;
|
||||
|
||||
hook_t* getHookFast(size_t func) const {
|
||||
hook_t *getHookFast(size_t func) const {
|
||||
return m_hooklist[func];
|
||||
}
|
||||
|
||||
|
@ -69,6 +69,7 @@ void ServerDeactivate_Post()
|
||||
api_cfg.ServerDeactivate();
|
||||
g_hookManager.Clear();
|
||||
g_queryFileManager.Clear();
|
||||
g_entCallback.Clear();
|
||||
|
||||
g_pFunctionTable->pfnSpawn = DispatchSpawn;
|
||||
g_pFunctionTable->pfnKeyValue = KeyValue;
|
||||
@ -118,3 +119,14 @@ void ResetGlobalState()
|
||||
|
||||
SET_META_RESULT(MRES_IGNORED);
|
||||
}
|
||||
|
||||
void OnFreeEntPrivateData(edict_t *pEdict)
|
||||
{
|
||||
CBaseEntity *pEntity = getPrivate<CBaseEntity>(pEdict);
|
||||
if (!pEntity){
|
||||
return;
|
||||
}
|
||||
|
||||
g_entCallback.Clear(pEntity);
|
||||
SET_META_RESULT(MRES_IGNORED);
|
||||
}
|
||||
|
@ -13,6 +13,7 @@ void OnAmxxAttach();
|
||||
bool OnMetaAttach();
|
||||
void OnMetaDetach();
|
||||
|
||||
void OnFreeEntPrivateData(edict_t *pEdict);
|
||||
void ServerActivate_Post(edict_t *pEdictList, int edictCount, int clientMax);
|
||||
void ServerDeactivate_Post();
|
||||
int DispatchSpawn(edict_t* pEntity);
|
||||
|
@ -255,6 +255,197 @@ cell AMX_NATIVE_CALL amx_GetAttachment(AMX *amx, cell *params)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Sets callback for entity
|
||||
*
|
||||
* @param entity Entity index
|
||||
* @param callback The forward to call
|
||||
* @note Use "" to reset callback
|
||||
*
|
||||
* @noreturn
|
||||
*
|
||||
* native SetThink(const ent, const callback[]);
|
||||
*/
|
||||
cell AMX_NATIVE_CALL amx_SetThink(AMX *amx, cell *params)
|
||||
{
|
||||
enum args_e { arg_count, arg_index, arg_handler };
|
||||
|
||||
CHECK_ISENTITY(arg_index);
|
||||
|
||||
CBaseEntity *pEntity = getPrivate<CBaseEntity>(params[arg_index]);
|
||||
if (unlikely(pEntity == nullptr)) {
|
||||
MF_LogError(amx, AMX_ERR_NATIVE, "%s: invalid or uninitialized entity", __FUNCTION__);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
int funcid;
|
||||
const char *funcname = getAmxString(amx, params[arg_handler]);
|
||||
if (unlikely(funcname == nullptr || funcname[0] == '\0')) {
|
||||
pEntity->SetThink(nullptr);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (unlikely(g_amxxapi.amx_FindPublic(amx, funcname, &funcid) != AMX_ERR_NONE)) {
|
||||
MF_LogError(amx, AMX_ERR_NATIVE, "%s: public function \"%s\" not found.", __FUNCTION__, funcname);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return (cell)g_entCallback.SetThink(amx, pEntity, funcname);
|
||||
}
|
||||
|
||||
/*
|
||||
* Sets callback for entity
|
||||
*
|
||||
* @param entity Entity index
|
||||
* @param callback The forward to call
|
||||
* @note Use "" to reset callback
|
||||
*
|
||||
* @noreturn
|
||||
*
|
||||
* native SetTouch(const ent, const callback[]);
|
||||
*/
|
||||
cell AMX_NATIVE_CALL amx_SetTouch(AMX *amx, cell *params)
|
||||
{
|
||||
enum args_e { arg_count, arg_index, arg_handler };
|
||||
|
||||
CHECK_ISENTITY(arg_index);
|
||||
|
||||
CBaseEntity *pEntity = getPrivate<CBaseEntity>(params[arg_index]);
|
||||
if (unlikely(pEntity == nullptr)) {
|
||||
MF_LogError(amx, AMX_ERR_NATIVE, "%s: invalid or uninitialized entity", __FUNCTION__);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
int funcid;
|
||||
const char *funcname = getAmxString(amx, params[arg_handler]);
|
||||
if (unlikely(funcname == nullptr || funcname[0] == '\0')) {
|
||||
pEntity->SetTouch(nullptr);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (unlikely(g_amxxapi.amx_FindPublic(amx, funcname, &funcid) != AMX_ERR_NONE)) {
|
||||
MF_LogError(amx, AMX_ERR_NATIVE, "%s: public function \"%s\" not found.", __FUNCTION__, funcname);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return (cell)g_entCallback.SetTouch(amx, pEntity, funcname);
|
||||
}
|
||||
|
||||
/*
|
||||
* Sets callback for entity
|
||||
*
|
||||
* @param entity Entity index
|
||||
* @param callback The forward to call
|
||||
* @note Use "" to reset callback
|
||||
*
|
||||
* @noreturn
|
||||
*
|
||||
* native SetUse(const ent, const callback[]);
|
||||
*/
|
||||
cell AMX_NATIVE_CALL amx_SetUse(AMX *amx, cell *params)
|
||||
{
|
||||
enum args_e { arg_count, arg_index, arg_handler };
|
||||
|
||||
CHECK_ISENTITY(arg_index);
|
||||
|
||||
CBaseEntity *pEntity = getPrivate<CBaseEntity>(params[arg_index]);
|
||||
if (unlikely(pEntity == nullptr)) {
|
||||
MF_LogError(amx, AMX_ERR_NATIVE, "%s: invalid or uninitialized entity", __FUNCTION__);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
int funcid;
|
||||
const char *funcname = getAmxString(amx, params[arg_handler]);
|
||||
if (unlikely(funcname == nullptr || funcname[0] == '\0')) {
|
||||
pEntity->SetUse(nullptr);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (unlikely(g_amxxapi.amx_FindPublic(amx, funcname, &funcid) != AMX_ERR_NONE)) {
|
||||
MF_LogError(amx, AMX_ERR_NATIVE, "%s: public function \"%s\" not found.", __FUNCTION__, funcname);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return (cell)g_entCallback.SetUse(amx, pEntity, funcname);
|
||||
}
|
||||
|
||||
/*
|
||||
* Sets callback for entity
|
||||
*
|
||||
* @param entity Entity index
|
||||
* @param callback The forward to call
|
||||
* @note Use "" to reset callback
|
||||
*
|
||||
* @noreturn
|
||||
*
|
||||
* native SetBlocked(const ent, const callback[]);
|
||||
*/
|
||||
cell AMX_NATIVE_CALL amx_SetBlocked(AMX *amx, cell *params)
|
||||
{
|
||||
enum args_e { arg_count, arg_index, arg_handler };
|
||||
|
||||
CHECK_ISENTITY(arg_index);
|
||||
|
||||
CBaseEntity *pEntity = getPrivate<CBaseEntity>(params[arg_index]);
|
||||
if (unlikely(pEntity == nullptr)) {
|
||||
MF_LogError(amx, AMX_ERR_NATIVE, "%s: invalid or uninitialized entity", __FUNCTION__);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
int funcid;
|
||||
const char *funcname = getAmxString(amx, params[arg_handler]);
|
||||
if (unlikely(funcname == nullptr || funcname[0] == '\0')) {
|
||||
pEntity->SetBlocked(nullptr);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (unlikely(g_amxxapi.amx_FindPublic(amx, funcname, &funcid) != AMX_ERR_NONE)) {
|
||||
MF_LogError(amx, AMX_ERR_NATIVE, "%s: public function \"%s\" not found.", __FUNCTION__, funcname);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return (cell)g_entCallback.SetBlocked(amx, pEntity, funcname);
|
||||
}
|
||||
|
||||
/*
|
||||
* Sets callback for entity
|
||||
* @note Entity should be inherited from CBaseToggle, otherwise server can crash
|
||||
*
|
||||
* @param entity Entity index
|
||||
* @param callback The forward to call
|
||||
* @note Use "" to reset callback
|
||||
*
|
||||
* @noreturn
|
||||
*
|
||||
* native SetMoveDone(const ent, const callback[]);
|
||||
*/
|
||||
cell AMX_NATIVE_CALL amx_SetMoveDone(AMX *amx, cell *params)
|
||||
{
|
||||
enum args_e { arg_count, arg_index, arg_handler };
|
||||
|
||||
CHECK_ISENTITY(arg_index);
|
||||
|
||||
CBaseEntity *pEntity = getPrivate<CBaseEntity>(params[arg_index]);
|
||||
if (unlikely(pEntity == nullptr)) {
|
||||
MF_LogError(amx, AMX_ERR_NATIVE, "%s: invalid or uninitialized entity", __FUNCTION__);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
int funcid;
|
||||
const char *funcname = getAmxString(amx, params[arg_handler]);
|
||||
if (unlikely(funcname == nullptr || funcname[0] == '\0')) {
|
||||
((CBaseToggle *)pEntity)->SetMoveDone(nullptr);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (unlikely(g_amxxapi.amx_FindPublic(amx, funcname, &funcid) != AMX_ERR_NONE)) {
|
||||
MF_LogError(amx, AMX_ERR_NATIVE, "%s: public function \"%s\" not found.", __FUNCTION__, funcname);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return (cell)g_entCallback.SetMoveDone(amx, pEntity, funcname);
|
||||
}
|
||||
|
||||
AMX_NATIVE_INFO Natives_Common[] =
|
||||
{
|
||||
{ "FClassnameIs", amx_FClassnameIs },
|
||||
@ -265,6 +456,11 @@ AMX_NATIVE_INFO Natives_Common[] =
|
||||
{ "set_key_value", amx_set_key_value },
|
||||
{ "GetBonePosition", amx_GetBonePosition },
|
||||
{ "GetAttachment", amx_GetAttachment },
|
||||
{ "SetThink", amx_SetThink },
|
||||
{ "SetTouch", amx_SetTouch },
|
||||
{ "SetUse", amx_SetUse },
|
||||
{ "SetBlocked", amx_SetBlocked },
|
||||
{ "SetMoveDone", amx_SetMoveDone },
|
||||
|
||||
{ nullptr, nullptr }
|
||||
};
|
||||
|
@ -3,7 +3,7 @@
|
||||
#define PARAMS_COUNT (params[0] / sizeof(cell))
|
||||
|
||||
#define CHECK_ISPLAYER(x) if (unlikely(params[x] <= 0 || params[x] > gpGlobals->maxClients)) { MF_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] > gpGlobals->maxEntities)) { MF_LogError(amx, AMX_ERR_NATIVE, "%s: invalid entity index %i [%s]", __FUNCTION__, params[x], #x); return FALSE; }
|
||||
#define CHECK_ISENTITY(x) if (unlikely(params[x] < 0 || params[x] > gpGlobals->maxEntities)) { MF_LogError(amx, AMX_ERR_NATIVE, "%s: invalid entity index %i [%s]", __FUNCTION__, params[x], #x); return FALSE; }
|
||||
#define CHECK_GAMERULES() if (unlikely(!g_pGameRules)) { MF_LogError(amx, AMX_ERR_NATIVE, "%s: gamerules not initialized", __FUNCTION__); return FALSE; }
|
||||
#define CHECK_CONNECTED(x, y) if (unlikely(x == nullptr || x->has_disconnected)) { MF_LogError(amx, AMX_ERR_NATIVE, "%s: player %i is not connected", __FUNCTION__, params[y]); return FALSE; }
|
||||
|
||||
@ -98,6 +98,26 @@ private:
|
||||
cell* m_params;
|
||||
};
|
||||
|
||||
struct getAmxString
|
||||
{
|
||||
getAmxString(cell* src, size_t* len = nullptr)
|
||||
{
|
||||
getAmxStringTemp(src, temp, sizeof temp - 1, len);
|
||||
}
|
||||
|
||||
getAmxString(AMX* amx, cell addr, size_t* len = nullptr)
|
||||
{
|
||||
getAmxStringTemp(getAmxAddr(amx, addr), temp, sizeof temp - 1, len);
|
||||
}
|
||||
|
||||
operator char *()
|
||||
{
|
||||
return temp;
|
||||
}
|
||||
|
||||
char temp[1024];
|
||||
};
|
||||
|
||||
inline void fillNatives(AMX_NATIVE_INFO* table, cell (AMX_NATIVE_CALL with)(AMX *, cell *))
|
||||
{
|
||||
for (size_t i = 0; table[i].name; i++)
|
||||
|
@ -63,6 +63,7 @@
|
||||
#include "api_config.h"
|
||||
#include "hook_manager.h"
|
||||
#include "hook_callback.h"
|
||||
#include "entity_callback.h"
|
||||
#include "member_list.h"
|
||||
|
||||
// natives
|
||||
|
Loading…
x
Reference in New Issue
Block a user