[ Web Proxy ]
URL:
Viewing: https://raw.githubusercontent.com/srpg/Source.Python/master/src/core/sp_main.cpp [Back]  [Original]

/**
* =============================================================================
* Source Python
* Copyright (C) 2012-2015 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 "sp_python.h"
#include "sp_main.h"
#include "interface.h"
#include "filesystem.h"
#include "eiface.h"
#include "igameevents.h"
#include "convar.h"
#include "Color.h"
#include "vstdlib/random.h"
#include "engine/IEngineTrace.h"
#include "tier2/tier2.h"
#include "game/server/iplayerinfo.h"
#include "shake.h" // Linux compile fails without this.
#include "game/shared/IEffects.h"
#include "utilities/wrap_macros.h"
#include "engine/IEngineSound.h"
#include "engine/IEngineTrace.h"
#include "public/toolframework/itoolentity.h"
#include "dyncall.h"
#include "networkstringtabledefs.h"
#include "edict.h"
#include "convar.h"
#include "utilities/call_python.h"
#include "vphysics_interface.h"
#include "datacache/imdlcache.h"
#include "ivoiceserver.h"
#include "tier0/threadtools.h"

#include "manager.h"

#include "modules/listeners/listeners_manager.h"
#include "utilities/conversions.h"
#include "modules/entities/entities.h"
#include "modules/entities/entities_entity.h"
#include "modules/entities/entities_collisions.h"
#include "modules/entities/entities_transmit.h"
#include "modules/core/core.h"

#ifdef _WIN32
	#include "Windows.h"
#endif

#include "sp_hooks.h"

//-----------------------------------------------------------------------------
// Disable warnings.
//-----------------------------------------------------------------------------
#if defined(_WIN32)
#	 pragma warning( disable : 4005 )
#endif

// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"

//-----------------------------------------------------------------------------
// Interfaces from the engine
//-----------------------------------------------------------------------------
IVEngineServer*			engine				= NULL; // helper functions (messaging clients, loading content, making entities, running commands, etc)
IGameEventManager2*		gameeventmanager	= NULL; // game events interface
IPlayerInfoManager*		playerinfomanager	= NULL; // game dll interface to interact with players
IBotManager*			botmanager			= NULL; // game dll interface to interact with bots
IServerPluginHelpers*	helpers				= NULL; // special 3rd party plugin helpers from the engine
IUniformRandomStream*	randomStr			= NULL;
IEngineTrace*			enginetrace			= NULL;
IEngineSound*			enginesound			= NULL;
CGlobalVars*			gpGlobals			= NULL;
IFileSystem*			filesystem			= NULL;
IServerGameDLL*			servergamedll		= NULL;
IServerGameClients*		servergameclients	= NULL;
IServerTools*			servertools			= NULL;
IServerGameEnts*		gameents			= NULL; // Interface to get at server entities
IPhysics*				physics				= NULL;
IPhysicsCollision*		physcollision		= NULL;
IPhysicsSurfaceProps*	physprops			= NULL;
IMDLCache*				modelcache			= NULL;
IVoiceServer*			voiceserver			= NULL;
INetworkStringTableContainer* networkstringtable = NULL;

//-----------------------------------------------------------------------------
// External globals
//-----------------------------------------------------------------------------
extern ICvar* g_pCVar;

//-----------------------------------------------------------------------------
// Extern functions
//-----------------------------------------------------------------------------
extern void InitCommands();
extern void ClearAllCommands();
extern PLUGIN_RESULT DispatchClientCommand(edict_t *pEntity, const CCommand &command);
extern CConVarChangedListenerManager* GetOnConVarChangedListenerManager();
extern CServerOutputListenerManager* GetOnServerOutputListenerManager();

//-----------------------------------------------------------------------------
// The plugin is a static singleton that is exported as an interface
//-----------------------------------------------------------------------------
CSourcePython g_SourcePythonPlugin;
EXPOSE_SINGLE_INTERFACE_GLOBALVAR(CSourcePython, IServerPluginCallbacks, INTERFACEVERSION_ISERVERPLUGINCALLBACKS, g_SourcePythonPlugin );

//-----------------------------------------------------------------------------
// Interface helper class.
//-----------------------------------------------------------------------------
struct InterfaceHelper_t
{
	const char* szInterface;
	void**		pGlobal;
};

//-----------------------------------------------------------------------------
// We need all of these interfaces in order to function.
//-----------------------------------------------------------------------------
InterfaceHelper_t gEngineInterfaces[] = {
	{INTERFACEVERSION_VENGINESERVER, (void **)&engine},
	{INTERFACEVERSION_GAMEEVENTSMANAGER2, (void **)&gameeventmanager},
	{INTERFACEVERSION_ISERVERPLUGINHELPERS, (void **)&helpers},
	{INTERFACEVERSION_ENGINETRACE_SERVER, (void **)&enginetrace},
	{IENGINESOUND_SERVER_INTERFACE_VERSION, (void **)&enginesound},
	{VENGINE_SERVER_RANDOM_INTERFACE_VERSION, (void **)&randomStr},
	{FILESYSTEM_INTERFACE_VERSION, (void **)&filesystem},
	{INTERFACENAME_NETWORKSTRINGTABLESERVER, (void **)&networkstringtable},
	{VPHYSICS_INTERFACE_VERSION, (void **)&physics},
	{VPHYSICS_COLLISION_INTERFACE_VERSION, (void **)&physcollision},
	{VPHYSICS_SURFACEPROPS_INTERFACE_VERSION, (void **)&physprops},
	{MDLCACHE_INTERFACE_VERSION, (void **)&modelcache},
	{INTERFACEVERSION_VOICESERVER, (void **)&voiceserver},

	{NULL, NULL}
};

InterfaceHelper_t gGameInterfaces[] = {
	{INTERFACEVERSION_PLAYERINFOMANAGER, (void **)&playerinfomanager},
	{INTERFACEVERSION_PLAYERBOTMANAGER, (void **)&botmanager},
	{INTERFACEVERSION_SERVERGAMEDLL, (void **)&servergamedll},
	{INTERFACEVERSION_SERVERGAMECLIENTS, (void **)&servergameclients},
	{VSERVERTOOLS_INTERFACE_VERSION, (void **)&servertools},
	{INTERFACEVERSION_SERVERGAMEENTS, (void **)&gameents},
	{NULL, NULL}
};


//-----------------------------------------------------------------------------
// Get all engine interfaces.
//-----------------------------------------------------------------------------
bool GetInterfaces( InterfaceHelper_t* pInterfaceList, CreateInterfaceFn factory )
{
	InterfaceHelper_t* pInterface = pInterfaceList;
	while( pInterface->szInterface )
	{
		void** pGlobal = pInterface->pGlobal;

		// Get the interface from the given factory.
		*pGlobal = factory(pInterface->szInterface, NULL);

		// If it's not valid, bail out.
		if( *pGlobal ) {
			DevMsg(1, MSG_PREFIX "Interface %s at %x\n", pInterface->szInterface, *pGlobal);
		} else {
			Warning(MSG_PREFIX "Could not retrieve interface %s\n", pInterface->szInterface);
			return false;
		}

		pInterface++;
	}

	return true;
}


//-----------------------------------------------------------------------------
// Purpose: constructor/destructor
//-----------------------------------------------------------------------------
CSourcePython::CSourcePython()
{
	m_iClientCommandIndex = 0;
	m_pOldMDLCacheNotifier = NULL;
}

CSourcePython::~CSourcePython()
{
}

//-----------------------------------------------------------------------------
// Purpose: called when the plugin is loaded, load the interface we need from the engine
//-----------------------------------------------------------------------------
bool CSourcePython::Load(	CreateInterfaceFn interfaceFactory, CreateInterfaceFn gameServerFactory )
{
#if defined(ENGINE_CSGO) || defined(ENGINE_BLADE)
	DevMsg(1, MSG_PREFIX "Connecting interfaces...\n");
	ConnectInterfaces(&interfaceFactory, 1);
#else
	DevMsg(1, MSG_PREFIX "Connecting tier1 libraries...\n");
	ConnectTier1Libraries( &interfaceFactory, 1 );

	DevMsg(1, MSG_PREFIX "Connecting tier2 libraries...\n");
	ConnectTier2Libraries( &interfaceFactory, 2 );
#endif

	// Get all engine interfaces.
	DevMsg(1, MSG_PREFIX "Retrieving engine interfaces...\n");
	if( !GetInterfaces(gEngineInterfaces, interfaceFactory) ) {
		return false;
	}

	// Get all game interfaces.
	DevMsg(1, MSG_PREFIX "Retrieving game interfaces...\n");
	if( !GetInterfaces(gGameInterfaces, gameServerFactory) ) {
		return false;
	}
	
	DevMsg(1, MSG_PREFIX "Retrieving global variables...\n");
	gpGlobals = playerinfomanager->GetGlobalVars();
	if (!gpGlobals) {
		Msg(MSG_PREFIX "Could retrieve global variables.\n");
		return false;
	}
	
	DevMsg(1, MSG_PREFIX "Initializing mathlib...\n");
	MathLib_Init( 2.2f, 2.2f, 0.0f, 2.0f );

	DevMsg(1, MSG_PREFIX "Initializing server and say commands...\n");
	InitCommands();

	// Initialize python
	DevMsg(1, MSG_PREFIX "Initializing python...\n");
	if( !g_PythonManager.Initialize() ) {
		Msg(MSG_PREFIX "Could not initialize python.\n");
		return false;
	}

	// TODO: Don't hardcode the 64 bytes offset
#ifdef ENGINE_LEFT4DEAD2
	#define CACHE_NOTIFY_OFFSET 68
#else
	#define CACHE_NOTIFY_OFFSET 64
#endif

	DevMsg(1, MSG_PREFIX "Retrieving the current cache notifier...\n");
	m_pOldMDLCacheNotifier = *(IMDLCacheNotify **)(((unsigned long) modelcache) + CACHE_NOTIFY_OFFSET);

	DevMsg(1, MSG_PREFIX "Setting the new cache notifier...\n");
	modelcache->SetCacheNotify(this);

	g_EntityHooks.push_back(new PlayerHook(
		"run_command",
		(HookHandlerFn*) (void*) &PrePlayerRunCommand,
		HOOKTYPE_PRE));

	g_EntityHooks.push_back(new PlayerHook(
		"run_command",
		(HookHandlerFn*) (void*) &PrePlayerRunCommand,
		HOOKTYPE_POST));

	InitHooks();
	
	Msg(MSG_PREFIX "Loaded successfully.\n");
	return true;
}

//-----------------------------------------------------------------------------
// Purpose: called when the plugin is unloaded (turned off)
//-----------------------------------------------------------------------------
void CSourcePython::Unload( void )
{
	Msg(MSG_PREFIX "Unloading...\n");

	DevMsg(1, MSG_PREFIX "Resetting cache notifier...\n");
	modelcache->SetCacheNotify(m_pOldMDLCacheNotifier);

	DevMsg(1, MSG_PREFIX "Shutting down python...\n");
	g_PythonManager.Shutdown();

	DevMsg(1, MSG_PREFIX "Clearing convar changed listener...\n");
	GetOnConVarChangedListenerManager()->clear();

	DevMsg(1, MSG_PREFIX "Clearing server output listeners...\n");
	GetOnServerOutputListenerManager()->clear();

	DevMsg(1, MSG_PREFIX "Unhooking all functions...\n");
	GetHookManager()->UnhookAllFunctions();

	DevMsg(1, MSG_PREFIX "Clearing all commands...\n");
	ClearAllCommands();

	DevMsg(1, MSG_PREFIX "Unregistering ConVar...\n");
	ConVar_Unregister( );

	// New in CSGO...
#if defined(ENGINE_CSGO) || defined(ENGINE_BLADE)
	DevMsg(1, MSG_PREFIX "Disconnecting interfaces...\n");
	DisconnectInterfaces();
#else
	DevMsg(1, MSG_PREFIX "Disconnecting tier2 libraries...\n");
	DisconnectTier2Libraries( );

	DevMsg(1, MSG_PREFIX "Disconnecting tier1 libraries...\n");
	DisconnectTier1Libraries( );
#endif

	Msg(MSG_PREFIX "Unloaded successfully.\n");

#ifdef _WIN32
	// This "fixes" a crash after SP has been unloaded.
	Sleep(1000);
#endif
}

//-----------------------------------------------------------------------------
// Purpose: called when the plugin is paused (i.e should stop running but isn't unloaded)
//-----------------------------------------------------------------------------
void CSourcePython::Pause( void )
{
}

//-----------------------------------------------------------------------------
// Purpose: called when the plugin is unpaused (i.e should start executing again)
//-----------------------------------------------------------------------------
void CSourcePython::UnPause( void )
{
}

//-----------------------------------------------------------------------------
// Purpose: the name of this plugin, returned in "plugin_print" command
//-----------------------------------------------------------------------------
const char *CSourcePython::GetPluginDescription( void )
{
	return "Source.Python, (C) 2012-2021, Source.Python Team.";
}

//-----------------------------------------------------------------------------
// Purpose: called on level start
//-----------------------------------------------------------------------------
void CSourcePython::LevelInit( char const *pMapName )
{
	CALL_LISTENERS(OnLevelInit, pMapName);
}

//-----------------------------------------------------------------------------
// Purpose: called on level start, when the server is ready to accept client connections
//		edictCount is the number of entities in the level, clientMax is the max client count
//-----------------------------------------------------------------------------
void CSourcePython::ServerActivate( edict_t *pEdictList, int edictCount, int clientMax )
{
	list edicts;
	for(int i=0; i < edictCount; i++)
		edicts.append(pEdictList[i]);
	
	CALL_LISTENERS(OnServerActivate, edicts, edictCount, clientMax);
}

//-----------------------------------------------------------------------------
// Purpose: called once per server frame, do recurring work here (like checking for timeouts)
//-----------------------------------------------------------------------------
void CSourcePython::GameFrame( bool simulating )
{
	CALL_LISTENERS(OnTick);
}

//-----------------------------------------------------------------------------
// Purpose: called on level end (as the server is shutting down or going to a new map)
//-----------------------------------------------------------------------------
void CSourcePython::LevelShutdown( void ) // !!!!this can get called multiple times per map change
{
	CALL_LISTENERS(OnLevelShutdown);

	// Cleanup active collision rules.
	static CCollisionManager *pCollisionManager = GetCollisionManager();
	pCollisionManager->OnLevelShutdown();

	// Cleanup active transmission rules.
	static CTransmitManager *pTransmitManager = GetTransmitManager();
	pTransmitManager->OnLevelShutdown();
}

//-----------------------------------------------------------------------------
// Purpose: called when a client spawns into a server (i.e as they begin to play)
//-----------------------------------------------------------------------------
void CSourcePython::ClientActive( edict_t *pEntity )
{
	unsigned int iEntityIndex;
	if (!IndexFromEdict(pEntity, iEntityIndex))
		return;

	CALL_LISTENERS(OnClientActive, iEntityIndex);
}

//-----------------------------------------------------------------------------
// Purpose: called when a client leaves a server (or is timed out)
//-----------------------------------------------------------------------------
void CSourcePython::ClientDisconnect( edict_t *pEntity )
{
	unsigned int iEntityIndex;
	if (!IndexFromEdict(pEntity, iEntityIndex))
		return;

	CALL_LISTENERS(OnClientDisconnect, iEntityIndex);
}

//-----------------------------------------------------------------------------
// Purpose: called on
//-----------------------------------------------------------------------------
void CSourcePython::ClientPutInServer( edict_t *pEntity, char const *playername )
{
	CALL_LISTENERS(OnClientPutInServer, ptr(pEntity), playername);
}

//-----------------------------------------------------------------------------
// Purpose: called on level start
//-----------------------------------------------------------------------------
void CSourcePython::SetCommandClient( int index )
{
	m_iClientCommandIndex = index;
}

//-----------------------------------------------------------------------------
// Purpose: called on level start
//-----------------------------------------------------------------------------
void CSourcePython::ClientSettingsChanged( edict_t *pEdict )
{
	unsigned int iEntityIndex;
	if (!IndexFromEdict(pEdict, iEntityIndex))
		return;

	CALL_LISTENERS(OnClientSettingsChanged, iEntityIndex);
}

//-----------------------------------------------------------------------------
// Purpose: called when a client joins a server
//-----------------------------------------------------------------------------
PLUGIN_RESULT CSourcePython::ClientConnect( bool *bAllowConnect, edict_t *pEntity, const char *pszName, const char *pszAddress, char *reject, int maxrejectlen )
{
	CPointer allowConnect = CPointer((unsigned long) bAllowConnect);
	CPointer rejectMessage = CPointer((unsigned long) reject);
	CALL_LISTENERS(OnClientConnect, allowConnect, ptr(pEntity), pszName, pszAddress, rejectMessage, maxrejectlen);
	return PLUGIN_OVERRIDE;
}

//-----------------------------------------------------------------------------
// Purpose: called when a client is authenticated
//-----------------------------------------------------------------------------
PLUGIN_RESULT CSourcePython::NetworkIDValidated( const char *pszUserName, const char *pszNetworkID )
{
	CALL_LISTENERS(OnNetworkidValidated, pszUserName, pszNetworkID);
	return PLUGIN_CONTINUE;
}

//-----------------------------------------------------------------------------
// Purpose: called when a cvar value query is finished
//-----------------------------------------------------------------------------
void CSourcePython::OnQueryCvarValueFinished( QueryCvarCookie_t iCookie, edict_t *pPlayerEntity,
	EQueryCvarValueStatus eStatus, const char *pCvarName, const char *pCvarValue )
{
	PythonLog(4, "Cvar query (cookie: %d, status: %d) - name: %s, value: %s", iCookie, eStatus, pCvarName, pCvarValue );
	unsigned int iEntityIndex;
	if (!IndexFromEdict(pPlayerEntity, iEntityIndex))
		return;

	CALL_LISTENERS(OnQueryCvarValueFinished, (int) iCookie, iEntityIndex, eStatus, pCvarName, pCvarValue);
}

//-----------------------------------------------------------------------------
// Orangebox.
//-----------------------------------------------------------------------------
PLUGIN_RESULT CSourcePython::ClientCommand( edict_t *pEntity, const CCommand &args )
{
	return DispatchClientCommand(pEntity, args);
}

//-----------------------------------------------------------------------------
// Alien Swarm.
//-----------------------------------------------------------------------------
#if defined(ENGINE_CSGO) || defined(ENGINE_BLADE)
void CSourcePython::ClientFullyConnect( edict_t *pEntity )
{
	unsigned int iEntityIndex;
	if (!IndexFromEdict(pEntity, iEntityIndex))
		return;

	CALL_LISTENERS(OnClientFullyConnect, iEntityIndex);
}
#endif

#if defined(ENGINE_CSGO) || defined(ENGINE_BMS) || defined(ENGINE_BLADE)
void CSourcePython::OnEdictAllocated( edict_t *edict )
{
	unsigned int iEntityIndex;
	if (!IndexFromEdict(edict, iEntityIndex))
		return;

	CALL_LISTENERS(OnEdictAllocated, iEntityIndex);
}

void CSourcePython::OnEdictFreed( const edict_t *edict )
{
	CALL_LISTENERS(OnEdictFreed, ptr(edict));
}
#endif

#ifdef ENGINE_BMS
void CSourcePython::OnEntityPreSpawned( CBaseEntity *pEntity )
{
	CALL_LISTENERS(OnEntityPreSpawned, ptr((CBaseEntityWrapper*) pEntity));

	GET_LISTENER_MANAGER(OnNetworkedEntityPreSpawned, on_networked_entity_pre_spawned_manager);
	if (!on_networked_entity_pre_spawned_manager->GetCount())
		return;

	unsigned int uiIndex;
	if (!IndexFromBaseEntity(pEntity, uiIndex))
		return;

	static object Entity = import("entities").attr("entity").attr("Entity");
	CALL_LISTENERS_WITH_MNGR(on_networked_entity_pre_spawned_manager, Entity(uiIndex));
}
#endif

void CSourcePython::OnEntityCreated( CBaseEntity *pEntity )
{
	edict_t *pEdict;
	if (EdictFromBaseEntity(pEntity, pEdict)) {
		IServerUnknown* pServerUnknown = pEdict->GetUnknown();
		if (pServerUnknown)
			pEdict->m_pNetworkable = pServerUnknown->GetNetworkable();
	}

	InitHooks(pEntity);

	CALL_LISTENERS(OnEntityCreated, ptr((CBaseEntityWrapper*) pEntity));

	unsigned int uiIndex;
	if (!IndexFromBaseEntity(pEntity, uiIndex))
		return;

	static object Entity = import("entities").attr("entity").attr("Entity");
	object oEntity = Entity(uiIndex);
	
	GET_LISTENER_MANAGER(OnNetworkedEntityCreated, on_networked_entity_created_manager);
	if (on_networked_entity_created_manager->GetCount()) {
		CALL_LISTENERS_WITH_MNGR(on_networked_entity_created_manager, oEntity);
	}

	static CCollisionManager *pCollisionManager = GetCollisionManager();
	pCollisionManager->OnNetworkedEntityCreated(oEntity);
}

void CSourcePython::OnEntitySpawned( CBaseEntity *pEntity )
{
	CALL_LISTENERS(OnEntitySpawned, ptr((CBaseEntityWrapper*) pEntity));

	GET_LISTENER_MANAGER(OnNetworkedEntitySpawned, on_networked_entity_spawned_manager);
	if (!on_networked_entity_spawned_manager->GetCount())
		return;

	unsigned int uiIndex;
	if (!IndexFromBaseEntity(pEntity, uiIndex))
		return;

	static object Entity = import("entities").attr("entity").attr("Entity");
	CALL_LISTENERS_WITH_MNGR(on_networked_entity_spawned_manager, Entity(uiIndex));
}

void CSourcePython::OnEntityDeleted( CBaseEntity *pEntity )
{
	// #455 - Temporarily rebind ourself to our edict if needed.
	bool bRebound = false;
	edict_t *pEdict;
	if (EdictFromBaseEntity(pEntity, pEdict) && !pEdict->GetUnknown()) {
		reinterpret_cast(pEdict)->SetUnknown((IServerUnknown *)pEntity);
		bRebound = true;
	}

	CALL_LISTENERS(OnEntityDeleted, ptr((CBaseEntityWrapper*) pEntity));

	unsigned int uiIndex;
	if (!IndexFromBaseEntity(pEntity, uiIndex))
		return;

	GET_LISTENER_MANAGER(OnNetworkedEntityDeleted, on_networked_entity_deleted_manager);
	if (on_networked_entity_deleted_manager->GetCount())
	{
		static object Entity = import("entities").attr("entity").attr("Entity");
		CALL_LISTENERS_WITH_MNGR(on_networked_entity_deleted_manager, Entity(uiIndex));
	}

	// Invalidate the internal entity cache once all callbacks have been called.
	static object _on_networked_entity_deleted = import("entities").attr("_base").attr("_on_networked_entity_deleted");
	_on_networked_entity_deleted(uiIndex);

	// Cleanup active collision rules.
	static CCollisionManager *pCollisionManager = GetCollisionManager();
	pCollisionManager->OnNetworkedEntityDeleted((CBaseEntityWrapper *)pEntity);

	// Cleanup active transmission rules.
	static CTransmitManager *pTransmitManager = GetTransmitManager();
	pTransmitManager->OnNetworkedEntityDeleted((CBaseEntityWrapper *)pEntity, uiIndex);

	if (bRebound) {
		reinterpret_cast(pEdict)->SetUnknown(NULL);
	}
}

void CSourcePython::OnDataLoaded( MDLCacheDataType_t type, MDLHandle_t handle )
{
	if (m_pOldMDLCacheNotifier)
		m_pOldMDLCacheNotifier->OnDataLoaded(type, handle);

	CALL_LISTENERS(OnDataLoaded, type, handle);
}

void CSourcePython::OnDataUnloaded( MDLCacheDataType_t type, MDLHandle_t handle )
{
	if (m_pOldMDLCacheNotifier)
		m_pOldMDLCacheNotifier->OnDataUnloaded(type, handle);

	CALL_LISTENERS(OnDataUnloaded, type, handle);
}
	
#if defined(ENGINE_CSGO) || defined(ENGINE_BLADE)
void CSourcePython::OnCombinerPreCache(MDLCacheDataType_t type, MDLHandle_t handle )
{
	if (m_pOldMDLCacheNotifier)
		m_pOldMDLCacheNotifier->OnCombinerPreCache(type, handle);

	CALL_LISTENERS(OnCombinerPreCache, type, handle);
}

bool CSourcePython::ShouldSupressLoadWarning(MDLHandle_t handle)
{
	bool result = false;
	if (m_pOldMDLCacheNotifier)
		result = m_pOldMDLCacheNotifier->ShouldSupressLoadWarning(handle);

	return result;
}

bool CSourcePython::BNetworkCryptKeyCheckRequired( uint32 unFromIP, uint16 usFromPort,
	uint32 unAccountIdProvidedByClient, bool bClientWantsToUseCryptKey )
{
	return false;
}

bool CSourcePython::BNetworkCryptKeyValidate( uint32 unFromIP, uint16 usFromPort, uint32 unAccountIdProvidedByClient,
	int nEncryptionKeyIndexFromClient, int numEncryptedBytesFromClient, byte *pbEncryptedBufferFromClient,
	byte *pbPlainTextKeyForNetchan )
{
	return false;
}
#endif

Web Proxy Viewer  |  New URL  |  Original Page