Compare commits

...

12 Commits

Author SHA1 Message Date
arthurdead
7b493af742 css 2023-09-16 17:30:33 -03:00
arthurdead
09aa70e774 memset 2023-03-05 04:03:48 -03:00
arthurdead
a4cb9f5fec i merged the pr wrong 2023-03-05 02:42:08 -03:00
arthurdead
eefac413f7 Merge branch 'master' of https://github.com/arthurdead/proxysend.git 2023-03-05 02:26:31 -03:00
arthurdead
5e73c21103 store refs as unsigned long instead of int, ignore hltv, replay servers and clients, fix opaque_ptr 2023-03-05 02:25:40 -03:00
Arthurdead
1240e21fff
Merge pull request #3 from sapphonie/master
fix hooked edicts not getting set to FL_EDICT_CHANGED, other tweaks
2023-03-05 02:22:34 -03:00
sappho
db5b53b09e
maintainer revert requests 2023-03-05 00:21:11 -05:00
sappho
596e19892d comment so ppl know who to blame when something explodes somehow 2023-03-04 06:33:32 -05:00
sappho
1a0bae1814 fix hooked edicts not getting set to FL_EDICT_CHANGED (fixes inconsistent proxy behavior), fix mismatched delete[], null init all vars 2023-03-04 06:30:50 -05:00
arthurdead
5c1f39064b comment sv_parallel_sendsnapshot, detect string_t, mark edict as changed after hooking/unhooking 2023-02-15 22:50:16 -03:00
arthurdead
ea36957b1e only call IndexToReference inside SendTable_CalcDelta once 2022-11-21 11:17:30 -03:00
arthurdead
849fc94958 support c++14 2022-11-19 05:57:59 -03:00
8 changed files with 2554 additions and 2372 deletions

View File

@ -173,13 +173,11 @@ class ExtensionConfig(object):
'-Wno-unused',
'-Wno-switch',
'-Wno-array-bounds',
'-Wno-register',
'-msse',
'-m32',
'-fvisibility=hidden',
]
cxx.cxxflags += [
'-std=gnu++2a',
'-fno-exceptions',
'-fno-threadsafe-statics',
'-Wno-non-virtual-dtor',
@ -188,6 +186,11 @@ class ExtensionConfig(object):
]
cxx.linkflags += ['-m32']
if cxx.version >= 'clang-5':
cxx.cxxflags += ['-Wno-register','-std=c++17']
else:
cxx.cxxflags += ['-std=c++14']
have_gcc = cxx.vendor == 'gcc'
have_clang = cxx.vendor == 'clang'
if cxx.version >= 'clang-3.6':

View File

@ -30,7 +30,7 @@ def CopyFiles(src, dest, files):
# Include files
CopyFiles('sourcemod/scripting/include', 'addons/sourcemod/scripting/include',
[ 'proxysend.inc', ]
[ 'proxysend.inc', 'proxysend_tf2.inc' ]
)
# GameData files

View File

