diff --git a/addons/source-python/packages/source-python/entities/_base.py b/addons/source-python/packages/source-python/entities/_base.py index e2bb09c92..8b27ad37d 100755 --- a/addons/source-python/packages/source-python/entities/_base.py +++ b/addons/source-python/packages/source-python/entities/_base.py @@ -68,6 +68,7 @@ # Source.Python Imports # Entities from _entities._entity import BaseEntity +from _entities._transmit import transmit_manager # ============================================================================= @@ -842,6 +843,71 @@ def set_parent(self, parent, attachment=INVALID_ATTACHMENT_INDEX): return [parent, attachment] + # ========================================================================= + # >> ENTITY TRANSMIT FUNCTIONALITY + # ========================================================================= + def hide(self): + """Hide the entity from all players.""" + transmit_manager.hide(self.index) + + def hide_from(self, player_index): + """Hide the entity from player. + + :param int player_index: + The target player index to hide this entity. + """ + transmit_manager.hide_from(self.index, player_index) + + def show(self): + """Show the entity to all players.""" + transmit_manager.show(self.index) + + def show_from(self, player_index): + """Show the entity to player. + + :param int player_index: + The target player index to show this entity. + """ + transmit_manager.show_from(self.index, player_index) + + def reset(self): + """Reset the entity's hidden/shown state.""" + transmit_manager.reset(self.index) + + def reset_from(self, player_index): + """Reset the player's entity hidden/shown state. + + :param int player_index: + The target player index to reset the player's hidden/shown state. + """ + transmit_manager.reset_from(self.index, player_index) + + def is_hidden(self): + """Return True if the entity is hidden from any player. + + :rtype: bool + """ + return transmit_manager.is_hidden(self.index) + + def is_hidden_from(self, player_index): + """Return True if the entity is hidden from the player. + + :param int player_index: + The target player index to check if the entity is hidden. + :rtype: bool + """ + return transmit_manager.is_hidden_from(self.index, player_index) + + def get_hidden_player(self): + """Get the players where the entity is hidden. + + :return: + A tuple containing :class:`players.entity.Player` instances + in which the entity is hidden. + :rtype: tuple + """ + return transmit_manager.get_hidden_player(self.index) + # ============================================================================= # >> LISTENERS @@ -873,3 +939,6 @@ def _on_networked_entity_deleted(index): # Invalidate the internal entity caches for this entity for cls in _entity_classes: cls.cache.pop(index, None) + + # Reset the entity's hidden state. + transmit_manager.reset(index) diff --git a/addons/source-python/packages/source-python/entities/transmit.py b/addons/source-python/packages/source-python/entities/transmit.py new file mode 100755 index 000000000..07e6e989f --- /dev/null +++ b/addons/source-python/packages/source-python/entities/transmit.py @@ -0,0 +1,29 @@ +# ../entities/transmit.py + +"""Provides entity transmission filtering.""" + + +# ============================================================================ +# >> FORWARD IMPORTS +# ============================================================================ +# Source.Python +# Entities +from _entities._transmit import transmit_manager + + +# ============================================================================ +# >> ALL DECLARATION +# ============================================================================ +__all__ = ( + 'transmit_manager', + 'reset_hidden_state', +) + + +# ============================================================================= +# >> FUNCTIONS +# ============================================================================= +def reset_hidden_state(): + """Reset all entities' hidden/shown state.""" + transmit_manager.reset_all() + diff --git a/addons/source-python/packages/source-python/players/_base.py b/addons/source-python/packages/source-python/players/_base.py index bc20a0b0f..65010f23c 100755 --- a/addons/source-python/packages/source-python/players/_base.py +++ b/addons/source-python/packages/source-python/players/_base.py @@ -77,6 +77,14 @@ from auth.manager import auth_manager +# ============================================================================= +# >> FORWARD IMPORTS +# ============================================================================= +# Source.Python Imports +# Entities +from _entities._transmit import transmit_manager + + # ============================================================================= # >> CLASSES # ============================================================================= @@ -1004,6 +1012,56 @@ def drop_weapon(self, weapon, target=None, velocity=None): """ return [weapon, target, velocity] + # ========================================================================= + # >> PLAYER TRANSMIT FUNCTIONALITY + # ========================================================================= + def hide_entity(self, entity_index): + """Hide the entity from player. + + :param int entity_index: + The target entity index to hide from the player. + """ + transmit_manager.hide_from(entity_index, self.index) + + def show_entity(self, entity_index): + """Show the entity to player. + + :param int entity_index: + The target entity index to show the entity to player. + """ + transmit_manager.show_from(entity_index, self.index) + + def reset_entity(self, entity_index): + """Reset the player's entity hidden/shown state. + + :param int entity_index: + The target entity_index to reset the player's hidden/shown state. + """ + transmit_manager.reset_from(entity_index, self.index) + + def reset_all_entity(self): + """Reset the player's hidden/shown state on all entities.""" + transmit_manager.reset_player(self.index) + + def is_entity_hidden(self, entity_index): + """Return True if the entity is hidden from the player. + + :param int entity_index: + The target entity index to check if the entity is hidden. + :rtype: bool + """ + return transmit_manager.is_hidden_from(entity_index, self.index) + + def get_hidden_entity(self): + """Get the entities that are hidden from the player. + + :return: + A tuple containing :class:`entities.entity.Entity` instances + that are hidden from the player. + :rtype: tuple + """ + return transmit_manager.get_hidden_entity(self.index) + # ============================================================================= # >> HELPER FUNCTIONS diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 9bb21297a..12894d8ac 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -225,6 +225,7 @@ Set(SOURCEPYTHON_ENTITIES_MODULE_HEADERS core/modules/entities/${SOURCE_ENGINE}/entities_props_wrap.h core/modules/entities/${SOURCE_ENGINE}/entities_constants_wrap.h core/modules/entities/entities_entity.h + core/modules/entities/entities_transmit.h ) Set(SOURCEPYTHON_ENTITIES_MODULE_SOURCES @@ -241,6 +242,8 @@ Set(SOURCEPYTHON_ENTITIES_MODULE_SOURCES core/modules/entities/entities_props_wrap.cpp core/modules/entities/entities_entity.cpp core/modules/entities/entities_entity_wrap.cpp + core/modules/entities/entities_transmit.cpp + core/modules/entities/entities_transmit_wrap.cpp ) # ------------------------------------------------------------------ diff --git a/src/core/modules/entities/entities_transmit.cpp b/src/core/modules/entities/entities_transmit.cpp new file mode 100755 index 000000000..dceb6a8e8 --- /dev/null +++ b/src/core/modules/entities/entities_transmit.cpp @@ -0,0 +1,438 @@ +/** +* ============================================================================= +* Source Python +* Copyright (C) 2012-2020 Source Python Development Team. 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, the Source Python Team gives you permission +* to link the code of this program (as well as its derivative works) to +* "Half-Life 2," the "Source Engine," 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, the Source.Python +* Development Team grants this exception to all derivative works. +*/ + +//----------------------------------------------------------------------------- +// Includes. +//----------------------------------------------------------------------------- +#include "eiface.h" +#include "strtools.h" + +#include "utilities/conversions.h" +#include "modules/entities/entities_transmit.h" +#include "modules/memory/memory_pointer.h" +#include "modules/memory/memory_function_info.h" + + +//----------------------------------------------------------------------------- +// Eternal variables. +//----------------------------------------------------------------------------- +extern IServerGameEnts *gameents; +extern CGlobalVars *gpGlobals; +extern IPlayerInfoManager *playerinfomanager; + + +//----------------------------------------------------------------------------- +// Static variables. +//----------------------------------------------------------------------------- +CTransmitManager* CTransmitManager::instance = nullptr; + + +//----------------------------------------------------------------------------- +// CTransmitManager class. +//----------------------------------------------------------------------------- +CTransmitManager::CTransmitManager() + :m_arrayFilterIndexes() +{ + CFunctionInfo *pFunctionInfo = GetFunctionInfo(&IServerGameEnts::CheckTransmit); + if (!pFunctionInfo) + BOOST_RAISE_EXCEPTION( + PyExc_ValueError, + "Failed to retrieve CheckTransmit's info." + ) + + CFunction *pFunction = CPointer((unsigned long)((void *)gameents)).MakeVirtualFunction(*pFunctionInfo); + delete pFunctionInfo; + + if (!pFunction || !pFunction->IsHookable()) + BOOST_RAISE_EXCEPTION( + PyExc_ValueError, + "CheckTransmit is invalid or not hookable." + ) + + void *pAddr = (void *)pFunction->m_ulAddr; + CHook *pHook = GetHookManager()->FindHook(pAddr); + if (!pHook) + { + pHook = GetHookManager()->HookFunction(pAddr, pFunction->m_pCallingConvention); + if (!pHook) + BOOST_RAISE_EXCEPTION( + PyExc_ValueError, + "Failed to hook CheckTransmit." + ) + } + + //m_pCheckTransmit = (void *)pFunction->m_ulAddr; + delete pFunction; + + pHook->AddCallback( + HOOKTYPE_POST, + (HookHandlerFn *)&CTransmitManager::_post_check_transmit + ); + + current_clients = 0; + + IPlayerInfo* pPlayerInfo = nullptr; + ConVar* sv_replaybots = cvar->FindVar("sv_replaybots"); + ConVar* sv_stressbots = cvar->FindVar("sv_stressbots"); + + for (unsigned int i=1; i <= (unsigned int) gpGlobals->maxClients; ++i) + { + if (!PlayerInfoFromIndex(i, pPlayerInfo)) + continue; + + if ((pPlayerInfo->IsFakeClient() || V_strstr(pPlayerInfo->GetNetworkIDString(), "BOT")) && ( + (!sv_replaybots || !sv_replaybots->GetBool()) || + (!sv_stressbots || !sv_stressbots->GetBool()))) + continue; + + ++current_clients; + m_arrayFilterIndexes[i-1] = current_clients; + } + + unsigned int filter_size = bit_ceil(current_clients); + if (filter_size < 4) + filter_size = 4; + + m_vecFilters.resize(filter_size); + + for(auto it = m_vecFilters.begin(); it != m_vecFilters.begin()+current_clients; ++it) + { + it->hide.SetAll(); + } +} + + +CTransmitManager::~CTransmitManager() +{ +/* + CHook *pHook = GetHookManager()->FindHook(m_pCheckTransmit); + if (pHook) + pHook->RemoveCallback(HOOKTYPE_POST, (HookHandlerFn *)&CTransmitManager::_post_check_transmit); +*/ +} + + +CTransmitManager* CTransmitManager::get_instance() +{ + if (!instance) + create(); + + return instance; +} + + +void CTransmitManager::create() +{ + instance = new CTransmitManager; +} + + +/* +void CTransmitManager::destroy() +{ + delete instance; + instance = nullptr; +} +*/ + + +void CTransmitManager::add_player(edict_t* pEdict, unsigned int player_index) +{ + static ConVar* sv_replaybots = cvar->FindVar("sv_replaybots"); + static ConVar* sv_stressbots = cvar->FindVar("sv_stressbots"); + IPlayerInfo* pPlayerInfo = playerinfomanager->GetPlayerInfo(pEdict); + + if ((pPlayerInfo && + (pPlayerInfo->IsFakeClient() || V_strstr(pPlayerInfo->GetNetworkIDString(), "BOT"))) && ( + (!sv_replaybots || !sv_replaybots->GetBool()) || + (!sv_stressbots || !sv_stressbots->GetBool()))) + return; + + unsigned int filter_size = m_vecFilters.size(); + if (current_clients >= filter_size) + m_vecFilters.resize(filter_size*2); + + unsigned char filter_index; + if (find_filter_index(player_index, filter_index)) + { + ++current_clients; + m_arrayFilterIndexes[player_index-1] = filter_index; + + Filter& filter = m_vecFilters[filter_index-1]; + + filter.hide.SetAll(); + filter.show.ClearAll(); + } +} + + +void CTransmitManager::remove_player(edict_t* pEdict, unsigned int player_index) +{ + unsigned char filter_index; + if (get_filter_index(player_index, filter_index)) + { + --current_clients; + m_arrayFilterIndexes[player_index-1] = 0; + } +} + + +void CTransmitManager::hide(unsigned int entity_index) +{ + if (entity_index < 1 || entity_index >= MAX_EDICTS) + return; + + for(auto it = m_vecFilters.begin(); it != m_vecFilters.begin()+current_clients; ++it) + { + it->hide.Set((int) entity_index, false); + it->show.Set((int) entity_index, false); + } + + reset_from(entity_index, entity_index); +} + + +void CTransmitManager::hide_from(unsigned int entity_index, unsigned int player_index) +{ + if (entity_index < 1 || entity_index >= MAX_EDICTS) + return; + + if (player_index < 1 || player_index > (unsigned int) gpGlobals->maxClients) + return; + + if (entity_index == player_index) + return; + + unsigned char filter_index; + if (get_filter_index(player_index, filter_index)) + { + Filter& filter = m_vecFilters[filter_index-1]; + + filter.hide.Set((int) entity_index, false); + filter.show.Set((int) entity_index, false); + } +} + + +void CTransmitManager::show(unsigned int entity_index) +{ + if (entity_index < 1 || entity_index >= MAX_EDICTS) + return; + + for( auto it = m_vecFilters.begin(); it != m_vecFilters.begin()+current_clients; ++it) + { + it->hide.Set((int) entity_index, true); + it->show.Set((int) entity_index, true); + } +} + + +void CTransmitManager::show_from(unsigned int entity_index, unsigned int player_index) +{ + if (entity_index < 1 || entity_index >= MAX_EDICTS) + return; + + if (player_index < 1 || player_index > (unsigned int) gpGlobals->maxClients) + return; + + unsigned char filter_index; + if (get_filter_index(player_index, filter_index)) + { + Filter& filter = m_vecFilters[filter_index-1]; + + filter.hide.Set((int) entity_index, true); + filter.show.Set((int) entity_index, true); + } +} + + +void CTransmitManager::reset(unsigned int entity_index) +{ + if (entity_index < 1 || entity_index >= MAX_EDICTS) + return; + + for( auto it = m_vecFilters.begin(); it != m_vecFilters.begin()+current_clients; ++it) + { + it->hide.Set((int) entity_index, true); + it->show.Set((int) entity_index, false); + } +} + + +void CTransmitManager::reset_from(unsigned int entity_index, unsigned int player_index) +{ + if (entity_index < 1 || entity_index >= MAX_EDICTS) + return; + + if (player_index < 1 || player_index > (unsigned int) gpGlobals->maxClients) + return; + + unsigned char filter_index; + if (get_filter_index(player_index, filter_index)) + { + Filter& filter = m_vecFilters[filter_index-1]; + + filter.hide.Set((int) entity_index, true); + filter.show.Set((int) entity_index, false); + } +} + + +void CTransmitManager::reset_player(unsigned int player_index) +{ + if (player_index < 1 || player_index > (unsigned int) gpGlobals->maxClients) + return; + + unsigned char filter_index; + if (get_filter_index(player_index, filter_index)) + { + Filter& filter = m_vecFilters[filter_index-1]; + + filter.hide.SetAll(); + filter.show.ClearAll(); + } +} + + +void CTransmitManager::reset_all() +{ + for( auto it = m_vecFilters.begin(); it != m_vecFilters.begin()+current_clients; ++it) + { + it->hide.SetAll(); + it->show.ClearAll(); + } +} + + +bool CTransmitManager::is_hidden(unsigned int entity_index) +{ + if (entity_index < 1 || entity_index >= MAX_EDICTS) + return false; + + bool hidden_state = false; + + for( auto it = m_vecFilters.begin(); it != m_vecFilters.begin()+current_clients; ++it) + { + hidden_state |= (!it->hide.IsBitSet((int) entity_index)); + } + + return hidden_state; +} + + +bool CTransmitManager::is_hidden_from(unsigned int entity_index, unsigned int player_index) +{ + if (entity_index < 1 || entity_index >= MAX_EDICTS) + return false; + + if (player_index < 1 || player_index > (unsigned int) gpGlobals->maxClients) + return false; + + unsigned char filter_index; + if (get_filter_index(player_index, filter_index)) + { + Filter& filter = m_vecFilters[filter_index-1]; + + return (!filter.hide.IsBitSet((int) entity_index)); + } + + return false; +} + + +boost::python::tuple CTransmitManager::get_hidden_player(unsigned int entity_index) +{ + if (entity_index < 1 || entity_index >= MAX_EDICTS) + return boost::python::tuple(); + + static boost::python::object Player = boost::python::import("players.entity").attr("Player"); + + boost::python::list player_list; + + for (unsigned int i=1; i <= (unsigned int) gpGlobals->maxClients; ++i) + { + if (is_hidden_from(entity_index, i)) + player_list.append(Player(i)); + } + + return boost::python::tuple(player_list); +} + + +boost::python::tuple CTransmitManager::get_hidden_entity(unsigned int player_index) +{ + if (player_index < 1 || player_index > (unsigned int) gpGlobals->maxClients) + return boost::python::tuple(); + + static boost::python::object Entity = boost::python::import("entities.entity").attr("Entity"); + + boost::python::list entity_list; + + for (unsigned int i=1; i < MAX_EDICTS; ++i) + { + if (is_hidden_from(i, player_index)) + entity_list.append(Entity(i)); + } + + return boost::python::tuple(entity_list); +} + + +void CTransmitManager::handle_filters(TransmitStates_t* pTransmitEdict, unsigned int player_index) +{ + unsigned char filter_index; + if (get_filter_index(player_index, filter_index)) + { + Filter& filter = m_vecFilters[filter_index-1]; + + uint32* base = pTransmitEdict->Base(); + const uint32* hide = filter.hide.Base(); + const uint32* show = filter.show.Base(); + for (int i = 0; i < CalcNumIntsForBits(MAX_EDICTS); ++i) + { + base[i] = (base[i] & hide[i]) | show[i]; + } + } +} + + +bool CTransmitManager::_post_check_transmit(HookType_t eHookType, CHook* pHook) +{ + int nEdicts = pHook->GetArgument(3); + if (!nEdicts) + return false; + + CCheckTransmitInfo* pTransmitInfo = pHook->GetArgument(1); + + unsigned int player_index; + if (!IndexFromEdict(pTransmitInfo->m_pClientEnt, player_index)) + return false; + + instance->handle_filters(pTransmitInfo->m_pTransmitEdict, player_index); + + return false; +} + diff --git a/src/core/modules/entities/entities_transmit.h b/src/core/modules/entities/entities_transmit.h new file mode 100755 index 000000000..db6e74a89 --- /dev/null +++ b/src/core/modules/entities/entities_transmit.h @@ -0,0 +1,155 @@ +/** +* ============================================================================= +* Source Python +* Copyright (C) 2012-2020 Source Python Development Team. 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, the Source Python Team gives you permission +* to link the code of this program (as well as its derivative works) to +* "Half-Life 2," the "Source Engine," 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, the Source.Python +* Development Team grants this exception to all derivative works. +*/ + +#ifndef _ENTITIES_TRANSMIT_H +#define _ENTITIES_TRANSMIT_H + +//----------------------------------------------------------------------------- +// Includes. +//----------------------------------------------------------------------------- +#include +#include +#include +#include + +#ifdef _WIN32 + #include +#endif + +// Source SDK +#include "public/bitvec.h" + +// Source.Python +#include "utilities/baseentity.h" +#include "modules/memory/memory_function.h" + +// Boost.Python +#include "boost/python.hpp" + + +//----------------------------------------------------------------------------- +// TransmitStates_t definition. +//----------------------------------------------------------------------------- +typedef CBitVec TransmitStates_t; + + +//----------------------------------------------------------------------------- +// Filter struct. +//----------------------------------------------------------------------------- +struct Filter{ + TransmitStates_t hide; + TransmitStates_t show; +}; + + +//----------------------------------------------------------------------------- +// CTransmitManager class. +//----------------------------------------------------------------------------- +class CTransmitManager +{ +private: + CTransmitManager(); + ~CTransmitManager(); + + void handle_filters(TransmitStates_t* pTransmitEdict, unsigned int player_index); + static bool _post_check_transmit(HookType_t eHookType, CHook *pHook); + +public: + static CTransmitManager* get_instance(); + + static void create(); + //static void destroy(); + + void add_player(edict_t* pEdict, unsigned int player_index); + void remove_player(edict_t* pEdict, unsigned int player_index); + + void hide(unsigned int entity_index); + void hide_from(unsigned int entity_index, unsigned int player_index); + + void show(unsigned int entity_index); + void show_from(unsigned int entity_index, unsigned int player_index); + + void reset(unsigned int entity_index); + void reset_from(unsigned int entity_index, unsigned int player_index); + void reset_player(unsigned int player_index); + void reset_all(); + + bool is_hidden(unsigned int entity_index); + bool is_hidden_from(unsigned int entity_index, unsigned int player_index); + + boost::python::tuple get_hidden_player(unsigned int entity_index); + boost::python::tuple get_hidden_entity(unsigned int player_index); + + inline bool find_filter_index(unsigned int player_index, unsigned char& filter_index) + { + for (unsigned int i = 1; i <= m_arrayFilterIndexes.size(); ++i) + { + auto it = std::find(m_arrayFilterIndexes.begin(), m_arrayFilterIndexes.end(), i); + if (it == m_arrayFilterIndexes.end()) + { + filter_index = i; + return true; + } + } + return false; + } + + inline bool get_filter_index(unsigned int player_index, unsigned char& filter_index) + { + filter_index = m_arrayFilterIndexes[player_index-1]; + if (filter_index) + return true; + else + return false; + } + +private: + static CTransmitManager* instance; + + //void* m_pCheckTransmit; + + unsigned int current_clients; + std::vector m_vecFilters; + std::array m_arrayFilterIndexes; +}; + + +//----------------------------------------------------------------------------- +// Functions. +//----------------------------------------------------------------------------- +inline unsigned int bit_ceil(unsigned int x) +{ +#ifdef _WIN32 + unsigned long ret; + _BitScanReverse(&ret, (x-1)); + return 1 << (32 - (31 ^ ret));//(1 << (32 - __lzcnt(x)))) +#else + return 1 << (32 - __builtin_clz(x-1)); +#endif +} + + +#endif // _ENTITIES_TRANSMIT_H diff --git a/src/core/modules/entities/entities_transmit_wrap.cpp b/src/core/modules/entities/entities_transmit_wrap.cpp new file mode 100755 index 000000000..e1a405048 --- /dev/null +++ b/src/core/modules/entities/entities_transmit_wrap.cpp @@ -0,0 +1,142 @@ +/** +* ============================================================================= +* Source Python +* Copyright (C) 2012-2020 Source Python Development Team. 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, the Source Python Team gives you permission +* to link the code of this program (as well as its derivative works) to +* "Half-Life 2," the "Source Engine," 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, the Source.Python +* Development Team grants this exception to all derivative works. +*/ + +//----------------------------------------------------------------------------- +// Includes. +//----------------------------------------------------------------------------- +#include "export_main.h" +#include "utilities/wrap_macros.h" +#include "modules/entities/entities_transmit.h" +#include "modules/memory/memory_tools.h" + + +//----------------------------------------------------------------------------- +// Forward declarations. +//----------------------------------------------------------------------------- +static void export_transmit_manager(scope); + + +//----------------------------------------------------------------------------- +// Declare the _entities._transmit module. +//----------------------------------------------------------------------------- +DECLARE_SP_SUBMODULE(_entities, _transmit) +{ + export_transmit_manager(_transmit); +} + + +//----------------------------------------------------------------------------- +// Exports CTransmitManager. +//----------------------------------------------------------------------------- +void export_transmit_manager(scope _transmit) +{ + class_("TransmitManager", no_init) + + // Class methods + .def("hide", + &CTransmitManager::hide, + "Hide the entity from all players.", + ("entity_index") + ) + + .def("hide_from", + &CTransmitManager::hide_from, + "Hide the entity from player.", + ("entity_index", "player_index") + ) + + + .def("show", + &CTransmitManager::show, + "Show the entity to all players.", + ("entity_index") + ) + + .def("show_from", + &CTransmitManager::show_from, + "Show the entity to player.", + ("entity_index", "player_index") + ) + + + .def("reset", + &CTransmitManager::reset, + "Reset the entity's hidden/shown state.", + ("entity_index") + ) + + .def("reset_from", + &CTransmitManager::reset_from, + "Reset the player's entity hidden/shown state.", + ("entity_index", "player_index") + ) + + .def("reset_player", + &CTransmitManager::reset_player, + "Reset the player's hidden/shown state on all entities.", + ("player_index") + ) + + .def("reset_all", + &CTransmitManager::reset_all, + "Reset all entities' hidden/shown state." + ) + + + .def("is_hidden", + &CTransmitManager::is_hidden, + "Return True if the entity is hidden from any player.", + ("entity_index") + ) + + .def("is_hidden_from", + &CTransmitManager::is_hidden_from, + "Return True if the entity is hidden from the player.", + ("entity_index", "player_index") + ) + + + .def("get_hidden_player", + &CTransmitManager::get_hidden_player, + "Get the players where the entity is hidden.", + ("entity_index") + ) + + .def("get_hidden_entity", + &CTransmitManager::get_hidden_entity, + "Get the entities that are hidden from the player.", + ("player_index") + ) + + + // Add memory tools... + ADD_MEM_TOOLS(CTransmitManager) + ; + + // Singleton... + _transmit.attr("transmit_manager") = object(ptr(CTransmitManager::get_instance())); +} + diff --git a/src/core/sp_main.cpp b/src/core/sp_main.cpp index 6f1be1dcb..e68c599ce 100755 --- a/src/core/sp_main.cpp +++ b/src/core/sp_main.cpp @@ -61,6 +61,7 @@ #include "utilities/conversions.h" #include "modules/entities/entities_entity.h" #include "modules/core/core.h" +#include "modules/entities/entities_transmit.h" #ifdef _WIN32 #include "Windows.h" @@ -92,6 +93,7 @@ IEngineSound* enginesound = NULL; CGlobalVars* gpGlobals = NULL; IFileSystem* filesystem = NULL; IServerGameDLL* servergamedll = NULL; +IServerGameEnts* gameents = NULL; // Interface to get at server entities IServerGameClients* servergameclients = NULL; IServerTools* servertools = NULL; IPhysics* physics = NULL; @@ -154,6 +156,7 @@ InterfaceHelper_t gGameInterfaces[] = { {INTERFACEVERSION_PLAYERINFOMANAGER, (void **)&playerinfomanager}, {INTERFACEVERSION_PLAYERBOTMANAGER, (void **)&botmanager}, {INTERFACEVERSION_SERVERGAMEDLL, (void **)&servergamedll}, + {INTERFACEVERSION_SERVERGAMEENTS, (void **)&gameents}, {INTERFACEVERSION_SERVERGAMECLIENTS, (void **)&servergameclients}, {VSERVERTOOLS_INTERFACE_VERSION, (void **)&servertools}, {NULL, NULL} @@ -500,6 +503,9 @@ void CSourcePython::ClientActive( edict_t *pEntity ) if (!IndexFromEdict(pEntity, iEntityIndex)) return; + static CTransmitManager* transmit_manager = CTransmitManager::get_instance(); + transmit_manager->add_player(pEntity, iEntityIndex); + CALL_LISTENERS(OnClientActive, iEntityIndex); } @@ -513,6 +519,9 @@ void CSourcePython::ClientDisconnect( edict_t *pEntity ) return; CALL_LISTENERS(OnClientDisconnect, iEntityIndex); + + static CTransmitManager* transmit_manager = CTransmitManager::get_instance(); + transmit_manager->remove_player(pEntity, iEntityIndex); } //-----------------------------------------------------------------------------