/**
* 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 .
*
* 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 .
*
* Version: $Id$
*/
#include "natives.h"
static cell_t Native_UnhookPropChange(IPluginContext * pContext, const cell_t * params)
{
if (params[1] < 0 || params[1] >= g_iEdictCount)
return pContext->ThrowNativeError("Invalid Edict Index %d", params[1]);
int entity = params[1];
char * name;
edict_t * pEnt = gamehelpers->EdictOfIndex(entity);
pContext->LocalToString(params[2], &name);
ServerClass * sc = pEnt->GetNetworkable()->GetServerClass();
if (!sc)
return pContext->ThrowNativeError("Cannot find ServerClass for entity %d", entity);
sm_sendprop_info_t info;
gamehelpers->FindSendPropInfo(sc->GetName(), name, &info);
IPluginFunction * callback = pContext->GetFunctionById(params[3]);
auto it = g_ChangeHooks.begin();
while(it != g_ChangeHooks.end())
{
auto &hook = *it;
if (hook.objectID == entity &&
hook.pVar == info.prop)
{
CallBackInfo sInfo;
sInfo.pCallback = callback;
sInfo.pOwner = (void *)pContext;
sInfo.iCallbackType = CallBackType::Callback_PluginFunction;
if(g_SendProxyManager.UnhookChange(hook, sInfo)) {
g_ChangeHooks.erase(it);
}
break;
}
}
return 1;
}
static cell_t Native_UnhookPropChangeGameRules(IPluginContext * pContext, const cell_t * params)
{
char * name;
pContext->LocalToString(params[1], &name);
IPluginFunction * callback = pContext->GetFunctionById(params[2]);
sm_sendprop_info_t info;
gamehelpers->FindSendPropInfo(g_szGameRulesProxy, name, &info);
auto it = g_ChangeHooksGamerules.begin();
while(it != g_ChangeHooksGamerules.end())
{
auto &hook = *it;
if (hook.pVar == info.prop)
{
CallBackInfo sInfo;
sInfo.pCallback = callback;
sInfo.pOwner = (void *)pContext;
sInfo.iCallbackType = CallBackType::Callback_PluginFunction;
if(g_SendProxyManager.UnhookChangeGamerules(hook, sInfo)) {
g_ChangeHooksGamerules.erase(it);
}
break;
}
}
return 1;
}
static cell_t Native_HookPropChange(IPluginContext * pContext, const cell_t * params)
{
bool bSafeCheck = params[0] >= 4;
if (params[1] < 0 || params[1] >= g_iEdictCount)
return pContext->ThrowNativeError("Invalid Edict Index %d", params[1]);
int entity = params[1];
char * name;
edict_t * pEnt = gamehelpers->EdictOfIndex(entity);
pContext->LocalToString(params[2], &name);
ServerClass * sc = pEnt->GetNetworkable()->GetServerClass();
if (!sc)
return pContext->ThrowNativeError("Cannot find ServerClass for entity %d", entity);
sm_sendprop_info_t info;
gamehelpers->FindSendPropInfo(sc->GetName(), name, &info);
SendProp * pProp = info.prop;
if (!pProp)
return pContext->ThrowNativeError("Could not find prop %s", name);
IPluginFunction * callback = nullptr;
PropType propType = PropType::Prop_Max;
if (bSafeCheck)
{
propType = static_cast(params[3]);
callback = pContext->GetFunctionById(params[4]);
}
else
callback = pContext->GetFunctionById(params[3]);
if (bSafeCheck && !IsPropValid(pProp, propType)) {
switch (propType)
{
case PropType::Prop_Int:
return pContext->ThrowNativeError("Prop %s is not an int!", pProp->GetName());
case PropType::Prop_Float:
return pContext->ThrowNativeError("Prop %s is not a float!", pProp->GetName());
case PropType::Prop_String:
return pContext->ThrowNativeError("Prop %s is not a string!", pProp->GetName());
case PropType::Prop_Vector:
return pContext->ThrowNativeError("Prop %s is not a vector!", pProp->GetName());
default:
return pContext->ThrowNativeError("Unsupported prop type %d", propType);
}
}
PropChangeHook hook;
hook.objectID = entity;
hook.Offset = info.actual_offset;
hook.pVar = pProp;
CallBackInfo sCallInfo;
sCallInfo.iCallbackType = CallBackType::Callback_PluginFunction;
sCallInfo.pCallback = (void *)callback;
sCallInfo.pOwner = (void *)pContext;
if (!g_SendProxyManager.AddChangeHookToList(std::move(hook), std::move(sCallInfo)))
return pContext->ThrowNativeError("Entity %d isn't valid", entity);
return 1;
}
static cell_t Native_HookPropChangeGameRules(IPluginContext * pContext, const cell_t * params)
{
bool bSafeCheck = params[0] >= 3;
char * name;
pContext->LocalToString(params[1], &name);
sm_sendprop_info_t info;
gamehelpers->FindSendPropInfo(g_szGameRulesProxy, name, &info);
SendProp * pProp = info.prop;
if (!pProp)
return pContext->ThrowNativeError("Could not find prop %s", name);
IPluginFunction * callback = nullptr;
PropType propType = PropType::Prop_Max;
if (bSafeCheck)
{
propType = static_cast(params[2]);
callback = pContext->GetFunctionById(params[3]);
}
else
callback = pContext->GetFunctionById(params[2]);
if (bSafeCheck && !IsPropValid(pProp, propType)) {
switch (propType)
{
case PropType::Prop_Int:
return pContext->ThrowNativeError("Prop %s is not an int!", pProp->GetName());
case PropType::Prop_Float:
return pContext->ThrowNativeError("Prop %s is not a float!", pProp->GetName());
case PropType::Prop_String:
return pContext->ThrowNativeError("Prop %s is not a string!", pProp->GetName());
case PropType::Prop_Vector:
return pContext->ThrowNativeError("Prop %s is not a vector!", pProp->GetName());
default:
return pContext->ThrowNativeError("Unsupported prop type %d", propType);
}
}
if (!g_pGameRules)
{
g_pGameRules = g_pSDKTools->GetGameRules();
if (!g_pGameRules)
{
return pContext->ThrowNativeError("CRITICAL ERROR: Could not get gamerules pointer!");
}
}
PropChangeHookGamerules hook;
hook.Offset = info.actual_offset;
hook.pVar = pProp;
CallBackInfo sCallInfo;
sCallInfo.iCallbackType = CallBackType::Callback_PluginFunction;
sCallInfo.pCallback = (void *)callback;
sCallInfo.pOwner = (void *)pContext;
if (!g_SendProxyManager.AddChangeHookToListGamerules(std::move(hook), std::move(sCallInfo)))
return pContext->ThrowNativeError("Prop type %d isn't valid", pProp->GetType()); //should never happen
return 1;
}
static cell_t Native_Hook(IPluginContext * pContext, const cell_t * params)
{
if (params[1] < 0 || params[1] >= g_iEdictCount)
return pContext->ThrowNativeError("Invalid Edict Index %d", params[1]);
int entity = params[1];
char * name;
pContext->LocalToString(params[2], &name);
edict_t * pEnt = gamehelpers->EdictOfIndex(entity);
ServerClass * sc = pEnt->GetNetworkable()->GetServerClass();
if (!sc)
return pContext->ThrowNativeError("Cannot find ServerClass for entity %d", entity);
sm_sendprop_info_t info;
gamehelpers->FindSendPropInfo(sc->GetName(), name, &info);
SendProp * pProp = info.prop;
if (!pProp)
return pContext->ThrowNativeError("Could not find prop %s", name);
PropType propType = static_cast(params[3]);
if (!IsPropValid(pProp, propType)) {
switch (propType)
{
case PropType::Prop_Int:
return pContext->ThrowNativeError("Prop %s is not an int!", pProp->GetName());
case PropType::Prop_Float:
return pContext->ThrowNativeError("Prop %s is not a float!", pProp->GetName());
case PropType::Prop_String:
return pContext->ThrowNativeError("Prop %s is not a string!", pProp->GetName());
case PropType::Prop_Vector:
return pContext->ThrowNativeError("Prop %s is not a vector!", pProp->GetName());
default:
return pContext->ThrowNativeError("Unsupported prop type %d", propType);
}
}
SendPropHook hook;
hook.objectID = entity;
hook.sCallbackInfo.pCallback = (void *)pContext->GetFunctionById(params[4]);
hook.sCallbackInfo.iCallbackType = CallBackType::Callback_PluginFunction;
hook.sCallbackInfo.pOwner = (void *)pContext;
hook.pEnt = pEnt;
hook.per_client = params[5];
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();
hook.propType = propType;
hook.pVar = pProp;
//if this prop has been hooked already, don't set the proxy again
if (bHookedAlready)
{
if (g_SendProxyManager.AddHookToList(std::move(hook)))
return 1;
return 0;
}
if (g_SendProxyManager.AddHookToList(std::move(hook)))
{
pProp->SetProxyFn(GlobalProxy);
return 1;
}
return 0;
}
static cell_t Native_HookGameRules(IPluginContext * pContext, const cell_t * params)
{
char * name;
pContext->LocalToString(params[1], &name);
sm_sendprop_info_t info;
gamehelpers->FindSendPropInfo(g_szGameRulesProxy, name, &info);
SendProp * pProp = info.prop;
if (!pProp)
return pContext->ThrowNativeError("Could not find prop %s", name);
PropType propType = static_cast(params[2]);
if (!IsPropValid(pProp, propType)) {
switch (propType)
{
case PropType::Prop_Int:
return pContext->ThrowNativeError("Prop %s is not an int!", pProp->GetName());
case PropType::Prop_Float:
return pContext->ThrowNativeError("Prop %s is not a float!", pProp->GetName());
case PropType::Prop_String:
return pContext->ThrowNativeError("Prop %s is not a string!", pProp->GetName());
case PropType::Prop_Vector:
return pContext->ThrowNativeError("Prop %s is not a vector!", pProp->GetName());
default:
return pContext->ThrowNativeError("Unsupported prop type %d", propType);
}
}
SendPropHookGamerules hook;
hook.sCallbackInfo.pCallback = (void *)pContext->GetFunctionById(params[3]);
hook.sCallbackInfo.iCallbackType = CallBackType::Callback_PluginFunction;
hook.sCallbackInfo.pOwner = (void *)pContext;
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 = propType;
hook.pVar = pProp;
hook.per_client = params[4];
//if this prop has been hooked already, don't set the proxy again
if (bHookedAlready)
{
if (g_SendProxyManager.AddHookToListGamerules(std::move(hook)))
return 1;
return 0;
}
if (g_SendProxyManager.AddHookToListGamerules(std::move(hook)))
{
pProp->SetProxyFn(GlobalProxyGamerules);
return 1;
}
return 0;
}
static cell_t Native_HookArrayProp(IPluginContext * pContext, const cell_t * params)
{
if (params[1] < 0 || params[1] >= g_iEdictCount)
return pContext->ThrowNativeError("Invalid Edict Index %d", params[1]);
int entity = params[1];
char * propName;
pContext->LocalToString(params[2], &propName);
edict_t * pEnt = gamehelpers->EdictOfIndex(entity);
ServerClass * sc = pEnt->GetNetworkable()->GetServerClass();
if (!sc)
return pContext->ThrowNativeError("Cannot find ServerClass for entity %d", entity);
sm_sendprop_info_t info;
gamehelpers->FindSendPropInfo(sc->GetName(), propName, &info);
if (!info.prop)
return pContext->ThrowNativeError("Could not find prop %s", propName);
SendTable * st = info.prop->GetDataTable();
if (!st)
return pContext->ThrowNativeError("Prop %s does not contain any elements", propName);
int element = params[3];
SendProp * pProp = st->GetProp(element);
if (!pProp)
return pContext->ThrowNativeError("Could not find element %d in %s", element, info.prop->GetName());
PropType propType = static_cast(params[4]);
if (!IsPropValid(pProp, propType)) {
switch (propType)
{
case PropType::Prop_Int:
return pContext->ThrowNativeError("Prop %s is not an int!", pProp->GetName());
case PropType::Prop_Float:
return pContext->ThrowNativeError("Prop %s is not a float!", pProp->GetName());
case PropType::Prop_String:
return pContext->ThrowNativeError("Prop %s is not a string!", pProp->GetName());
case PropType::Prop_Vector:
return pContext->ThrowNativeError("Prop %s is not a vector!", pProp->GetName());
default:
return pContext->ThrowNativeError("Unsupported prop type %d", propType);
}
}
SendPropHook hook;
hook.objectID = entity;
hook.sCallbackInfo.pCallback = (void *)pContext->GetFunctionById(params[5]);;
hook.sCallbackInfo.iCallbackType = CallBackType::Callback_PluginFunction;
hook.sCallbackInfo.pOwner = (void *)pContext;
hook.pEnt = pEnt;
hook.Element = element;
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();
hook.propType = propType;
hook.pVar = pProp;
hook.per_client = params[6];
if (bHookedAlready)
{
if (g_SendProxyManager.AddHookToList(std::move(hook)))
return 1;
return 0;
}
if (g_SendProxyManager.AddHookToList(std::move(hook)))
{
pProp->SetProxyFn(GlobalProxy);
return 1;
}
return 0;
}
static cell_t Native_UnhookArrayProp(IPluginContext * pContext, const cell_t * params)
{
if (params[1] < 0 || params[1] >= g_iEdictCount)
return pContext->ThrowNativeError("Invalid Edict Index %d", params[1]);
int entity = params[1];
char * propName;
pContext->LocalToString(params[2], &propName);
int element = params[3];
PropType propType = static_cast(params[4]);
IPluginFunction * callback = pContext->GetFunctionById(params[5]);
auto it = g_Hooks.begin();
while(it != g_Hooks.end())
{
auto &hook = *it;
//we check callback here, so, we do not need to check owner
if (hook.Element == element &&
hook.sCallbackInfo.iCallbackType == CallBackType::Callback_PluginFunction &&
hook.propType == propType &&
hook.sCallbackInfo.pCallback == (void *)callback &&
!strcmp(hook.pVar->GetName(), propName) &&
hook.objectID == entity)
{
g_SendProxyManager.UnhookProxy(hook);
g_Hooks.erase(it);
return 1;
}
++it;
}
return 0;
}
static cell_t Native_Unhook(IPluginContext * pContext, const cell_t * params)
{
char * propName;
pContext->LocalToString(params[2], &propName);
IPluginFunction * pFunction = pContext->GetFunctionById(params[3]);
auto it = g_Hooks.begin();
while(it != g_Hooks.end())
{
auto &hook = *it;
//we check callback here, so, we do not need to check owner
if (params[1] == hook.objectID &&
hook.sCallbackInfo.iCallbackType == CallBackType::Callback_PluginFunction &&
strcmp(hook.pVar->GetName(), propName) == 0 &&
(void *)pFunction == hook.sCallbackInfo.pCallback)
{
g_SendProxyManager.UnhookProxy(hook);
g_Hooks.erase(it);
return 1;
}
++it;
}
return 0;
}
static cell_t Native_UnhookGameRules(IPluginContext * pContext, const cell_t * params)
{
char * propName;
pContext->LocalToString(params[1], &propName);
IPluginFunction * pFunction = pContext->GetFunctionById(params[2]);
auto it = g_HooksGamerules.begin();
while(it != g_HooksGamerules.end())
{
auto &hook = *it;
//we check callback here, so, we do not need to check owner
if (hook.sCallbackInfo.iCallbackType == CallBackType::Callback_PluginFunction &&
strcmp(hook.pVar->GetName(), propName) == 0 &&
(void *)pFunction == hook.sCallbackInfo.pCallback)
{
g_SendProxyManager.UnhookProxyGamerules(hook);
g_HooksGamerules.erase(it);
return 1;
}
++it;
}
return 0;
}
static cell_t Native_IsHooked(IPluginContext * pContext, const cell_t * params)
{
int objectID = params[1];
char * propName;
pContext->LocalToString(params[2], &propName);
for (auto &it : g_Hooks)
{
if (it.objectID == objectID &&
it.sCallbackInfo.pOwner == (void *)pContext &&
strcmp(propName, it.pVar->GetName()) == 0) {
return 1;
}
}
return 0;
}
static cell_t Native_IsHookedGameRules(IPluginContext * pContext, const cell_t * params)
{
char * propName;
pContext->LocalToString(params[1], &propName);
for (auto &it : g_HooksGamerules)
{
if (it.sCallbackInfo.pOwner == (void *)pContext &&
strcmp(propName, it.pVar->GetName()) == 0) {
return 1;
}
}
return 0;
}
static cell_t Native_HookArrayPropGamerules(IPluginContext * pContext, const cell_t * params)
{
char * propName;
pContext->LocalToString(params[1], &propName);
sm_sendprop_info_t info;
gamehelpers->FindSendPropInfo(g_szGameRulesProxy, propName, &info);
if (!info.prop)
return pContext->ThrowNativeError("Could not find prop %s", propName);
SendTable * st = info.prop->GetDataTable();
if (!st)
return pContext->ThrowNativeError("Prop %s does not contain any elements", propName);
int element = params[2];
SendProp * pProp = st->GetProp(element);
if (!pProp)
return pContext->ThrowNativeError("Could not find element %d in %s", element, info.prop->GetName());
PropType propType = static_cast(params[3]);
if (!IsPropValid(pProp, propType)) {
switch (propType)
{
case PropType::Prop_Int:
return pContext->ThrowNativeError("Prop %s is not an int!", pProp->GetName());
case PropType::Prop_Float:
return pContext->ThrowNativeError("Prop %s is not a float!", pProp->GetName());
case PropType::Prop_String:
return pContext->ThrowNativeError("Prop %s is not a string!", pProp->GetName());
case PropType::Prop_Vector:
return pContext->ThrowNativeError("Prop %s is not a vector!", pProp->GetName());
default:
return pContext->ThrowNativeError("Unsupported prop type %d", propType);
}
}
SendPropHookGamerules hook;
hook.sCallbackInfo.pCallback = (void *)pContext->GetFunctionById(params[4]);
hook.sCallbackInfo.iCallbackType = CallBackType::Callback_PluginFunction;
hook.sCallbackInfo.pOwner = (void *)pContext;
hook.Element = element;
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 = propType;
hook.pVar = pProp;
if (bHookedAlready)
{
if (g_SendProxyManager.AddHookToListGamerules(std::move(hook)))
return 1;
return 0;
}
if (g_SendProxyManager.AddHookToListGamerules(std::move(hook)))
{
pProp->SetProxyFn(GlobalProxy);
return 1;
}
return 0;
}
static cell_t Native_UnhookArrayPropGamerules(IPluginContext * pContext, const cell_t * params)
{
char * propName;
pContext->LocalToString(params[1], &propName);
int iElement = params[2];
PropType iPropType = static_cast(params[3]);
IPluginFunction * pFunction = pContext->GetFunctionById(params[4]);
auto it = g_HooksGamerules.begin();
while(it != g_HooksGamerules.end())
{
auto &hook = *it;
if (hook.Element == iElement &&
hook.sCallbackInfo.iCallbackType == CallBackType::Callback_PluginFunction &&
hook.propType == iPropType &&
hook.sCallbackInfo.pCallback == (void *)pFunction &&
!strcmp(hook.pVar->GetName(), propName))
{
g_SendProxyManager.UnhookProxyGamerules(hook);
g_HooksGamerules.erase(it);
return 1;
}
++it;
}
return 0;
}
static cell_t Native_IsHookedArray(IPluginContext * pContext, const cell_t * params)
{
int objectID = params[1];
char * propName;
pContext->LocalToString(params[2], &propName);
int iElement = params[3];
for (auto &it : g_Hooks)
{
if (it.sCallbackInfo.pOwner == (void *)pContext &&
it.objectID == objectID &&
it.Element == iElement &&
strcmp(propName, it.pVar->GetName()) == 0) {
return 1;
}
}
return 0;
}
static cell_t Native_IsHookedArrayGameRules(IPluginContext * pContext, const cell_t * params)
{
char * propName;
pContext->LocalToString(params[1], &propName);
int iElement = params[2];
for (auto &it : g_HooksGamerules)
{
if (it.sCallbackInfo.pOwner == (void *)pContext &&
it.Element == iElement &&
strcmp(propName, it.pVar->GetName()) == 0) {
return 1;
}
}
return 0;
}
static cell_t Native_HookPropChangeArray(IPluginContext * pContext, const cell_t * params)
{
if (params[1] < 0 || params[1] >= g_iEdictCount)
return pContext->ThrowNativeError("Invalid Edict Index %d", params[1]);
int entity = params[1];
char * name;
edict_t * pEnt = gamehelpers->EdictOfIndex(entity);
pContext->LocalToString(params[2], &name);
ServerClass * sc = pEnt->GetNetworkable()->GetServerClass();
if (!sc)
return pContext->ThrowNativeError("Cannot find ServerClass for entity %d", entity);
sm_sendprop_info_t info;
gamehelpers->FindSendPropInfo(sc->GetName(), name, &info);
if (!info.prop)
return pContext->ThrowNativeError("Could not find prop %s", name);
SendTable * st = info.prop->GetDataTable();
if (!st)
return pContext->ThrowNativeError("Prop %s does not contain any elements", name);
int element = params[3];
SendProp * pProp = st->GetProp(element);
if (!pProp)
return pContext->ThrowNativeError("Could not find element %d in %s", element, info.prop->GetName());
PropType propType = static_cast(params[4]);
if (!IsPropValid(pProp, propType)) {
switch (propType)
{
case PropType::Prop_Int:
return pContext->ThrowNativeError("Prop %s is not an int!", pProp->GetName());
case PropType::Prop_Float:
return pContext->ThrowNativeError("Prop %s is not a float!", pProp->GetName());
case PropType::Prop_String:
return pContext->ThrowNativeError("Prop %s is not a string!", pProp->GetName());
case PropType::Prop_Vector:
return pContext->ThrowNativeError("Prop %s is not a vector!", pProp->GetName());
default:
return pContext->ThrowNativeError("Unsupported prop type %d", propType);
}
}
PropChangeHook hook;
hook.objectID = entity;
hook.Offset = info.actual_offset + pProp->GetOffset();
hook.pVar = pProp;
CallBackInfo sCallInfo;
sCallInfo.iCallbackType = CallBackType::Callback_PluginFunction;
sCallInfo.pCallback = (void *)pContext->GetFunctionById(params[5]);
sCallInfo.pOwner = (void *)pContext;
if (!g_SendProxyManager.AddChangeHookToList(std::move(hook), std::move(sCallInfo)))
return pContext->ThrowNativeError("Entity %d isn't valid", entity);
return 1;
}
static cell_t Native_UnhookPropChangeArray(IPluginContext * pContext, const cell_t * params)
{
if (params[1] < 0 || params[1] >= g_iEdictCount)
return pContext->ThrowNativeError("Invalid Edict Index %d", params[1]);
int entity = params[1];
char * name;
edict_t * pEnt = gamehelpers->EdictOfIndex(entity);
pContext->LocalToString(params[2], &name);
ServerClass * sc = pEnt->GetNetworkable()->GetServerClass();
if (!sc)
return pContext->ThrowNativeError("Cannot find ServerClass for entity %d", entity);
sm_sendprop_info_t info;
gamehelpers->FindSendPropInfo(sc->GetName(), name, &info);
SendTable * st = info.prop->GetDataTable();
if (!st)
return pContext->ThrowNativeError("Prop %s does not contain any elements", name);
int element = params[3];
SendProp * pProp = st->GetProp(element);
if (!pProp)
return pContext->ThrowNativeError("Could not find element %d in %s", element, info.prop->GetName());
IPluginFunction * callback = pContext->GetFunctionById(params[4]);
auto it = g_ChangeHooks.begin();
while(it != g_ChangeHooks.end())
{
auto &hook = *it;
if (hook.objectID == entity &&
hook.pVar == info.prop)
{
CallBackInfo sInfo;
sInfo.pCallback = callback;
sInfo.pOwner = (void *)pContext;
sInfo.iCallbackType = CallBackType::Callback_PluginFunction;
if(g_SendProxyManager.UnhookChange(hook, sInfo)) {
g_ChangeHooks.erase(it);
}
break;
}
++it;
}
return 1;
}
static cell_t Native_HookPropChangeArrayGameRules(IPluginContext * pContext, const cell_t * params)
{
char * name;
pContext->LocalToString(params[1], &name);
sm_sendprop_info_t info;
gamehelpers->FindSendPropInfo(g_szGameRulesProxy, name, &info);
if (!info.prop)
return pContext->ThrowNativeError("Could not find prop %s", name);
SendTable * st = info.prop->GetDataTable();
if (!st)
return pContext->ThrowNativeError("Prop %s does not contain any elements", name);
int element = params[2];
SendProp * pProp = st->GetProp(element);
if (!pProp)
return pContext->ThrowNativeError("Could not find element %d in %s", element, info.prop->GetName());
PropType propType = static_cast(params[3]);
if (!IsPropValid(pProp, propType)) {
switch (propType)
{
case PropType::Prop_Int:
return pContext->ThrowNativeError("Prop %s is not an int!", pProp->GetName());
case PropType::Prop_Float:
return pContext->ThrowNativeError("Prop %s is not a float!", pProp->GetName());
case PropType::Prop_String:
return pContext->ThrowNativeError("Prop %s is not a string!", pProp->GetName());
case PropType::Prop_Vector:
return pContext->ThrowNativeError("Prop %s is not a vector!", pProp->GetName());
default:
return pContext->ThrowNativeError("Unsupported prop type %d", propType);
}
}
PropChangeHookGamerules hook;
hook.Offset = info.actual_offset + pProp->GetOffset();
hook.pVar = pProp;
CallBackInfo sCallInfo;
sCallInfo.iCallbackType = CallBackType::Callback_PluginFunction;
sCallInfo.pCallback = (void *)pContext->GetFunctionById(params[4]);
sCallInfo.pOwner = (void *)pContext;
if (!g_SendProxyManager.AddChangeHookToListGamerules(std::move(hook), std::move(sCallInfo)))
return pContext->ThrowNativeError("Prop type %d isn't valid", pProp->GetType()); //should never happen
return 1;
}
static cell_t Native_UnhookPropChangeArrayGameRules(IPluginContext * pContext, const cell_t * params)
{
char * name;
pContext->LocalToString(params[1], &name);
sm_sendprop_info_t info;
gamehelpers->FindSendPropInfo(g_szGameRulesProxy, name, &info);
if (!info.prop)
return pContext->ThrowNativeError("Could not find prop %s", name);
SendTable * st = info.prop->GetDataTable();
if (!st)
return pContext->ThrowNativeError("Prop %s does not contain any elements", name);
int element = params[2];
SendProp * pProp = st->GetProp(element);
if (!pProp)
return pContext->ThrowNativeError("Could not find element %d in %s", element, info.prop->GetName());
IPluginFunction * callback = pContext->GetFunctionById(params[3]);
auto it = g_ChangeHooksGamerules.begin();
while(it != g_ChangeHooksGamerules.end())
{
auto &hook = *it;
if (hook.pVar == info.prop)
{
CallBackInfo sInfo;
sInfo.pCallback = callback;
sInfo.pOwner = (void *)pContext;
sInfo.iCallbackType = CallBackType::Callback_PluginFunction;
if(g_SendProxyManager.UnhookChangeGamerules(hook, sInfo)) {
g_ChangeHooksGamerules.erase(it);
}
break;
}
++it;
}
return 1;
}
static cell_t Native_IsPropChangeHooked(IPluginContext * pContext, const cell_t * params)
{
int objectID = params[1];
char * propName;
pContext->LocalToString(params[2], &propName);
for (auto &it : g_ChangeHooks)
{
if (it.objectID == objectID &&
strcmp(propName, it.pVar->GetName()) == 0)
{
auto &pCallbacks = it.vCallbacksInfo;
for (auto &it2 : pCallbacks) {
if (it2.iCallbackType == CallBackType::Callback_PluginFunction &&
it2.pOwner == (void *)pContext)
{
return 1;
}
}
break;
}
}
return 0;
}
static cell_t Native_IsPropChangeHookedGameRules(IPluginContext * pContext, const cell_t * params)
{
char * propName;
pContext->LocalToString(params[1], &propName);
for (auto &it : g_ChangeHooksGamerules)
{
if (strcmp(propName, it.pVar->GetName()) == 0)
{
auto &pCallbacks = it.vCallbacksInfo;
for (auto &it2 : pCallbacks) {
if (it2.iCallbackType == CallBackType::Callback_PluginFunction &&
it2.pOwner == (void *)pContext)
{
return 1;
}
}
break;
}
}
return 0;
}
static cell_t Native_IsPropChangeArrayHooked(IPluginContext * pContext, const cell_t * params)
{
int objectID = params[1];
char * propName;
pContext->LocalToString(params[2], &propName);
int element = params[3];
for (auto &it : g_ChangeHooks)
{
if (it.Element == element &&
it.objectID == objectID &&
strcmp(propName, it.pVar->GetName()) == 0)
{
auto &pCallbacks = it.vCallbacksInfo;
for (auto &it2 : pCallbacks) {
if (it2.iCallbackType == CallBackType::Callback_PluginFunction &&
it2.pOwner == (void *)pContext)
{
return 1;
}
}
break;
}
}
return 0;
}
static cell_t Native_IsPropChangeArrayHookedGameRules(IPluginContext * pContext, const cell_t * params)
{
char * propName;
pContext->LocalToString(params[1], &propName);
int element = params[2];
for (auto &it : g_ChangeHooksGamerules)
{
if (it.Element == element &&
strcmp(propName, it.pVar->GetName()) == 0)
{
auto &pCallbacks = it.vCallbacksInfo;
for (auto &it2 : pCallbacks) {
if (it2.iCallbackType == CallBackType::Callback_PluginFunction &&
it2.pOwner == (void *)pContext)
{
return 1;
}
}
break;
}
}
return 0;
}
const sp_nativeinfo_t g_MyNatives[] = {
{"SendProxy_Hook", Native_Hook},
{"SendProxy_HookGameRules", Native_HookGameRules},
{"SendProxy_HookArrayProp", Native_HookArrayProp},
{"SendProxy_UnhookArrayProp", Native_UnhookArrayProp},
{"SendProxy_Unhook", Native_Unhook},
{"SendProxy_UnhookGameRules", Native_UnhookGameRules},
{"SendProxy_IsHooked", Native_IsHooked},
{"SendProxy_IsHookedGameRules", Native_IsHookedGameRules},
{"SendProxy_HookPropChange", Native_HookPropChange},
{"SendProxy_HookPropChangeGameRules", Native_HookPropChangeGameRules},
{"SendProxy_UnhookPropChange", Native_UnhookPropChange},
{"SendProxy_UnhookPropChangeGameRules", Native_UnhookPropChangeGameRules},
{"SendProxy_HookArrayPropGamerules", Native_HookArrayPropGamerules},
{"SendProxy_UnhookArrayPropGamerules", Native_UnhookArrayPropGamerules},
{"SendProxy_IsHookedArrayProp", Native_IsHookedArray},
{"SendProxy_IsHookedArrayPropGamerules", Native_IsHookedArrayGameRules},
{"SendProxy_HookPropChangeArray", Native_HookPropChangeArray},
{"SendProxy_UnhookPropChangeArray", Native_UnhookPropChangeArray},
{"SendProxy_HookPropChangeArrayGameRules", Native_HookPropChangeArrayGameRules},
{"SendProxy_UnhookPropChangeArrayGameRules", Native_UnhookPropChangeArrayGameRules},
{"SendProxy_IsPropChangeHooked", Native_IsPropChangeHooked},
{"SendProxy_IsPropChangeHookedGameRules", Native_IsPropChangeHookedGameRules},
{"SendProxy_IsPropChangeArrayHooked", Native_IsPropChangeArrayHooked},
{"SendProxy_IsPropChangeArrayHookedGameRules", Native_IsPropChangeArrayHookedGameRules},
{"SendProxy_HookPropChangeSafe", Native_HookPropChange},
{"SendProxy_HookPropChangeGameRulesSafe", Native_HookPropChangeGameRules},
//Probably add listeners for plugins?
{NULL, NULL}
};