mirror of
https://github.com/Haze1337/sendproxy_archive.git
synced 2025-12-06 18:28:21 +00:00
939 lines
28 KiB
C++
939 lines
28 KiB
C++
/**
|
|
* vim: set ts=4 :
|
|
* =============================================================================
|
|
* SendVar Proxy Manager
|
|
* Copyright (C) 2011-2019 Afronanny & AlliedModders community. All rights reserved.
|
|
* =============================================================================
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify it under
|
|
* the terms of the GNU General Public License, version 3.0, as published by the
|
|
* Free Software Foundation.
|
|
*
|
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
|
* details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License along with
|
|
* this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*
|
|
* As a special exception, AlliedModders LLC gives you permission to link the
|
|
* code of this program (as well as its derivative works) to "Half-Life 2," the
|
|
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
|
|
* by the Valve Corporation. You must obey the GNU General Public License in
|
|
* all respects for all other code used. Additionally, AlliedModders LLC grants
|
|
* this exception to all derivative works. AlliedModders LLC defines further
|
|
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
|
|
* or <http://www.sourcemod.net/license.php>.
|
|
*
|
|
* Version: $Id$
|
|
*/
|
|
|
|
#include "interfaceimpl.h"
|
|
|
|
SH_DECL_HOOK0_void(IExtensionInterface, OnExtensionUnload, SH_NOATTRIB, false);
|
|
|
|
void Hook_OnExtensionUnload()
|
|
{
|
|
IExtensionInterface * pExtAPI = META_IFACEPTR(IExtensionInterface);
|
|
auto it = g_Hooks.begin();
|
|
while(it != g_Hooks.end())
|
|
{
|
|
auto &hook = *it;
|
|
|
|
//remove all listeners for this extension
|
|
auto &listeners = hook.vListeners;
|
|
auto it2 = listeners.begin();
|
|
while(it2 != listeners.end()) {
|
|
if (it2->m_pExtAPI == pExtAPI) {
|
|
listeners.erase(it2);
|
|
continue;
|
|
}
|
|
++it2;
|
|
}
|
|
|
|
//remove hook for this extension
|
|
if (hook.sCallbackInfo.iCallbackType == CallBackType::Callback_CPPCallbackInterface &&
|
|
static_cast<IExtension *>(hook.sCallbackInfo.pOwner)->GetAPI() == pExtAPI) {
|
|
g_SendProxyManager.UnhookProxy(hook);
|
|
g_Hooks.erase(it);
|
|
continue;
|
|
}
|
|
|
|
++it;
|
|
}
|
|
|
|
auto it2 = g_HooksGamerules.begin();
|
|
while(it2 != g_HooksGamerules.end()) {
|
|
auto &hook = *it2;
|
|
|
|
//remove all listeners for this extension
|
|
auto &listeners = hook.vListeners;
|
|
auto it3 = listeners.begin();
|
|
while(it3 != listeners.end()) {
|
|
if (it3->m_pExtAPI == pExtAPI) {
|
|
listeners.erase(it3);
|
|
continue;
|
|
}
|
|
++it3;
|
|
}
|
|
|
|
//remove hook for this extension
|
|
if (hook.sCallbackInfo.iCallbackType == CallBackType::Callback_CPPCallbackInterface &&
|
|
static_cast<IExtension *>(hook.sCallbackInfo.pOwner)->GetAPI() == pExtAPI) {
|
|
g_SendProxyManager.UnhookProxyGamerules(hook);
|
|
g_HooksGamerules.erase(it2);
|
|
continue;
|
|
}
|
|
|
|
++it2;
|
|
}
|
|
SH_REMOVE_HOOK(IExtensionInterface, OnExtensionUnload, pExtAPI, SH_STATIC(Hook_OnExtensionUnload), false);
|
|
RETURN_META(MRES_IGNORED);
|
|
}
|
|
|
|
void HookExtensionUnload(IExtension * pExt)
|
|
{
|
|
if (!pExt)
|
|
return;
|
|
|
|
bool bHookedAlready = false;
|
|
for (auto &it : g_Hooks)
|
|
{
|
|
if (it.sCallbackInfo.pOwner == pExt)
|
|
{
|
|
bHookedAlready = true;
|
|
break;
|
|
}
|
|
else {
|
|
for (auto &it2 : it.vListeners)
|
|
{
|
|
if (it2.m_pExtAPI == pExt->GetAPI())
|
|
{
|
|
bHookedAlready = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (!bHookedAlready) {
|
|
for (auto &it : g_HooksGamerules)
|
|
{
|
|
if (it.sCallbackInfo.pOwner == pExt)
|
|
{
|
|
bHookedAlready = true;
|
|
break;
|
|
}
|
|
else {
|
|
for (auto &it2 : it.vListeners)
|
|
{
|
|
if (it2.m_pExtAPI == pExt->GetAPI())
|
|
{
|
|
bHookedAlready = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (!bHookedAlready) //Hook only if needed!
|
|
SH_ADD_HOOK(IExtensionInterface, OnExtensionUnload, pExt->GetAPI(), SH_STATIC(Hook_OnExtensionUnload), false);
|
|
}
|
|
|
|
void UnhookExtensionUnload(IExtension * pExt)
|
|
{
|
|
if (!pExt)
|
|
return;
|
|
|
|
bool bHaveHooks = false;
|
|
for (auto &it : g_Hooks)
|
|
{
|
|
if (it.sCallbackInfo.pOwner == pExt)
|
|
{
|
|
bHaveHooks = true;
|
|
break;
|
|
}
|
|
else {
|
|
auto &listeners = it.vListeners;
|
|
for (auto &it2 : listeners)
|
|
{
|
|
if (it2.m_pExtAPI == pExt->GetAPI())
|
|
{
|
|
bHaveHooks = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (!bHaveHooks) {
|
|
for (auto &it : g_HooksGamerules)
|
|
{
|
|
if (it.sCallbackInfo.pOwner == pExt)
|
|
{
|
|
bHaveHooks = true;
|
|
break;
|
|
}
|
|
else {
|
|
auto &listeners = it.vListeners;
|
|
for (auto &it2 : listeners)
|
|
{
|
|
if (it2.m_pExtAPI == pExt->GetAPI())
|
|
{
|
|
bHaveHooks = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!bHaveHooks) //so, if there are active hooks, we shouldn't remove hook!
|
|
SH_REMOVE_HOOK(IExtensionInterface, OnExtensionUnload, pExt->GetAPI(), SH_STATIC(Hook_OnExtensionUnload), false);
|
|
}
|
|
|
|
void CallListenersForHook(const SendPropHook &hook)
|
|
{
|
|
for (auto &it : hook.vListeners)
|
|
{
|
|
it.m_pCallBack->OnEntityPropHookRemoved(gameents->EdictToBaseEntity(hook.pEnt), hook.pVar, hook.propType, hook.sCallbackInfo.iCallbackType, hook.sCallbackInfo.pCallback);
|
|
}
|
|
}
|
|
|
|
void CallListenersForHookGamerules(const SendPropHookGamerules &hook)
|
|
{
|
|
for (auto &it : hook.vListeners)
|
|
{
|
|
it.m_pCallBack->OnGamerulesPropHookRemoved(hook.pVar, hook.propType, hook.sCallbackInfo.iCallbackType, hook.sCallbackInfo.pCallback);
|
|
}
|
|
}
|
|
|
|
//interface
|
|
|
|
const char * SendProxyManagerInterfaceImpl::GetInterfaceName() { return SMINTERFACE_SENDPROXY_NAME; }
|
|
unsigned int SendProxyManagerInterfaceImpl::GetInterfaceVersion() { return SMINTERFACE_SENDPROXY_VERSION; }
|
|
|
|
bool SendProxyManagerInterfaceImpl::HookProxy(IExtension * pExt, SendProp * pProp, CBaseEntity * pEntity, PropType iType, CallBackType iCallbackType, void * pCallback, bool per_client)
|
|
{
|
|
if (!pEntity)
|
|
return false;
|
|
|
|
edict_t * pEdict = gameents->BaseEntityToEdict(pEntity);
|
|
if (!pEdict || pEdict->IsFree())
|
|
return false;
|
|
|
|
if (!IsPropValid(pProp, iType))
|
|
return false;
|
|
|
|
SendPropHook hook;
|
|
hook.objectID = gamehelpers->IndexOfEdict(pEdict);
|
|
hook.sCallbackInfo.pCallback = pCallback;
|
|
hook.sCallbackInfo.iCallbackType = iCallbackType;
|
|
hook.sCallbackInfo.pOwner = (void *)pExt;
|
|
hook.propType = iType;
|
|
hook.pEnt = pEdict;
|
|
hook.pVar = pProp;
|
|
hook.per_client = per_client;
|
|
bool bHookedAlready = false;
|
|
for (auto &it : g_Hooks)
|
|
{
|
|
if (it.pVar == pProp)
|
|
{
|
|
hook.pRealProxy = it.pRealProxy;
|
|
bHookedAlready = true;
|
|
break;
|
|
}
|
|
}
|
|
if (!bHookedAlready)
|
|
hook.pRealProxy = pProp->GetProxyFn();
|
|
HookExtensionUnload(pExt);
|
|
if (g_SendProxyManager.AddHookToList(std::move(hook)))
|
|
{
|
|
if (!bHookedAlready)
|
|
pProp->SetProxyFn(GlobalProxy);
|
|
}
|
|
else
|
|
{
|
|
UnhookExtensionUnload(pExt);
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool SendProxyManagerInterfaceImpl::HookProxy(IExtension * pExt, const char * pProp, CBaseEntity * pEntity, PropType iType, CallBackType iCallbackType, void * pCallback, bool per_client)
|
|
{
|
|
if (!pProp || !*pProp)
|
|
return false;
|
|
if (!pEntity)
|
|
return false;
|
|
ServerClass * sc = ((IServerUnknown *)pEntity)->GetNetworkable()->GetServerClass();
|
|
if (!sc)
|
|
return false; //we don't use exceptions, bad extensions may do not handle this and server will crashed, just return false
|
|
sm_sendprop_info_t info;
|
|
gamehelpers->FindSendPropInfo(sc->GetName(), pProp, &info);
|
|
SendProp * pSendProp = info.prop;
|
|
if (pSendProp)
|
|
return HookProxy(pExt, pSendProp, pEntity, iType, iCallbackType, pCallback, per_client);
|
|
return false;
|
|
}
|
|
|
|
bool SendProxyManagerInterfaceImpl::HookProxyGamerules(IExtension * pExt, SendProp * pProp, PropType iType, CallBackType iCallbackType, void * pCallback, bool per_client)
|
|
{
|
|
if (!IsPropValid(pProp, iType))
|
|
return false;
|
|
|
|
SendPropHookGamerules hook;
|
|
hook.sCallbackInfo.pCallback = pCallback;
|
|
hook.sCallbackInfo.iCallbackType = iCallbackType;
|
|
hook.sCallbackInfo.pOwner = (void *)pExt;
|
|
bool bHookedAlready = false;
|
|
for (auto &it : g_HooksGamerules)
|
|
{
|
|
if (it.pVar == pProp)
|
|
{
|
|
hook.pRealProxy = it.pRealProxy;
|
|
bHookedAlready = true;
|
|
break;
|
|
}
|
|
}
|
|
if (!bHookedAlready)
|
|
hook.pRealProxy = pProp->GetProxyFn();
|
|
hook.propType = iType;
|
|
hook.pVar = pProp;
|
|
hook.per_client = per_client;
|
|
sm_sendprop_info_t info;
|
|
gamehelpers->FindSendPropInfo(g_szGameRulesProxy, pProp->GetName(), &info);
|
|
|
|
//if this prop has been hooked already, don't set the proxy again
|
|
HookExtensionUnload(pExt);
|
|
if (bHookedAlready)
|
|
{
|
|
if (g_SendProxyManager.AddHookToListGamerules(std::move(hook)))
|
|
return true;
|
|
UnhookExtensionUnload(pExt);
|
|
return false;
|
|
}
|
|
if (g_SendProxyManager.AddHookToListGamerules(std::move(hook)))
|
|
{
|
|
pProp->SetProxyFn(GlobalProxyGamerules);
|
|
return true;
|
|
}
|
|
UnhookExtensionUnload(pExt);
|
|
return false;
|
|
}
|
|
|
|
bool SendProxyManagerInterfaceImpl::HookProxyGamerules(IExtension * pExt, const char * pProp, PropType iType, CallBackType iCallbackType, void * pCallback, bool per_client)
|
|
{
|
|
if (!pProp || !*pProp)
|
|
return false;
|
|
sm_sendprop_info_t info;
|
|
gamehelpers->FindSendPropInfo(g_szGameRulesProxy, pProp, &info);
|
|
SendProp * pSendProp = info.prop;
|
|
if (pSendProp)
|
|
return HookProxyGamerules(pExt, pSendProp, iType, iCallbackType, pCallback, per_client);
|
|
return false;
|
|
}
|
|
|
|
bool SendProxyManagerInterfaceImpl::UnhookProxy(IExtension * pExt, SendProp * pProp, CBaseEntity * pEntity, CallBackType iCallbackType, void * pCallback)
|
|
{
|
|
const char * pPropName = pProp->GetName();
|
|
return UnhookProxy(pExt, pPropName, pEntity, iCallbackType, pCallback);
|
|
}
|
|
|
|
bool SendProxyManagerInterfaceImpl::UnhookProxy(IExtension * pExt, const char * pProp, CBaseEntity * pEntity, CallBackType iCallbackType, void * pCallback)
|
|
{
|
|
if (!pProp || !*pProp)
|
|
return false;
|
|
edict_t * pEdict = gameents->BaseEntityToEdict(pEntity);
|
|
auto it = g_Hooks.begin();
|
|
while(it != g_Hooks.end()) {
|
|
auto &hook = *it;
|
|
|
|
if (hook.sCallbackInfo.pOwner == pExt &&
|
|
pEdict == hook.pEnt &&
|
|
hook.sCallbackInfo.iCallbackType == iCallbackType &&
|
|
!strcmp(hook.pVar->GetName(), pProp) &&
|
|
pCallback == hook.sCallbackInfo.pCallback)
|
|
{
|
|
g_SendProxyManager.UnhookProxy(hook);
|
|
g_Hooks.erase(it);
|
|
UnhookExtensionUnload(pExt);
|
|
return true;
|
|
}
|
|
|
|
++it;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool SendProxyManagerInterfaceImpl::UnhookProxyGamerules(IExtension * pExt, SendProp * pProp, CallBackType iCallbackType, void * pCallback)
|
|
{
|
|
const char * pPropName = pProp->GetName();
|
|
return UnhookProxyGamerules(pExt, pPropName, iCallbackType, pCallback);
|
|
}
|
|
|
|
bool SendProxyManagerInterfaceImpl::UnhookProxyGamerules(IExtension * pExt, const char * pProp, CallBackType iCallbackType, void * pCallback)
|
|
{
|
|
if (!pProp || !*pProp)
|
|
return false;
|
|
|
|
auto it = g_HooksGamerules.begin();
|
|
while(it != g_HooksGamerules.end()) {
|
|
auto &hook = *it;
|
|
|
|
if (hook.sCallbackInfo.pOwner == pExt &&
|
|
hook.sCallbackInfo.iCallbackType == iCallbackType &&
|
|
!strcmp(hook.pVar->GetName(), pProp) &&
|
|
pCallback == hook.sCallbackInfo.pCallback)
|
|
{
|
|
g_SendProxyManager.UnhookProxyGamerules(hook);
|
|
g_HooksGamerules.erase(it);
|
|
UnhookExtensionUnload(pExt);
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool SendProxyManagerInterfaceImpl::AddUnhookListener(IExtension * pExt, SendProp * pProp, CBaseEntity * pEntity, CallBackType iCallbackType, void * pCallback, ISendProxyUnhookListener * pListener)
|
|
{
|
|
const char * pPropName = pProp->GetName();
|
|
return AddUnhookListener(pExt, pPropName, pEntity, iCallbackType, pCallback, pListener);
|
|
}
|
|
|
|
bool SendProxyManagerInterfaceImpl::AddUnhookListener(IExtension * pExt, const char * pProp, CBaseEntity * pEntity, CallBackType iCallbackType, void * pCallback, ISendProxyUnhookListener * pListener)
|
|
{
|
|
if (!pProp || !*pProp)
|
|
return false;
|
|
edict_t * pEdict = gameents->BaseEntityToEdict(pEntity);
|
|
for (auto &it : g_Hooks) {
|
|
if (pEdict == it.pEnt &&
|
|
it.sCallbackInfo.iCallbackType == iCallbackType &&
|
|
!strcmp(it.pVar->GetName(), pProp) &&
|
|
pCallback == it.sCallbackInfo.pCallback)
|
|
{
|
|
ListenerCallbackInfo info;
|
|
info.m_pExt = pExt;
|
|
info.m_pExtAPI = pExt->GetAPI();
|
|
info.m_pCallBack = pListener;
|
|
HookExtensionUnload(pExt);
|
|
it.vListeners.emplace_back(std::move(info));
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool SendProxyManagerInterfaceImpl::AddUnhookListenerGamerules(IExtension * pExt, SendProp * pProp, CallBackType iCallbackType, void * pCallback, ISendProxyUnhookListener * pListener)
|
|
{
|
|
const char * pPropName = pProp->GetName();
|
|
return AddUnhookListenerGamerules(pExt, pPropName, iCallbackType, pCallback, pListener);
|
|
}
|
|
|
|
bool SendProxyManagerInterfaceImpl::AddUnhookListenerGamerules(IExtension * pExt, const char * pProp, CallBackType iCallbackType, void * pCallback, ISendProxyUnhookListener * pListener)
|
|
{
|
|
if (!pProp || !*pProp)
|
|
return false;
|
|
for (auto &it : g_HooksGamerules) {
|
|
if (it.sCallbackInfo.iCallbackType == iCallbackType &&
|
|
!strcmp(it.pVar->GetName(), pProp) &&
|
|
pCallback == it.sCallbackInfo.pCallback)
|
|
{
|
|
ListenerCallbackInfo info;
|
|
info.m_pExt = pExt;
|
|
info.m_pExtAPI = pExt->GetAPI();
|
|
info.m_pCallBack = pListener;
|
|
HookExtensionUnload(pExt);
|
|
it.vListeners.emplace_back(std::move(info));
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool SendProxyManagerInterfaceImpl::RemoveUnhookListener(IExtension * pExt, SendProp * pProp, CBaseEntity * pEntity, CallBackType iCallbackType, void * pCallback, ISendProxyUnhookListener * pListener)
|
|
{
|
|
const char * pPropName = pProp->GetName();
|
|
return RemoveUnhookListener(pExt, pPropName, pEntity, iCallbackType, pCallback, pListener);
|
|
}
|
|
|
|
bool SendProxyManagerInterfaceImpl::RemoveUnhookListener(IExtension * pExt, const char * pProp, CBaseEntity * pEntity, CallBackType iCallbackType, void * pCallback, ISendProxyUnhookListener * pListener)
|
|
{
|
|
if (!pProp || !*pProp)
|
|
return false;
|
|
|
|
edict_t * pEdict = gameents->BaseEntityToEdict(pEntity);
|
|
for (auto &it : g_Hooks) {
|
|
if (it.pEnt == pEdict &&
|
|
it.sCallbackInfo.iCallbackType == iCallbackType &&
|
|
!strcmp(it.pVar->GetName(), pProp) &&
|
|
pCallback == it.sCallbackInfo.pCallback)
|
|
{
|
|
auto &listeners = it.vListeners;
|
|
auto it2 = listeners.begin();
|
|
while(it2 != listeners.end())
|
|
{
|
|
auto &cb = *it2;
|
|
|
|
if (cb.m_pExt == pExt &&
|
|
cb.m_pCallBack == pListener)
|
|
{
|
|
listeners.erase(it2);
|
|
UnhookExtensionUnload(pExt);
|
|
return true;
|
|
}
|
|
|
|
++it2;
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool SendProxyManagerInterfaceImpl::RemoveUnhookListenerGamerules(IExtension * pExt, SendProp * pProp, CallBackType iCallbackType, void * pCallback, ISendProxyUnhookListener * pListener)
|
|
{
|
|
const char * pPropName = pProp->GetName();
|
|
return RemoveUnhookListenerGamerules(pExt, pPropName, iCallbackType, pCallback, pListener);
|
|
}
|
|
|
|
bool SendProxyManagerInterfaceImpl::RemoveUnhookListenerGamerules(IExtension * pExt, const char * pProp, CallBackType iCallbackType, void * pCallback, ISendProxyUnhookListener * pListener)
|
|
{
|
|
if (!pProp || !*pProp)
|
|
return false;
|
|
|
|
for (auto &it : g_HooksGamerules) {
|
|
if (it.sCallbackInfo.iCallbackType == iCallbackType &&
|
|
!strcmp(it.pVar->GetName(), pProp) &&
|
|
pCallback == it.sCallbackInfo.pCallback)
|
|
{
|
|
auto &listeners = it.vListeners;
|
|
auto it2 = listeners.begin();
|
|
while(it2 != listeners.end())
|
|
{
|
|
auto &cb = *it2;
|
|
|
|
if (cb.m_pExt == pExt &&
|
|
cb.m_pCallBack == pListener)
|
|
{
|
|
listeners.erase(it2);
|
|
UnhookExtensionUnload(pExt);
|
|
return true;
|
|
}
|
|
|
|
++it2;
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
//same for the arrays
|
|
|
|
bool SendProxyManagerInterfaceImpl::HookProxyArray(IExtension * pExt, SendProp * pProp, CBaseEntity * pEntity, PropType iType, int iElement, CallBackType iCallbackType, void * pCallback)
|
|
{
|
|
if (!pEntity)
|
|
return false;
|
|
|
|
edict_t * pEdict = gameents->BaseEntityToEdict(pEntity);
|
|
if (!pEdict || pEdict->IsFree())
|
|
return false;
|
|
|
|
SendTable * pSendTable = pProp->GetDataTable();
|
|
if (!pSendTable)
|
|
return false;
|
|
|
|
SendProp * pPropElem = pSendTable->GetProp(iElement);
|
|
if (!pPropElem)
|
|
return false;
|
|
|
|
if (!IsPropValid(pPropElem, iType))
|
|
return false;
|
|
|
|
SendPropHook hook;
|
|
hook.objectID = gamehelpers->IndexOfEdict(pEdict);
|
|
hook.sCallbackInfo.pCallback = pCallback;
|
|
hook.sCallbackInfo.iCallbackType = iCallbackType;
|
|
hook.sCallbackInfo.pOwner = (void *)pExt;
|
|
hook.propType = iType;
|
|
hook.pEnt = pEdict;
|
|
hook.pVar = pPropElem;
|
|
hook.Element = iElement;
|
|
bool bHookedAlready = false;
|
|
for (auto &it : g_Hooks)
|
|
{
|
|
if (it.pVar == pPropElem)
|
|
{
|
|
hook.pRealProxy = it.pRealProxy;
|
|
bHookedAlready = true;
|
|
break;
|
|
}
|
|
}
|
|
if (!bHookedAlready)
|
|
hook.pRealProxy = pPropElem->GetProxyFn();
|
|
HookExtensionUnload(pExt);
|
|
if (g_SendProxyManager.AddHookToList(std::move(hook)))
|
|
{
|
|
if (!bHookedAlready)
|
|
pPropElem->SetProxyFn(GlobalProxy);
|
|
}
|
|
else
|
|
{
|
|
UnhookExtensionUnload(pExt);
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool SendProxyManagerInterfaceImpl::HookProxyArray(IExtension * pExt, const char * pProp, CBaseEntity * pEntity, PropType iType, int iElement, CallBackType iCallbackType, void * pCallback)
|
|
{
|
|
if (!pProp || !*pProp)
|
|
return false;
|
|
if (!pEntity)
|
|
return false;
|
|
ServerClass * sc = ((IServerUnknown *)pEntity)->GetNetworkable()->GetServerClass();
|
|
if (!sc)
|
|
return false; //we don't use exceptions, bad extensions may do not handle this and server will crashed, just return false
|
|
sm_sendprop_info_t info;
|
|
gamehelpers->FindSendPropInfo(sc->GetName(), pProp, &info);
|
|
SendProp * pSendProp = info.prop;
|
|
if (pSendProp)
|
|
return HookProxyArray(pExt, pSendProp, pEntity, iType, iElement, iCallbackType, pCallback);
|
|
return false;
|
|
}
|
|
|
|
bool SendProxyManagerInterfaceImpl::HookProxyArrayGamerules(IExtension * pExt, SendProp * pProp, PropType iType, int iElement, CallBackType iCallbackType, void * pCallback)
|
|
{
|
|
SendTable * pSendTable = pProp->GetDataTable();
|
|
if (!pSendTable)
|
|
return false;
|
|
|
|
SendProp * pPropElem = pSendTable->GetProp(iElement);
|
|
if (!pPropElem)
|
|
return false;
|
|
|
|
if (!IsPropValid(pPropElem, iType))
|
|
return false;
|
|
|
|
SendPropHookGamerules hook;
|
|
hook.sCallbackInfo.pCallback = pCallback;
|
|
hook.sCallbackInfo.iCallbackType = iCallbackType;
|
|
hook.sCallbackInfo.pOwner = (void *)pExt;
|
|
bool bHookedAlready = false;
|
|
for (auto &it : g_HooksGamerules)
|
|
{
|
|
if (it.pVar == pProp)
|
|
{
|
|
hook.pRealProxy = it.pRealProxy;
|
|
bHookedAlready = true;
|
|
break;
|
|
}
|
|
}
|
|
if (!bHookedAlready)
|
|
hook.pRealProxy = pProp->GetProxyFn();
|
|
hook.propType = iType;
|
|
hook.pVar = pProp;
|
|
sm_sendprop_info_t info;
|
|
gamehelpers->FindSendPropInfo(g_szGameRulesProxy, pProp->GetName(), &info);
|
|
hook.Element = iElement;
|
|
|
|
//if this prop has been hooked already, don't set the proxy again
|
|
HookExtensionUnload(pExt);
|
|
if (bHookedAlready)
|
|
{
|
|
if (g_SendProxyManager.AddHookToListGamerules(std::move(hook)))
|
|
return true;
|
|
UnhookExtensionUnload(pExt);
|
|
return false;
|
|
}
|
|
if (g_SendProxyManager.AddHookToListGamerules(std::move(hook)))
|
|
{
|
|
pProp->SetProxyFn(GlobalProxyGamerules);
|
|
return true;
|
|
}
|
|
UnhookExtensionUnload(pExt);
|
|
return false;
|
|
}
|
|
|
|
bool SendProxyManagerInterfaceImpl::HookProxyArrayGamerules(IExtension * pExt, const char * pProp, PropType iType, int iElement, CallBackType iCallbackType, void * pCallback)
|
|
{
|
|
if (!pProp || !*pProp)
|
|
return false;
|
|
sm_sendprop_info_t info;
|
|
gamehelpers->FindSendPropInfo(g_szGameRulesProxy, pProp, &info);
|
|
SendProp * pSendProp = info.prop;
|
|
if (pSendProp)
|
|
return HookProxyArrayGamerules(pExt, pSendProp, iType, iElement, iCallbackType, pCallback);
|
|
return false;
|
|
}
|
|
|
|
bool SendProxyManagerInterfaceImpl::UnhookProxyArray(IExtension * pExt, SendProp * pProp, CBaseEntity * pEntity, int iElement, CallBackType iCallbackType, void * pCallback)
|
|
{
|
|
const char * pPropName = pProp->GetName();
|
|
return UnhookProxyArray(pExt, pPropName, pEntity, iElement, iCallbackType, pCallback);
|
|
}
|
|
|
|
bool SendProxyManagerInterfaceImpl::UnhookProxyArray(IExtension * pExt, const char * pProp, CBaseEntity * pEntity, int iElement, CallBackType iCallbackType, void * pCallback)
|
|
{
|
|
if (!pProp || !*pProp)
|
|
return false;
|
|
edict_t * pEdict = gameents->BaseEntityToEdict(pEntity);
|
|
auto it = g_Hooks.begin();
|
|
while (it != g_Hooks.end()) {
|
|
auto &hook = *it;
|
|
|
|
if (hook.sCallbackInfo.pOwner == pExt &&
|
|
hook.Element == iElement &&
|
|
pEdict == hook.pEnt &&
|
|
hook.sCallbackInfo.iCallbackType == iCallbackType &&
|
|
!strcmp(hook.pVar->GetName(), pProp) &&
|
|
pCallback == hook.sCallbackInfo.pCallback)
|
|
{
|
|
g_SendProxyManager.UnhookProxy(hook);
|
|
g_Hooks.erase(it);
|
|
UnhookExtensionUnload(pExt);
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool SendProxyManagerInterfaceImpl::UnhookProxyArrayGamerules(IExtension * pExt, SendProp * pProp, int iElement, CallBackType iCallbackType, void * pCallback)
|
|
{
|
|
const char * pPropName = pProp->GetName();
|
|
return UnhookProxyArrayGamerules(pExt, pPropName, iElement, iCallbackType, pCallback);
|
|
}
|
|
|
|
bool SendProxyManagerInterfaceImpl::UnhookProxyArrayGamerules(IExtension * pExt, const char * pProp, int iElement, CallBackType iCallbackType, void * pCallback)
|
|
{
|
|
if (!pProp || !*pProp)
|
|
return false;
|
|
auto it = g_HooksGamerules.begin();
|
|
while(it != g_HooksGamerules.end()) {
|
|
auto &hook = *it;
|
|
|
|
if (hook.sCallbackInfo.pOwner == pExt &&
|
|
hook.Element == iElement &&
|
|
hook.sCallbackInfo.iCallbackType == iCallbackType &&
|
|
!strcmp(hook.pVar->GetName(), pProp) &&
|
|
pCallback == hook.sCallbackInfo.pCallback)
|
|
{
|
|
g_SendProxyManager.UnhookProxyGamerules(hook);
|
|
g_HooksGamerules.erase(it);
|
|
UnhookExtensionUnload(pExt);
|
|
return true;
|
|
}
|
|
|
|
++it;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool SendProxyManagerInterfaceImpl::AddUnhookListenerArray(IExtension * pExt, SendProp * pProp, CBaseEntity * pEntity, int iElement, CallBackType iCallbackType, void * pCallback, ISendProxyUnhookListener * pListener)
|
|
{
|
|
const char * pPropName = pProp->GetName();
|
|
return AddUnhookListenerArray(pExt, pPropName, pEntity, iElement, iCallbackType, pCallback, pListener);
|
|
}
|
|
|
|
bool SendProxyManagerInterfaceImpl::AddUnhookListenerArray(IExtension * pExt, const char * pProp, CBaseEntity * pEntity, int iElement, CallBackType iCallbackType, void * pCallback, ISendProxyUnhookListener * pListener)
|
|
{
|
|
if (!pProp || !*pProp)
|
|
return false;
|
|
edict_t * pEdict = gameents->BaseEntityToEdict(pEntity);
|
|
for (auto &it : g_Hooks) {
|
|
if (pEdict == it.pEnt &&
|
|
it.sCallbackInfo.iCallbackType == iCallbackType &&
|
|
it.Element == iElement &&
|
|
!strcmp(it.pVar->GetName(), pProp) &&
|
|
pCallback == it.sCallbackInfo.pCallback)
|
|
{
|
|
ListenerCallbackInfo info;
|
|
info.m_pExt = pExt;
|
|
info.m_pExtAPI = pExt->GetAPI();
|
|
info.m_pCallBack = pListener;
|
|
HookExtensionUnload(pExt);
|
|
it.vListeners.emplace_back(std::move(info));
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool SendProxyManagerInterfaceImpl::AddUnhookListenerArrayGamerules(IExtension * pExt, SendProp * pProp, int iElement, CallBackType iCallbackType, void * pCallback, ISendProxyUnhookListener * pListener)
|
|
{
|
|
const char * pPropName = pProp->GetName();
|
|
return AddUnhookListenerArrayGamerules(pExt, pPropName, iElement, iCallbackType, pCallback, pListener);
|
|
}
|
|
|
|
bool SendProxyManagerInterfaceImpl::AddUnhookListenerArrayGamerules(IExtension * pExt, const char * pProp, int iElement, CallBackType iCallbackType, void * pCallback, ISendProxyUnhookListener * pListener)
|
|
{
|
|
if (!pProp || !*pProp)
|
|
return false;
|
|
for (auto &it : g_HooksGamerules) {
|
|
if (it.sCallbackInfo.iCallbackType == iCallbackType &&
|
|
it.Element == iElement &&
|
|
!strcmp(it.pVar->GetName(), pProp) &&
|
|
pCallback == it.sCallbackInfo.pCallback)
|
|
{
|
|
ListenerCallbackInfo info;
|
|
info.m_pExt = pExt;
|
|
info.m_pExtAPI = pExt->GetAPI();
|
|
info.m_pCallBack = pListener;
|
|
HookExtensionUnload(pExt);
|
|
it.vListeners.emplace_back(std::move(info));
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool SendProxyManagerInterfaceImpl::RemoveUnhookListenerArray(IExtension * pExt, SendProp * pProp, CBaseEntity * pEntity, int iElement, CallBackType iCallbackType, void * pCallback, ISendProxyUnhookListener * pListener)
|
|
{
|
|
const char * pPropName = pProp->GetName();
|
|
return RemoveUnhookListenerArray(pExt, pPropName, pEntity, iElement, iCallbackType, pCallback, pListener);
|
|
}
|
|
|
|
bool SendProxyManagerInterfaceImpl::RemoveUnhookListenerArray(IExtension * pExt, const char * pProp, CBaseEntity * pEntity, int iElement, CallBackType iCallbackType, void * pCallback, ISendProxyUnhookListener * pListener)
|
|
{
|
|
if (!pProp || !*pProp)
|
|
return false;
|
|
|
|
edict_t * pEdict = gameents->BaseEntityToEdict(pEntity);
|
|
for (auto &it : g_Hooks) {
|
|
if (it.pEnt == pEdict &&
|
|
it.sCallbackInfo.iCallbackType == iCallbackType &&
|
|
it.Element == iElement &&
|
|
!strcmp(it.pVar->GetName(), pProp) &&
|
|
pCallback == it.sCallbackInfo.pCallback)
|
|
{
|
|
auto &listeners = it.vListeners;
|
|
auto it2 = listeners.begin();
|
|
while(it2 != listeners.end())
|
|
{
|
|
if (it2->m_pExt == pExt &&
|
|
it2->m_pCallBack == pListener)
|
|
{
|
|
listeners.erase(it2);
|
|
UnhookExtensionUnload(pExt);
|
|
return true;
|
|
}
|
|
|
|
++it2;
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool SendProxyManagerInterfaceImpl::RemoveUnhookListenerArrayGamerules(IExtension * pExt, SendProp * pProp, int iElement, CallBackType iCallbackType, void * pCallback, ISendProxyUnhookListener * pListener)
|
|
{
|
|
const char * pPropName = pProp->GetName();
|
|
return RemoveUnhookListenerArrayGamerules(pExt, pPropName, iElement, iCallbackType, pCallback, pListener);
|
|
}
|
|
|
|
bool SendProxyManagerInterfaceImpl::RemoveUnhookListenerArrayGamerules(IExtension * pExt, const char * pProp, int iElement, CallBackType iCallbackType, void * pCallback, ISendProxyUnhookListener * pListener)
|
|
{
|
|
if (!pProp || !*pProp)
|
|
return false;
|
|
|
|
for (auto &it : g_HooksGamerules) {
|
|
if (it.sCallbackInfo.iCallbackType == iCallbackType &&
|
|
it.Element == iElement &&
|
|
!strcmp(it.pVar->GetName(), pProp) &&
|
|
pCallback == it.sCallbackInfo.pCallback)
|
|
{
|
|
auto &listeners = it.vListeners;
|
|
auto it2 = listeners.begin();
|
|
while(it2 != listeners.end())
|
|
{
|
|
if (it2->m_pExt == pExt &&
|
|
it2->m_pCallBack == pListener)
|
|
{
|
|
listeners.erase(it2);
|
|
UnhookExtensionUnload(pExt);
|
|
return true;
|
|
}
|
|
|
|
++it2;
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool SendProxyManagerInterfaceImpl::IsProxyHooked(IExtension * pExt, SendProp * pProp, CBaseEntity * pEntity) const
|
|
{
|
|
return IsProxyHooked(pExt, pProp->GetName(), pEntity);
|
|
}
|
|
|
|
bool SendProxyManagerInterfaceImpl::IsProxyHooked(IExtension * pExt, const char * pProp, CBaseEntity * pEntity) const
|
|
{
|
|
if (!pProp || !*pProp)
|
|
return false;
|
|
edict_t * pEdict = gameents->BaseEntityToEdict(pEntity);
|
|
for (auto &it : g_Hooks) {
|
|
if (it.sCallbackInfo.pOwner == (void *)pExt &&
|
|
it.pEnt == pEdict &&
|
|
!strcmp(pProp, it.pVar->GetName())) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool SendProxyManagerInterfaceImpl::IsProxyHookedGamerules(IExtension * pExt, SendProp * pProp) const
|
|
{
|
|
return IsProxyHookedGamerules(pExt, pProp->GetName());
|
|
}
|
|
|
|
bool SendProxyManagerInterfaceImpl::IsProxyHookedGamerules(IExtension * pExt, const char * pProp) const
|
|
{
|
|
if (!pProp || !*pProp)
|
|
return false;
|
|
for (auto &it : g_HooksGamerules) {
|
|
if (it.sCallbackInfo.pOwner == (void *)pExt &&
|
|
!strcmp(pProp, it.pVar->GetName())) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool SendProxyManagerInterfaceImpl::IsProxyHookedArray(IExtension * pExt, SendProp * pProp, CBaseEntity * pEntity, int iElement) const
|
|
{
|
|
return IsProxyHookedArray(pExt, pProp->GetName(), pEntity, iElement);
|
|
}
|
|
|
|
bool SendProxyManagerInterfaceImpl::IsProxyHookedArray(IExtension * pExt, const char * pProp, CBaseEntity * pEntity, int iElement) const
|
|
{
|
|
if (!pProp || !*pProp)
|
|
return false;
|
|
edict_t * pEdict = gameents->BaseEntityToEdict(pEntity);
|
|
for (auto &it : g_Hooks) {
|
|
if (it.sCallbackInfo.pOwner == (void *)pExt &&
|
|
it.pEnt == pEdict &&
|
|
it.Element == iElement &&
|
|
!strcmp(pProp, it.pVar->GetName())) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool SendProxyManagerInterfaceImpl::IsProxyHookedArrayGamerules(IExtension * pExt, SendProp * pProp, int iElement) const
|
|
{
|
|
return IsProxyHookedArrayGamerules(pExt, pProp->GetName(), iElement);
|
|
}
|
|
|
|
bool SendProxyManagerInterfaceImpl::IsProxyHookedArrayGamerules(IExtension * pExt, const char * pProp, int iElement) const
|
|
{
|
|
if (!pProp || !*pProp)
|
|
return false;
|
|
for (auto &it : g_HooksGamerules) {
|
|
if (it.sCallbackInfo.pOwner == (void *)pExt &&
|
|
it.Element == iElement &&
|
|
!strcmp(pProp, it.pVar->GetName())) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|