@ -214,6 +214,10 @@ private:
using restores_t = std::unordered_map<SendProp *, std::unique_ptr<proxyrestore_t>>;
static restores_t restores;
static SendVarProxyFn SendProxy_StringT_To_String_ptr{nullptr};
static SendVarProxyFn SendProxy_Color32ToInt_ptr{nullptr};
static SendVarProxyFn SendProxy_EHandleToInt_ptr{nullptr};
static prop_types guess_prop_type(const SendProp *pProp, const SendTable *pTable) noexcept
{
#if defined _DEBUG
@ -278,6 +282,12 @@ static prop_types guess_prop_type(const SendProp *pProp, const SendTable *pTable
#endif
return prop_types::unsigned_int;
} else {
if(SendProxy_Color32ToInt_ptr && pRealProxy == SendProxy_Color32ToInt_ptr) {
return prop_types::color32_;
} else if(SendProxy_EHandleToInt_ptr && pRealProxy == SendProxy_EHandleToInt_ptr) {
return prop_types::ehandle;
}
{
if(pProp->m_nBits == 32) {
struct dummy_t {
@ -368,7 +378,11 @@ static prop_types guess_prop_type(const SendProp *pProp, const SendTable *pTable
case DPT_VectorXY:
return prop_types::vector;
case DPT_String: {
return prop_types::cstring;
if(SendProxy_StringT_To_String_ptr && pRealProxy == SendProxy_StringT_To_String_ptr) {
return prop_types::tstring;
} else {
return prop_types::cstring;
}
}
case DPT_Array:
return prop_types::unknown;
@ -388,7 +402,7 @@ template <typename T>
class thread_var_base
{
protected:
using ptr_ret_t = std::conditional_t<std::is_pointer_v<T>, T, T *>;
using ptr_ret_t = std::conditional_t<std::is_pointer<T>::value, T, T *>;
public:
inline void reset(std::nullptr_t) noexcept
@ -405,7 +419,9 @@ public:
{
}
thread_var_base() noexcept = default;
inline thread_var_base() noexcept
{
}
inline bool operator!() const noexcept;
@ -442,9 +458,12 @@ protected:
if(!ptr) {
return nullptr;
}
#if 0
if constexpr(std::is_pointer_v<T>) {
return *ptr;
} else {
} else
#endif
{
return ptr;
}
}
@ -532,6 +551,11 @@ public:
return *ptr;
}
inline thread_var() noexcept
: thread_var_base<T>{}
{
}
inline thread_var(const T &val) noexcept
{ *this->get_or_allocate_ptr() = val; }
@ -584,6 +608,11 @@ public:
using thread_var_base<bool>::thread_var_base;
using thread_var_base<bool>::reset;
inline thread_var()
: thread_var_base<bool>{}
{
}
inline bool operator*() const noexcept
{ return get(); }
@ -624,6 +653,42 @@ private:
}
};
CBaseEntity *ReferenceToEntity(unsigned long ref)
{
union {
cell_t sp_val;
unsigned long e_val;
} u;
u.e_val = ref;
return gamehelpers->ReferenceToEntity(u.sp_val);
}
unsigned long EntityToReference(CBaseEntity *ent)
{
union {
cell_t sp_val;
unsigned long e_val;
} u;
u.sp_val = gamehelpers->EntityToReference(ent);
return u.e_val;
}
unsigned long IndexToReference(int objectID)
{
union {
cell_t sp_val;
unsigned long e_val;
} u;
u.sp_val = gamehelpers->IndexToReference(objectID);
return u.e_val;
}
struct packed_entity_data_t final
{
packed_entity_data_t(packed_entity_data_t &&other) noexcept
@ -640,7 +705,7 @@ struct packed_entity_data_t final
char *packedData{nullptr};
bf_write *writeBuf{nullptr};
int ref{INVALID_EHANDLE_INDEX};
unsigned long ref{INVALID_EHANDLE_INDEX};
bool allocated() const noexcept
{ return (packedData && writeBuf); }
@ -668,6 +733,7 @@ struct packed_entity_data_t final
reset();
packedData = static_cast<char *>(aligned_alloc(4, MAX_PACKEDENTITY_DATA));
memset(packedData, 0x0, MAX_PACKEDENTITY_DATA);
writeBuf = new bf_write{"SV_PackEntity->writeBuf", packedData, MAX_PACKEDENTITY_DATA};
}
@ -680,10 +746,10 @@ struct pack_entity_params_t final
{
std::vector<std::vector<packed_entity_data_t>> entity_data{};
std::vector<int> slots{};
std::vector<int> entities{};
std::vector<unsigned long> entities{};
int snapshot_index{-1};
pack_entity_params_t(std::vector<int> &&slots_, std::vector<int> &&entities_, int snapshot_index_) noexcept
pack_entity_params_t(std::vector<int> &&slots_, std::vector<unsigned long> &&entities_, int snapshot_index_) noexcept
: slots{std::move(slots_)}, entities{std::move(entities_)}, snapshot_index{snapshot_index_}
{
entity_data.resize(slots.size());
@ -697,13 +763,13 @@ private:
pack_entity_params_t &operator=(pack_entity_params_t &&) = delete;
};
static thread_var<bool> in_compute_packs;
static thread_var<bool> do_calc_delta;
static thread_var<bool> do_writedelta_entities;
static thread_var<int> writedeltaentities_client;
static thread_var<int> sendproxy_client_slot;
static thread_var<bool> in_compute_packs{};
static thread_var<bool> do_calc_delta{};
static thread_var<bool> do_writedelta_entities{};
static thread_var<int> writedeltaentities_client{};
static thread_var<int> sendproxy_client_slot{};
static std::unique_ptr<pack_entity_params_t> packentity_params;
static std::unique_ptr<pack_entity_params_t> packentity_params{};
static void Host_Error(const char *error, ...) noexcept
{
@ -723,7 +789,8 @@ struct prop_reference_t
{
restores_t::iterator it_restore{restores.find(pProp)};
if(it_restore == restores.end()) {
it_restore = restores.emplace(std::pair<SendProp *, std::unique_ptr<proxyrestore_t>>{pProp, new proxyrestore_t{pProp, type}}).first;
std::unique_ptr<proxyrestore_t> ptr{new proxyrestore_t{pProp, type}};
it_restore = restores.emplace(std::pair<SendProp *, std::unique_ptr<proxyrestore_t>>{pProp, std::move(ptr)}).first;
}
restore = it_restore->second.get();
++restore->ref;
@ -777,8 +844,11 @@ struct opaque_ptr final
{ operator=(std::move(other)); }
template <typename T>
static void del_hlpr(void *ptr_) noexcept
static void del_hlpr_arr(void *ptr_) noexcept
{ delete[] static_cast<T *>(ptr_); }
template <typename T>
static void del_hlpr(void *ptr_) noexcept
{ delete static_cast<T *>(ptr_); }
opaque_ptr() = default;
@ -787,8 +857,16 @@ struct opaque_ptr final
if(del_func && ptr) {
del_func(ptr);
}
ptr = static_cast<void *>(new T{std::forward<Args>(args)...});
del_func = del_hlpr<T>;
if(num > 1) {
ptr = static_cast<void *>(new T[num]);
for(size_t i = 0; i < num; ++i) {
new (&static_cast<T *>(ptr)[i]) T{std::forward<Args>(args)...};
}
del_func = del_hlpr_arr<T>;
} else {
ptr = static_cast<void *>(new T{std::forward<Args>(args)...});
del_func = del_hlpr<T>;
}
}
void clear() noexcept {
@ -838,7 +916,7 @@ private:
struct callback_t final : prop_reference_t
{
callback_t(int ref_, SendProp *pProp, std::string &&name_, int element_, prop_types type_, std::size_t offset_) noexcept
callback_t(unsigned long ref_, SendProp *pProp, std::string &&name_, int element_, prop_types type_, std::size_t offset_) noexcept
: prop_reference_t{pProp, type_}, offset{offset_}, type{type_}, element{element_}, name{std::move(name_)}, prop{pProp}, ref{ref_}
{
if(type == prop_types::cstring || type == prop_types::tstring) {
@ -878,10 +956,12 @@ struct callback_t final : prop_reference_t
void change_edict_state() noexcept
{
if(ref != INVALID_EHANDLE_INDEX) {
CBaseEntity *pEntity{gamehelpers->ReferenceToEntity(ref)};
edict_t *edict{pEntity->GetNetworkable()->GetEdict()};
if(edict) {
gamehelpers->SetEdictStateChanged(edict, offset);
CBaseEntity *pEntity{::ReferenceToEntity(ref)};
if(pEntity) {
edict_t *edict{pEntity->GetNetworkable()->GetEdict()};
if(edict) {
gamehelpers->SetEdictStateChanged(edict, offset);
}
}
}
}
@ -980,6 +1060,8 @@ struct callback_t final : prop_reference_t
pEntity = gamehelpers->ReferenceToEntity(sp_value);
if(pEntity) {
new_value = pEntity->GetRefEHandle();
} else {
new_value.Term();
}
return true;
}
@ -1086,8 +1168,10 @@ struct callback_t final : prop_reference_t
fwd->PushCell(objectID);
fwd->PushStringEx((char *)name.c_str(), name.size()+1, SM_PARAM_STRING_COPY|SM_PARAM_STRING_UTF8, 0);
static char sp_value[4096];
strcpy(sp_value, reinterpret_cast<const char *>(old_pData));
fwd->PushStringEx(sp_value, sizeof(sp_value), SM_PARAM_STRING_UTF8|SM_PARAM_STRING_COPY, SM_PARAM_COPYBACK);
const char *str{reinterpret_cast<const char *>(old_pData)};
size_t len{strlen(str)};
strcpy(sp_value, str);
fwd->PushStringEx(sp_value, len, SM_PARAM_STRING_UTF8|SM_PARAM_STRING_COPY, SM_PARAM_COPYBACK);
fwd->PushCell(sizeof(sp_value));
fwd->PushCell(element);
fwd->PushCell(client);
@ -1107,8 +1191,10 @@ struct callback_t final : prop_reference_t
fwd->PushCell(objectID);
fwd->PushStringEx((char *)name.c_str(), name.size()+1, SM_PARAM_STRING_COPY|SM_PARAM_STRING_UTF8, 0);
static char sp_value[4096];
strcpy(sp_value, STRING(*reinterpret_cast<const string_t *>(old_pData)));
fwd->PushStringEx(sp_value, sizeof(sp_value), SM_PARAM_STRING_UTF8|SM_PARAM_STRING_COPY, SM_PARAM_COPYBACK);
const char *str{STRING(*reinterpret_cast<const string_t *>(old_pData))};
size_t len{strlen(str)};
strcpy(sp_value, str);
fwd->PushStringEx(sp_value, len, SM_PARAM_STRING_UTF8|SM_PARAM_STRING_COPY, SM_PARAM_COPYBACK);
fwd->PushCell(sizeof(sp_value));
fwd->PushCell(element);
fwd->PushCell(client);
@ -1207,7 +1293,7 @@ struct callback_t final : prop_reference_t
int element{0};
std::string name{};
SendProp *prop{nullptr};
int ref{INVALID_EHANDLE_INDEX};
unsigned long ref{INVALID_EHANDLE_INDEX};
struct per_client_func_t
{
@ -1248,9 +1334,9 @@ using callbacks_t = std::unordered_map<const SendProp *, callback_t>;
struct proxyhook_t final
{
callbacks_t callbacks;
int ref{INVALID_EHANDLE_INDEX};
unsigned long ref{INVALID_EHANDLE_INDEX};
inline proxyhook_t(int ref_) noexcept
inline proxyhook_t(unsigned long ref_) noexcept
: ref{ref_}
{
}
@ -1286,7 +1372,7 @@ private:
proxyhook_t() = delete;
};
using hooks_t = std::unordered_map<int, proxyhook_t>;
using hooks_t = std::unordered_map<unsigned long, proxyhook_t>;
static hooks_t hooks;
DETOUR_DECL_STATIC6(SendTable_Encode, bool, const SendTable *, pTable, const void *, pStruct, bf_write *, pOut, int, objectID, CUtlMemory<CSendProxyRecipients> *, pRecipients, bool, bNonZeroOnly)
@ -1305,14 +1391,15 @@ DETOUR_DECL_STATIC6(SendTable_Encode, bool, const SendTable *, pTable, const voi
}
}
int ref{gamehelpers->IndexToReference(objectID)};
unsigned long ref{::IndexToReference(objectID)};
const std::vector<int> &entities{packentity_params->entities};
const std::vector<unsigned long> &entities{packentity_params->entities};
if(std::find(entities.cbegin(), entities.cend(), ref) != entities.cend()) {
const std::size_t slots_size{packentity_params->slots.size()};
for(int i{0}; i < slots_size; ++i) {
for(std::size_t i{0}; i < slots_size; ++i) {
std::vector<packed_entity_data_t> &vec{packentity_params->entity_data[i]};
packed_entity_data_t &packedData{vec.emplace_back()};
vec.emplace_back();
packed_entity_data_t &packedData{vec.back()};
packedData.ref = ref;
packedData.allocate();
@ -1343,18 +1430,21 @@ DETOUR_DECL_STATIC8(SendTable_CalcDelta, int, const SendTable *, pTable, const v
int total_nChanges{global_nChanges};
if(total_nChanges < nMaxDeltaProps) {
int *client_deltaProps{new int[nMaxDeltaProps]};
int *client_deltaProps{new int[nMaxDeltaProps]{}};
int new_nChanges{total_nChanges};
unsigned long ref = ::IndexToReference(objectID);
const std::size_t slots_size{packentity_params->slots.size()};
for(int i{0}; i < slots_size; ++i) {
std::vector<packed_entity_data_t> &entity_data{packentity_params->entity_data[i]};
for(std::size_t i{0}; i < slots_size; ++i) {
using entity_data_t = std::vector<packed_entity_data_t>;
entity_data_t &entity_data{packentity_params->entity_data[i]};
packed_entity_data_t *packedData{nullptr};
for(auto it{entity_data.rbegin()}; it != entity_data.rend(); ++it) {
if(it->ref == gamehelpers->IndexToReference(objectID)) {
packedData = &*it;
for(entity_data_t::reverse_iterator it{entity_data.rbegin()}; it != entity_data.rend(); ++it) {
if(it->ref == ref) {
packedData = &(*it);
break;
}
}
@ -1447,11 +1537,11 @@ DETOUR_DECL_MEMBER2(CFrameSnapshotManager_GetPackedEntity, PackedEntity *, CFram
const int slot{writedeltaentities_client};
int ref{gamehelpers->IndexToReference(entity)};
unsigned long ref{::IndexToReference(entity)};
const packed_entity_data_t *packedData{nullptr};
const std::size_t slots_size{packentity_params->slots.size()};
for(int i{0}; i < slots_size; ++i) {
for(std::size_t i{0}; i < slots_size; ++i) {
if(packentity_params->slots[i] == slot) {
const std::vector<packed_entity_data_t> &entity_data{packentity_params->entity_data[i]};
for(const packed_entity_data_t &it : entity_data) {
@ -1481,10 +1571,13 @@ static ConVar *sv_stressbots{nullptr};
static bool is_client_valid(CBaseClient *client) noexcept
{
if(client->IsHLTV() ||
client->IsReplay()) {
return false;
}
if(!sv_stressbots->GetBool()) {
if(client->IsFakeClient() ||
client->IsHLTV() ||
client->IsReplay()) {
if(client->IsFakeClient()) {
return false;
}
}
@ -1537,9 +1630,16 @@ void PostWriteDeltaEntities()
DETOUR_DECL_MEMBER4(CBaseServer_WriteDeltaEntities, void, CBaseClient *, client, CClientFrame *, to, CClientFrame *, from, bf_write &, pBuf)
{
PreWriteDeltaEntities(client);
DETOUR_MEMBER_CALL(CBaseServer_WriteDeltaEntities)(client, to, from, pBuf);
PostWriteDeltaEntities();
CBaseServer *pthis = (CBaseServer *)this;
if(pthis->IsHLTV() ||
pthis->IsReplay()) {
DETOUR_MEMBER_CALL(CBaseServer_WriteDeltaEntities)(client, to, from, pBuf);
} else {
PreWriteDeltaEntities(client);
DETOUR_MEMBER_CALL(CBaseServer_WriteDeltaEntities)(client, to, from, pBuf);
PostWriteDeltaEntities();
}
}
static CDetour *CBaseServer_WriteDeltaEntities_detour{nullptr};
@ -1585,7 +1685,7 @@ DETOUR_DECL_STATIC3(SV_ComputeClientPacks, void, int, clientCount, CGameClient *
}
const std::size_t slots_size{slots.size()};
std::vector<int> entities{};
std::vector<unsigned long> entities{};
bool any_hook{false};
@ -1593,10 +1693,10 @@ DETOUR_DECL_STATIC3(SV_ComputeClientPacks, void, int, clientCount, CGameClient *
for(int i{0}; i < snapshot->m_nValidEntities; ++i) {
int idx{snapshot->m_pValidEntities[i]};
int ref{gamehelpers->IndexToReference(idx)};
unsigned long ref{::IndexToReference(idx)};
for(auto it : g_Sample.pack_ent_listeners) {
CBaseEntity *pEntity{gamehelpers->ReferenceToEntity(ref)};
CBaseEntity *pEntity{::ReferenceToEntity(ref)};
if(pEntity) {
it->pre_pack_entity(pEntity);
}
@ -1647,7 +1747,7 @@ DETOUR_DECL_STATIC3(SV_ComputeClientPacks, void, int, clientCount, CGameClient *
g_Sample.is_parallel_pack_allowed()
};
sv_parallel_sendsnapshot->SetValue(true);
//sv_parallel_sendsnapshot->SetValue(false);
sv_parallel_packentities->SetValue(parallel_pack);
in_compute_packs = true;
@ -1681,7 +1781,7 @@ bool Sample::add_listener(const parallel_pack_listener *ptr) noexcept
bool Sample::remove_listener(const parallel_pack_listener *ptr) noexcept
{
auto it{std::find(pack_ent_listeners.cbegin(), pack_ent_listeners.cend(), ptr)};
pack_ent_listeners_t::const_iterator it{std::find(pack_ent_listeners.cbegin(), pack_ent_listeners.cend(), ptr)};
if(it == pack_ent_listeners.cend()) {
return false;
}
@ -1696,7 +1796,7 @@ static void global_send_proxy(const SendProp *pProp, const void *pStructBase, co
if(objectID != -1) {
const hooks_t &chooks{hooks};
int ref{gamehelpers->IndexToReference(objectID)};
unsigned long ref{::IndexToReference(objectID)};
hooks_t::const_iterator it_hook{chooks.find(ref)};
if(it_hook != chooks.cend()) {
callbacks_t::const_iterator it_callback{it_hook->second.callbacks.find(pProp)};
@ -1735,7 +1835,29 @@ static void game_frame(bool simulating) noexcept
return;
}
// dumb nonsense so clients are fully aware that our hooked edicts are changing.
// this looks hacky, and it is, but there is not a better way i could find
// after tearing my hair out for 3 days of research
// sappho.io
for (auto& hook : hooks)
{
unsigned long ref = hook.first; // hook.second.ref;
//for (auto& cb : hook.second.callbacks)
//{
// cb.second.change_edict_state();
//}
CBaseEntity* pEntity = ::ReferenceToEntity(ref);
if (!pEntity)
{
continue;
}
edict_t* edict = pEntity->GetNetworkable()->GetEdict();
if (!edict)
{
continue;
}
gamehelpers->SetEdictStateChanged(edict, 0);
}
}
DETOUR_DECL_MEMBER1(CGameServer_SendClientMessages, void, bool, bSendSnapshots)
@ -1812,11 +1934,13 @@ static bool UTIL_FindInSendTable(SendTable *pTable,
return false;
}
static std::unordered_map<ServerClass *, std::unordered_map<std::string, sm_sendprop_info_ex_t>> propinfos;
using propinfo_t = std::unordered_map<std::string, sm_sendprop_info_ex_t>;
using propinfos_t = std::unordered_map<ServerClass *, propinfo_t>;
static propinfos_t propinfos;
bool Sample::remove_serverclass_from_cache(ServerClass *pClass) noexcept
{
auto it_props{propinfos.find(pClass)};
propinfos_t::iterator it_props{propinfos.find(pClass)};
if(it_props == propinfos.cend()) {
return false;
}
@ -1827,12 +1951,12 @@ bool Sample::remove_serverclass_from_cache(ServerClass *pClass) noexcept
static bool FindSendPropInfo(ServerClass *pClass, std::string &&name, sm_sendprop_info_ex_t *info) noexcept
{
auto it_props{propinfos.find(pClass)};
propinfos_t::iterator it_props{propinfos.find(pClass)};
if(it_props == propinfos.cend()) {
it_props = propinfos.emplace(std::pair<ServerClass *, std::unordered_map<std::string, sm_sendprop_info_ex_t>>{pClass, {}}).first;
it_props = propinfos.emplace(std::pair<ServerClass *, propinfo_t>{pClass, propinfo_t{}}).first;
}
if(it_props != propinfos.cend()) {
auto it_prop{it_props->second.find(name)};
propinfo_t::iterator it_prop{it_props->second.find(name)};
if(it_prop == it_props->second.cend()) {
if(UTIL_FindInSendTable(pClass->m_pTable, name.c_str(), info, 0)) {
it_prop = it_props->second.emplace(std::pair<std::string, sm_sendprop_info_ex_t>{std::move(name), std::move(*info)}).first;
@ -1846,7 +1970,7 @@ static bool FindSendPropInfo(ServerClass *pClass, std::string &&name, sm_sendpro
return false;
}
static cell_t proxysend_handle_hook(IPluginContext *pContext, hooks_t::iterator it_hook, int idx, int offset, SendProp *pProp, std::string &&prop_name, int element, SendTable *pTable, IPluginFunction *callback, bool per_client)
static cell_t proxysend_handle_hook(IPluginContext *pContext, hooks_t::iterator it_hook, unsigned long ref, int offset, SendProp *pProp, std::string &&prop_name, int element, SendTable *pTable, IPluginFunction *callback, bool per_client)
{
prop_types type{prop_types::unknown};
restores_t::const_iterator it_restore{restores.find(pProp)};
@ -1860,7 +1984,7 @@ static cell_t proxysend_handle_hook(IPluginContext *pContext, hooks_t::iterator
}
#ifdef _DEBUG
printf("added %s %p hook for %i\n", pProp->GetName(), pProp, idx);
printf("added %s %p hook for %i\n", pProp->GetName(), pProp, ref);
#endif
it_hook->second.add_callback(pProp, std::move(prop_name), element, type, offset, callback, per_client);
@ -1895,31 +2019,44 @@ static cell_t proxysend_hook(IPluginContext *pContext, const cell_t *params) noe
SendProp *pProp{info.prop};
std::string prop_name{pProp->GetName()};
int ref = gamehelpers->EntityToReference(pEntity);
unsigned long ref = ::EntityToReference(pEntity);
hooks_t::iterator it_hook{hooks.find(ref)};
if(it_hook == hooks.end()) {
it_hook = hooks.emplace(std::pair<int, proxyhook_t>{ref, proxyhook_t{ref}}).first;
it_hook = hooks.emplace(std::pair<unsigned long, proxyhook_t>{ref, proxyhook_t{ref}}).first;
}
edict_t *edict{pEntity->GetNetworkable()->GetEdict()};
if(pProp->GetType() == DPT_DataTable) {
SendTable *pPropTable{pProp->GetDataTable()};
int NumProps{pPropTable->GetNumProps()};
for(int i = 0; i < NumProps; ++i) {
SendProp *pChildProp{pPropTable->GetProp(i)};
std::string tmp_name{prop_name};
cell_t ret{proxysend_handle_hook(pContext, it_hook, ref, info.actual_offset + pChildProp->GetOffset(), pChildProp, std::move(tmp_name), i, pTable, callback, per_client)};
int offset{info.actual_offset + pChildProp->GetOffset()};
cell_t ret{proxysend_handle_hook(pContext, it_hook, ref, offset, pChildProp, std::move(tmp_name), i, pTable, callback, per_client)};
if(ret != 0) {
return ret;
}
if(edict) {
gamehelpers->SetEdictStateChanged(edict, offset);
}
}
return 0;
}
return proxysend_handle_hook(pContext, it_hook, ref, info.actual_offset, pProp, std::move(prop_name), 0, pTable, callback, per_client);
cell_t ret{proxysend_handle_hook(pContext, it_hook, ref, info.actual_offset, pProp, std::move(prop_name), 0, pTable, callback, per_client)};
if(ret == 0) {
if(edict) {
gamehelpers->SetEdictStateChanged(edict, info.actual_offset);
}
}
return ret;
}
static void proxysend_handle_unhook(hooks_t::iterator it_hook, int ref, const SendProp *pProp, const char *name, IPluginFunction *callback)
static void proxysend_handle_unhook(hooks_t::iterator it_hook, unsigned long ref, const SendProp *pProp, const char *name, IPluginFunction *callback)
{
callbacks_t::iterator it_callback{it_hook->second.callbacks.find(pProp)};
if(it_callback != it_hook->second.callbacks.end()) {
@ -1958,7 +2095,7 @@ static cell_t proxysend_unhook(IPluginContext *pContext, const cell_t *params) n
IPluginFunction *callback{pContext->GetFunctionById(params[3])};
int ref = gamehelpers->EntityToReference(pEntity);
unsigned long ref = gamehelpers->EntityToReference(pEntity);
hooks_t::iterator it_hook{hooks.find(ref)};
if(it_hook != hooks.end()) {
@ -1977,6 +2114,11 @@ static cell_t proxysend_unhook(IPluginContext *pContext, const cell_t *params) n
}
}
edict_t *edict{pEntity->GetNetworkable()->GetEdict()};
if(edict) {
gamehelpers->SetEdictStateChanged(edict, 0);
}
return 0;
}
@ -2025,6 +2167,15 @@ bool Sample::SDK_OnLoad(char *error, size_t maxlen, bool late) noexcept
return false;
}
gameconf->GetMemSig("SendProxy_StringT_To_String", (void **)&SendProxy_StringT_To_String_ptr);
if(SendProxy_StringT_To_String_ptr == nullptr) {
snprintf(error, maxlen, "could not get SendProxy_StringT_To_String address");
return false;
}
gameconf->GetMemSig("SendProxy_Color32ToInt", (void **)&SendProxy_Color32ToInt_ptr);
gameconf->GetMemSig("SendProxy_EHandleToInt", (void **)&SendProxy_EHandleToInt_ptr);
CDetourManager::Init(smutils->GetScriptingEngine(), gameconf);
SendTable_CalcDelta_detour = DETOUR_CREATE_STATIC(SendTable_CalcDelta, "SendTable_CalcDelta");
@ -2057,7 +2208,7 @@ bool Sample::SDK_OnLoad(char *error, size_t maxlen, bool late) noexcept
return false;
}
#if SOURCE_ENGINE == SE_TF2
#if SOURCE_ENGINE == SE_TF2 || SOURCE_ENGINE == SE_CSS
{
void **vtable = *(void ***)server;
int index = vfunc_index(&CBaseServer::WriteDeltaEntities);
@ -2122,7 +2273,7 @@ bool Sample::SDK_OnMetamodLoad(ISmmAPI *ismm, char *error, size_t maxlen, bool l
GET_V_IFACE_ANY(GetEngineFactory, g_pCVar, ICvar, CVAR_INTERFACE_VERSION);
ConVar_Register(0, this);
#if SOURCE_ENGINE == SE_TF2
#if SOURCE_ENGINE == SE_TF2 || SOURCE_ENGINE == SE_CSS
server = engine->GetIServer();
#endif
@ -2172,7 +2323,7 @@ void Sample::OnEntityDestroyed(CBaseEntity *pEntity) noexcept
return;
}
const int ref{gamehelpers->EntityToReference(pEntity)};
const unsigned long ref{::EntityToReference(pEntity)};
hooks_t::iterator it_hook{hooks.find(ref)};
if(it_hook != hooks.end()) {

View File

@ -48,7 +48,8 @@
class Sample final : public SDKExtension, public IPluginsListener, public ISMEntityListener, public IConCommandBaseAccessor, public proxysend
{
public:
std::vector<const parallel_pack_listener *> pack_ent_listeners;
using pack_ent_listeners_t = std::vector<const parallel_pack_listener *>;
pack_ent_listeners_t pack_ent_listeners{};
bool add_listener(const parallel_pack_listener *ptr) noexcept override final;
bool remove_listener(const parallel_pack_listener *ptr) noexcept override final;

View File

@ -40,7 +40,7 @@
/* Basic information exposed publicly */
#define SMEXT_CONF_NAME "proxysend"
#define SMEXT_CONF_DESCRIPTION "proxysend"
#define SMEXT_CONF_VERSION "0.1.0.6"
#define SMEXT_CONF_VERSION "0.1.0.8"
#define SMEXT_CONF_AUTHOR "Arthurdead"
#define SMEXT_CONF_URL ""
#define SMEXT_CONF_LOGTAG "PROXYSEND"

View File

@ -1,6 +1,6 @@
"Games"
{
"tf"
"#default"
{
"Offsets"
{
@ -60,6 +60,21 @@
"library" "engine"
"linux" "@_ZN10PackWork_t7ProcessERS_"
}
"SendProxy_StringT_To_String"
{
"library" "server"
"linux" "@_Z27SendProxy_StringT_To_StringPK8SendPropPKvS3_P8DVariantii"
}
"SendProxy_Color32ToInt"
{
"library" "server"
"linux" "@_Z22SendProxy_Color32ToIntPK8SendPropPKvS3_P8DVariantii"
}
"SendProxy_EHandleToInt"
{
"library" "server"
"linux" "@_Z22SendProxy_EHandleToIntPK8SendPropPKvS3_P8DVariantii"
}
}
}
}

View File

@ -3,7 +3,6 @@
#endif
#define __PROXYSEND_INC
#include <tf2>
#include <sdktools>
typeset proxysend_callbacks
@ -12,7 +11,6 @@ typeset proxysend_callbacks
function Action (int entity, const char[] prop, RoundState &value, int element, int client);
function Action (int entity, const char[] prop, RenderMode &value, int element, int client);
function Action (int entity, const char[] prop, RenderFx &value, int element, int client);
function Action (int entity, const char[] prop, TFClassType &value, int element, int client);
function Action (int entity, const char[] prop, bool &value, int element, int client);
@ -28,58 +26,9 @@ typeset proxysend_callbacks
native void proxysend_hook(int entity, const char[] prop, proxysend_callbacks callback, bool per_client);
native void proxysend_unhook(int entity, const char[] prop, proxysend_callbacks callback);
stock int get_bit_for_cond(TFCond cond)
{
int icond = view_as<int>(cond);
switch(icond / 32) {
case 0: return (1 << icond);
case 1: return (1 << (icond - 32));
case 2: return (1 << (icond - 64));
case 3: return (1 << (icond - 96));
case 4: return (1 << (icond - 128));
default: ThrowError("Invalid TFCond value %d", icond);
}
return 0;
}
stock void get_prop_name_for_cond(TFCond cond, char[] name, int len)
{
int icond = view_as<int>(cond);
switch(icond / 32) {
case 0: strcopy(name, len, "m_nPlayerCond");
case 1: strcopy(name, len, "m_nPlayerCondEx");
case 2: strcopy(name, len, "m_nPlayerCondEx2");
case 3: strcopy(name, len, "m_nPlayerCondEx3");
case 4: strcopy(name, len, "m_nPlayerCondEx4");
default: ThrowError("Invalid TFCond value %d", icond);
}
}
stock void proxysend_hook_cond(int entity, TFCond cond, proxysend_callbacks callback, bool per_client)
{
int icond = view_as<int>(cond);
switch(icond / 32) {
case 0: proxysend_hook(entity, "m_nPlayerCond", callback, per_client);
case 1: proxysend_hook(entity, "m_nPlayerCondEx", callback, per_client);
case 2: proxysend_hook(entity, "m_nPlayerCondEx2", callback, per_client);
case 3: proxysend_hook(entity, "m_nPlayerCondEx3", callback, per_client);
case 4: proxysend_hook(entity, "m_nPlayerCondEx4", callback, per_client);
default: ThrowError("Invalid TFCond value %d", icond);
}
}
stock void proxysend_unhook_cond(int entity, TFCond cond, proxysend_callbacks callback)
{
int icond = view_as<int>(cond);
switch(icond / 32) {
case 0: proxysend_unhook(entity, "m_nPlayerCond", callback);
case 1: proxysend_unhook(entity, "m_nPlayerCondEx", callback);
case 2: proxysend_unhook(entity, "m_nPlayerCondEx2", callback);
case 3: proxysend_unhook(entity, "m_nPlayerCondEx3", callback);
case 4: proxysend_unhook(entity, "m_nPlayerCondEx4", callback);
default: ThrowError("Invalid TFCond value %d", icond);
}
}
#if defined _tf2_included || defined _tf2_stocks_included
#include <proxysend_tf2>
#endif
#if !defined REQUIRE_EXTENSIONS
public __ext_proxysend_SetNTVOptional()

View File

@ -0,0 +1,63 @@
#if defined __PROXYSEND_TF2_INC
#endinput
#endif
#define __PROXYSEND_TF2_INC
#include <tf2>
#if !defined __PROXYSEND_INC
#include <proxysend>
#endif
stock int get_bit_for_cond(TFCond cond)
{
int icond = view_as<int>(cond);
switch(icond / 32) {
case 0: return (1 << icond);
case 1: return (1 << (icond - 32));
case 2: return (1 << (icond - 64));
case 3: return (1 << (icond - 96));
case 4: return (1 << (icond - 128));
default: ThrowError("Invalid TFCond value %d", icond);
}
return 0;
}
stock void get_prop_name_for_cond(TFCond cond, char[] name, int len)
{
int icond = view_as<int>(cond);
switch(icond / 32) {
case 0: strcopy(name, len, "m_nPlayerCond");
case 1: strcopy(name, len, "m_nPlayerCondEx");
case 2: strcopy(name, len, "m_nPlayerCondEx2");
case 3: strcopy(name, len, "m_nPlayerCondEx3");
case 4: strcopy(name, len, "m_nPlayerCondEx4");
default: ThrowError("Invalid TFCond value %d", icond);
}
}
stock void proxysend_hook_cond(int entity, TFCond cond, proxysend_callbacks callback, bool per_client)
{
int icond = view_as<int>(cond);
switch(icond / 32) {
case 0: proxysend_hook(entity, "m_nPlayerCond", callback, per_client);
case 1: proxysend_hook(entity, "m_nPlayerCondEx", callback, per_client);
case 2: proxysend_hook(entity, "m_nPlayerCondEx2", callback, per_client);
case 3: proxysend_hook(entity, "m_nPlayerCondEx3", callback, per_client);
case 4: proxysend_hook(entity, "m_nPlayerCondEx4", callback, per_client);
default: ThrowError("Invalid TFCond value %d", icond);
}
}
stock void proxysend_unhook_cond(int entity, TFCond cond, proxysend_callbacks callback)
{
int icond = view_as<int>(cond);
switch(icond / 32) {
case 0: proxysend_unhook(entity, "m_nPlayerCond", callback);
case 1: proxysend_unhook(entity, "m_nPlayerCondEx", callback);
case 2: proxysend_unhook(entity, "m_nPlayerCondEx2", callback);
case 3: proxysend_unhook(entity, "m_nPlayerCondEx3", callback);
case 4: proxysend_unhook(entity, "m_nPlayerCondEx4", callback);
default: ThrowError("Invalid TFCond value %d", icond);
}
}