Compare commits

..

No commits in common. "master" and "0.1.0.6" have entirely different histories.

8 changed files with 2372 additions and 2554 deletions

View File

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

View File

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

View File

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

View File

@ -48,8 +48,7 @@
class Sample final : public SDKExtension, public IPluginsListener, public ISMEntityListener, public IConCommandBaseAccessor, public proxysend class Sample final : public SDKExtension, public IPluginsListener, public ISMEntityListener, public IConCommandBaseAccessor, public proxysend
{ {
public: public:
using pack_ent_listeners_t = std::vector<const parallel_pack_listener *>; std::vector<const parallel_pack_listener *> pack_ent_listeners;
pack_ent_listeners_t pack_ent_listeners{};
bool add_listener(const parallel_pack_listener *ptr) noexcept override final; bool add_listener(const parallel_pack_listener *ptr) noexcept override final;
bool remove_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 */ /* Basic information exposed publicly */
#define SMEXT_CONF_NAME "proxysend" #define SMEXT_CONF_NAME "proxysend"
#define SMEXT_CONF_DESCRIPTION "proxysend" #define SMEXT_CONF_DESCRIPTION "proxysend"
#define SMEXT_CONF_VERSION "0.1.0.8" #define SMEXT_CONF_VERSION "0.1.0.6"
#define SMEXT_CONF_AUTHOR "Arthurdead" #define SMEXT_CONF_AUTHOR "Arthurdead"
#define SMEXT_CONF_URL "" #define SMEXT_CONF_URL ""
#define SMEXT_CONF_LOGTAG "PROXYSEND" #define SMEXT_CONF_LOGTAG "PROXYSEND"

View File

@ -1,6 +1,6 @@
"Games" "Games"
{ {
"#default" "tf"
{ {
"Offsets" "Offsets"
{ {
@ -60,21 +60,6 @@
"library" "engine" "library" "engine"
"linux" "@_ZN10PackWork_t7ProcessERS_" "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,6 +3,7 @@
#endif #endif
#define __PROXYSEND_INC #define __PROXYSEND_INC
#include <tf2>
#include <sdktools> #include <sdktools>
typeset proxysend_callbacks typeset proxysend_callbacks
@ -11,6 +12,7 @@ typeset proxysend_callbacks
function Action (int entity, const char[] prop, RoundState &value, int element, int client); 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, 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, 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); function Action (int entity, const char[] prop, bool &value, int element, int client);
@ -26,9 +28,58 @@ typeset proxysend_callbacks
native void proxysend_hook(int entity, const char[] prop, proxysend_callbacks callback, bool per_client); 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); native void proxysend_unhook(int entity, const char[] prop, proxysend_callbacks callback);
#if defined _tf2_included || defined _tf2_stocks_included stock int get_bit_for_cond(TFCond cond)
#include <proxysend_tf2> {
#endif 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 REQUIRE_EXTENSIONS #if !defined REQUIRE_EXTENSIONS
public __ext_proxysend_SetNTVOptional() public __ext_proxysend_SetNTVOptional()

View File

@ -1,63 +0,0 @@
#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);
}
}