ds@783: /** ds@783: * vim: set ts=4 : ds@1330: * ============================================================================= dvander@1233: * SourceMod SDKTools Extension fyrenmoo@3089: * Copyright (C) 2004-2010 AlliedModders LLC. All rights reserved. ds@1330: * ============================================================================= ds@783: * ds@1330: * This program is free software; you can redistribute it and/or modify it under ds@1330: * the terms of the GNU General Public License, version 3.0, as published by the ds@1330: * Free Software Foundation. dvander@1233: * ds@1330: * This program is distributed in the hope that it will be useful, but WITHOUT ds@1330: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS ds@1330: * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more ds@1330: * details. dvander@1233: * ds@1330: * You should have received a copy of the GNU General Public License along with ds@1330: * this program. If not, see . dvander@1233: * ds@1330: * As a special exception, AlliedModders LLC gives you permission to link the ds@1330: * code of this program (as well as its derivative works) to "Half-Life 2," the ds@1330: * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software ds@1330: * by the Valve Corporation. You must obey the GNU General Public License in ds@1330: * all respects for all other code used. Additionally, AlliedModders LLC grants ds@1330: * this exception to all derivative works. AlliedModders LLC defines further ds@1330: * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), ds@1330: * or . ds@783: * ds@783: * Version: $Id$ ds@783: */ ds@783: dvander@2783: #include ds@783: #include "extension.h" ds@2400: #include dvander@950: #include "vcallbuilder.h" dvander@954: #include "vnatives.h" dvander@1169: #include "vhelpers.h" ds@1240: #include "vglobals.h" faluco@1031: #include "tempents.h" faluco@1735: #include "vsound.h" pred@1958: #include "output.h" pred@2711: #include "hooks.h" skamonkey@3333: #include "gamerulesnatives.h" dvander@2503: #include bluebriansimon@3339: #include "clientnatives.h" ds@783: /** ds@783: * @file extension.cpp ds@995: * @brief Implements SDK Tools extension code. ds@783: */ ds@783: faluco@1262: SH_DECL_HOOK6(IServerGameDLL, LevelInit, SH_NOATTRIB, false, bool, const char *, const char *, const char *, const char *, bool, bool); faluco@1262: ds@783: SDKTools g_SdkTools; /**< Global singleton for extension's main interface */ ds@783: IServerGameEnts *gameents = NULL; faluco@1075: IEngineTrace *enginetrace = NULL; ds@1114: IEngineSound *engsound = NULL; ds@1114: INetworkStringTableContainer *netstringtables = NULL; dvander@1169: IServerPluginHelpers *pluginhelpers = NULL; ds@783: IBinTools *g_pBinTools = NULL; dvander@950: IGameConfig *g_pGameConf = NULL; faluco@1031: IGameHelpers *g_pGameHelpers = NULL; faluco@1219: IServerGameClients *serverClients = NULL; ds@1240: IVoiceServer *voiceserver = NULL; teame06@1239: IPlayerInfoManager *playerinfomngr = NULL; faluco@1560: ICvar *icvar = NULL; faluco@1769: IServer *iserver = NULL; ds@2400: CGlobalVars *gpGlobals; skamonkey@3280: skamonkey@3280: #if SOURCE_ENGINE >= SE_ORANGEBOX skamonkey@3280: IServerTools *servertools = NULL; skamonkey@3280: #endif skamonkey@3280: faluco@1735: SourceHook::CallClass *enginePatch = NULL; faluco@1735: SourceHook::CallClass *enginesoundPatch = NULL; dvander@950: HandleType_t g_CallHandle = 0; faluco@1075: HandleType_t g_TraceHandle = 0; dvander@2503: ISDKTools *g_pSDKTools; ds@783: ds@783: SMEXT_LINK(&g_SdkTools); ds@783: dvander@950: extern sp_nativeinfo_t g_CallNatives[]; faluco@1031: extern sp_nativeinfo_t g_TENatives[]; faluco@1075: extern sp_nativeinfo_t g_TRNatives[]; ds@1114: extern sp_nativeinfo_t g_StringTableNatives[]; teame06@1235: extern sp_nativeinfo_t g_VoiceNatives[]; faluco@1498: extern sp_nativeinfo_t g_EntInputNatives[]; faluco@1613: extern sp_nativeinfo_t g_TeamNatives[]; skamonkey@3333: extern sp_nativeinfo_t g_GameRulesNatives[]; bluebriansimon@3339: extern sp_nativeinfo_t g_ClientNatives[]; dvander@950: dvander@2503: static void InitSDKToolsAPI(); dvander@2503: ds@783: bool SDKTools::SDK_OnLoad(char *error, size_t maxlength, bool late) ds@783: { dvander@2306: HandleError err; dvander@2306: dvander@2529: if (!gameconfs->LoadGameConfigFile("sdktools.games", &g_pGameConf, error, maxlength)) pred@2124: { pred@2124: return false; pred@2124: } pred@2124: dvander@950: sharesys->AddDependency(myself, "bintools.ext", true, true); dvander@950: sharesys->AddNatives(myself, g_CallNatives); dvander@954: sharesys->AddNatives(myself, g_Natives); faluco@1031: sharesys->AddNatives(myself, g_TENatives); dvander@1047: sharesys->AddNatives(myself, g_SoundNatives); faluco@1075: sharesys->AddNatives(myself, g_TRNatives); ds@1114: sharesys->AddNatives(myself, g_StringTableNatives); teame06@1235: sharesys->AddNatives(myself, g_VoiceNatives); faluco@1498: sharesys->AddNatives(myself, g_EntInputNatives); faluco@1613: sharesys->AddNatives(myself, g_TeamNatives); pred@1958: sharesys->AddNatives(myself, g_EntOutputNatives); skamonkey@3333: sharesys->AddNatives(myself, g_GameRulesNatives); bluebriansimon@3339: sharesys->AddNatives(myself, g_ClientNatives); faluco@1031: faluco@1031: SM_GET_IFACE(GAMEHELPERS, g_pGameHelpers); ds@783: teame06@1235: playerhelpers->AddClientListener(&g_SdkTools); dvander@2306: g_CallHandle = handlesys->CreateType("ValveCall", this, 0, NULL, NULL, myself->GetIdentity(), &err); dvander@2306: if (g_CallHandle == 0) dvander@2306: { dvander@2306: snprintf(error, maxlength, "Could not create call handle type (err: %d)", err); dvander@2306: return false; dvander@2306: } pred@2108: pred@2108: TypeAccess TraceAccess; pred@2108: handlesys->InitAccessDefaults(&TraceAccess, NULL); pred@2116: TraceAccess.ident = myself->GetIdentity(); pred@2108: TraceAccess.access[HTypeAccess_Create] = true; pred@2116: TraceAccess.access[HTypeAccess_Inherit] = true; dvander@2306: g_TraceHandle = handlesys->CreateType("TraceRay", this, 0, &TraceAccess, NULL, myself->GetIdentity(), &err); dvander@2306: if (g_TraceHandle == 0) dvander@2306: { dvander@2306: handlesys->RemoveType(g_CallHandle, myself->GetIdentity()); dvander@2306: g_CallHandle = 0; dvander@2306: snprintf(error, maxlength, "Could not create traceray handle type (err: %d)", err); dvander@2306: return false; dvander@2306: } ds@783: ds@2400: #if SOURCE_ENGINE >= SE_ORANGEBOX faluco@1560: g_pCVar = icvar; faluco@1560: #endif faluco@1560: CONVAR_REGISTER(this); dvander@1052: faluco@1262: SH_ADD_HOOK_MEMFUNC(IServerGameDLL, LevelInit, gamedll, this, &SDKTools::LevelInit, true); faluco@1262: dvander@1628: playerhelpers->RegisterCommandTargetProcessor(this); dvander@1628: dvander@1611: MathLib_Init(2.2f, 2.2f, 0.0f, 2); dvander@1611: pred@1958: spengine = g_pSM->GetScriptingEngine(); pred@1958: pred@1958: plsys->AddPluginsListener(&g_OutputManager); pred@1958: fyrenmoo@3089: CDetourManager::Init(g_pSM->GetScriptingEngine(), g_pGameConf); pred@1958: g_OutputManager.Init(); pred@1958: dvander@2044: VoiceInit(); dvander@2044: dvander@2503: GetIServer(); dvander@2503: skamonkey@3333: GameRulesNativesInit(); skamonkey@3333: dvander@2503: InitSDKToolsAPI(); dvander@2503: ds@783: return true; ds@783: } ds@783: dvander@950: void SDKTools::OnHandleDestroy(HandleType_t type, void *object) dvander@950: { dvander@950: if (type == g_CallHandle) dvander@950: { dvander@950: ValveCall *v = (ValveCall *)object; dvander@950: delete v; dvander@1628: } dvander@1628: else if (type == g_TraceHandle) dvander@1628: { faluco@1075: trace_t *tr = (trace_t *)object; faluco@1075: delete tr; faluco@1075: } dvander@950: } dvander@950: dvander@950: void SDKTools::SDK_OnUnload() dvander@950: { faluco@1560: SourceHook::List::iterator iter; dvander@954: for (iter = g_RegCalls.begin(); dvander@954: iter != g_RegCalls.end(); dvander@954: iter++) dvander@954: { dvander@954: delete (*iter); dvander@954: } dvander@954: g_RegCalls.clear(); dvander@1169: ShutdownHelpers(); dvander@954: faluco@1498: if (g_pAcceptInput) faluco@1498: { faluco@1498: g_pAcceptInput->Destroy(); faluco@1498: g_pAcceptInput = NULL; faluco@1498: } faluco@1498: faluco@1031: g_TEManager.Shutdown(); faluco@1255: s_TempEntHooks.Shutdown(); faluco@1735: s_SoundHooks.Shutdown(); pred@2711: g_Hooks.Shutdown(); dvander@3414: g_OutputManager.Shutdown(); faluco@1031: dvander@950: gameconfs->CloseGameConfigFile(g_pGameConf); teame06@1235: playerhelpers->RemoveClientListener(&g_SdkTools); dvander@1628: playerhelpers->UnregisterCommandTargetProcessor(this); dvander@2060: plsys->RemovePluginsListener(&g_OutputManager); faluco@1262: faluco@1262: SH_REMOVE_HOOK_MEMFUNC(IServerGameDLL, LevelInit, gamedll, this, &SDKTools::LevelInit, true); faluco@1735: faluco@1735: if (enginePatch) faluco@1735: { faluco@1735: SH_RELEASE_CALLCLASS(enginePatch); faluco@1735: enginePatch = NULL; faluco@1735: } faluco@1735: if (enginesoundPatch) faluco@1735: { faluco@1735: SH_RELEASE_CALLCLASS(enginesoundPatch); faluco@1735: enginesoundPatch = NULL; faluco@1735: } dvander@2306: dvander@2306: bool err; dvander@2306: if (g_CallHandle != 0) dvander@2306: { dvander@2306: if ((err = handlesys->RemoveType(g_CallHandle, myself->GetIdentity())) != true) dvander@2306: { dvander@2306: g_pSM->LogError(myself, "Could not remove call handle (type=%x, err=%d)", g_CallHandle, err); dvander@2306: } dvander@2306: } dvander@2306: dvander@2306: if (g_TraceHandle != 0) dvander@2306: { dvander@2306: if ((err = handlesys->RemoveType(g_TraceHandle, myself->GetIdentity())) != true) dvander@2306: { dvander@2306: g_pSM->LogError(myself, "Could not remove trace handle (type=%x, err=%d)", g_TraceHandle, err); dvander@2306: } dvander@2306: } dvander@950: } dvander@950: ds@783: bool SDKTools::SDK_OnMetamodLoad(ISmmAPI *ismm, char *error, size_t maxlen, bool late) ds@783: { faluco@1560: GET_V_IFACE_ANY(GetServerFactory, gameents, IServerGameEnts, INTERFACEVERSION_SERVERGAMEENTS); faluco@1560: GET_V_IFACE_ANY(GetEngineFactory, engsound, IEngineSound, IENGINESOUND_SERVER_INTERFACE_VERSION); faluco@1560: GET_V_IFACE_ANY(GetEngineFactory, enginetrace, IEngineTrace, INTERFACEVERSION_ENGINETRACE_SERVER); faluco@1560: GET_V_IFACE_ANY(GetEngineFactory, netstringtables, INetworkStringTableContainer, INTERFACENAME_NETWORKSTRINGTABLESERVER); faluco@1560: GET_V_IFACE_ANY(GetEngineFactory, pluginhelpers, IServerPluginHelpers, INTERFACEVERSION_ISERVERPLUGINHELPERS); faluco@1560: GET_V_IFACE_ANY(GetServerFactory, serverClients, IServerGameClients, INTERFACEVERSION_SERVERGAMECLIENTS); faluco@1560: GET_V_IFACE_ANY(GetEngineFactory, voiceserver, IVoiceServer, INTERFACEVERSION_VOICESERVER); faluco@1560: GET_V_IFACE_ANY(GetServerFactory, playerinfomngr, IPlayerInfoManager, INTERFACEVERSION_PLAYERINFOMANAGER); faluco@1560: GET_V_IFACE_CURRENT(GetEngineFactory, icvar, ICvar, CVAR_INTERFACE_VERSION); ds@783: skamonkey@3280: #if SOURCE_ENGINE >= SE_ORANGEBOX skamonkey@3280: GET_V_IFACE_ANY(GetServerFactory, servertools, IServerTools, VSERVERTOOLS_INTERFACE_VERSION); skamonkey@3280: #endif skamonkey@3280: ds@2400: gpGlobals = ismm->GetCGlobals(); faluco@1735: enginePatch = SH_GET_CALLCLASS(engine); faluco@1735: enginesoundPatch = SH_GET_CALLCLASS(engsound); faluco@1735: ds@783: return true; ds@783: } ds@783: ds@783: void SDKTools::SDK_OnAllLoaded() ds@783: { ds@783: SM_GET_LATE_IFACE(BINTOOLS, g_pBinTools); ds@1065: dvander@1757: if (!g_pBinTools) dvander@1757: { dvander@1757: return; dvander@1757: } dvander@1757: faluco@1031: g_TEManager.Initialize(); faluco@1255: s_TempEntHooks.Initialize(); faluco@1735: s_SoundHooks.Initialize(); pred@2711: g_Hooks.Initialize(); ds@1240: InitializeValveGlobals(); ds@783: } ds@783: ds@783: bool SDKTools::QueryRunning(char *error, size_t maxlength) ds@783: { ds@783: SM_CHECK_IFACE(BINTOOLS, g_pBinTools); ds@783: ds@783: return true; ds@783: } dvander@1023: dvander@1023: bool SDKTools::QueryInterfaceDrop(SMInterface *pInterface) dvander@1023: { dvander@1023: if (pInterface == g_pBinTools) dvander@1023: { dvander@1023: return false; dvander@1023: } dvander@1023: dvander@1023: return IExtensionInterface::QueryInterfaceDrop(pInterface); dvander@1023: } dvander@1023: dvander@1023: void SDKTools::NotifyInterfaceDrop(SMInterface *pInterface) dvander@1023: { faluco@1560: SourceHook::List::iterator iter; dvander@1023: for (iter = g_RegCalls.begin(); dvander@1023: iter != g_RegCalls.end(); dvander@1023: iter++) dvander@1023: { dvander@1023: delete (*iter); dvander@1023: } dvander@1023: g_RegCalls.clear(); dvander@1169: ShutdownHelpers(); dvander@1023: faluco@1031: g_TEManager.Shutdown(); faluco@1255: s_TempEntHooks.Shutdown(); faluco@1498: faluco@1498: if (g_pAcceptInput) faluco@1498: { faluco@1498: g_pAcceptInput->Destroy(); faluco@1498: g_pAcceptInput = NULL; faluco@1498: } dvander@1023: } dvander@1052: dvander@1052: bool SDKTools::RegisterConCommandBase(ConCommandBase *pVar) dvander@1052: { faluco@1560: #if defined METAMOD_PLAPI_VERSION faluco@1560: return g_SMAPI->RegisterConCommandBase(g_PLAPI, pVar); faluco@1560: #else dvander@1052: return g_SMAPI->RegisterConCmdBase(g_PLAPI, pVar); faluco@1560: #endif dvander@1052: } faluco@1262: faluco@1262: bool SDKTools::LevelInit(char const *pMapName, char const *pMapEntities, char const *pOldLevel, char const *pLandmarkName, bool loadGame, bool background) faluco@1262: { faluco@1262: const char *name; faluco@1262: char key[32]; faluco@1262: int count, n = 1; faluco@1262: faluco@1262: if (!(name=g_pGameConf->GetKeyValue("SlapSoundCount"))) faluco@1262: { faluco@1262: RETURN_META_VALUE(MRES_IGNORED, true); faluco@1262: } faluco@1262: faluco@1262: count = atoi(name); faluco@1262: faluco@1262: while (n <= count) faluco@1262: { faluco@1262: snprintf(key, sizeof(key), "SlapSound%d", n); faluco@1262: if ((name=g_pGameConf->GetKeyValue(key))) faluco@1262: { faluco@1262: engsound->PrecacheSound(name, true); faluco@1262: } faluco@1262: n++; faluco@1262: } faluco@1262: faluco@1262: RETURN_META_VALUE(MRES_IGNORED, true); faluco@1262: } dvander@1628: dvander@1628: bool SDKTools::ProcessCommandTarget(cmd_target_info_t *info) dvander@1628: { dvander@1628: IGamePlayer *pAdmin = info->admin ? playerhelpers->GetGamePlayer(info->admin) : NULL; dvander@1628: dvander@2838: if (strcmp(info->pattern, "@aim") == 0) dvander@1628: { dvander@2838: /* The server can't aim, of course. */ dvander@2838: if (pAdmin == NULL) dvander@2838: { dvander@2838: return false; dvander@2838: } dvander@2838: dvander@2838: int player_index; dvander@2838: if ((player_index = GetClientAimTarget(pAdmin->GetEdict(), true)) < 1) dvander@2838: { dvander@2838: info->reason = COMMAND_TARGET_NONE; dvander@2838: info->num_targets = 0; dvander@2838: return true; dvander@2838: } dvander@2838: dvander@2838: IGamePlayer *pTarget = playerhelpers->GetGamePlayer(player_index); dvander@2838: dvander@2838: if (pTarget == NULL) dvander@2838: { dvander@2838: info->reason = COMMAND_TARGET_NONE; dvander@2838: info->num_targets = 0; dvander@2838: return true; dvander@2838: } dvander@2838: dvander@2838: info->reason = playerhelpers->FilterCommandTarget(pAdmin, pTarget, info->flags); dvander@2838: if (info->reason != COMMAND_TARGET_VALID) dvander@2838: { dvander@2838: info->num_targets = 0; dvander@2838: return true; dvander@2838: } dvander@1628: dvander@2838: info->targets[0] = player_index; dvander@2838: info->num_targets = 1; dvander@2838: info->reason = COMMAND_TARGET_VALID; dvander@2838: info->target_name_style = COMMAND_TARGETNAME_RAW; dvander@2838: snprintf(info->target_name, info->target_name_maxlength, "%s", pTarget->GetName()); dvander@2838: return true; dvander@2838: } dvander@2838: else if (strcmp(info->pattern, "@spec") == 0) dvander@1628: { dvander@2838: const char *teamname = tools_GetTeamName(1); dvander@2838: if (strcasecmp(teamname, "spectator") != 0) dvander@2838: return false; dvander@1757: info->num_targets = 0; dvander@2838: for (int i = 1; i <= playerhelpers->GetMaxClients(); i++) dvander@2838: { dvander@2838: IGamePlayer *player = playerhelpers->GetGamePlayer(i); dvander@2838: if (player == NULL || !player->IsInGame()) dvander@2838: continue; dvander@2838: IPlayerInfo *plinfo = player->GetPlayerInfo(); dvander@2838: if (plinfo == NULL) dvander@2838: continue; dvander@2838: if (plinfo->GetTeamIndex() == 1 && dvander@2838: playerhelpers->FilterCommandTarget(pAdmin, player, info->flags) == dvander@2838: COMMAND_TARGET_VALID) dvander@2838: { dvander@2838: info->targets[info->num_targets++] = i; dvander@2838: } dvander@2838: } dvander@2838: info->reason = info->num_targets > 0 ? COMMAND_TARGET_VALID : COMMAND_TARGET_EMPTY_FILTER; dvander@2838: info->target_name_style = COMMAND_TARGETNAME_ML; dvander@2838: snprintf(info->target_name, info->target_name_maxlength, "all spectators"); dvander@1757: return true; dvander@1628: } dvander@1628: dvander@2838: return false; dvander@1628: } dvander@2503: dvander@2790: const char *SDKTools::GetExtensionVerString() pred@2711: { dvander@2783: return SM_FULL_VERSION; dvander@2783: } dvander@2783: dvander@2790: const char *SDKTools::GetExtensionDateString() dvander@2783: { dvander@2783: return SM_BUILD_TIMESTAMP; pred@2711: } pred@2711: dvander@2786: void SDKTools::OnClientPutInServer(int client) dvander@2786: { dvander@2786: g_Hooks.OnClientPutInServer(client); dvander@2786: } dvander@2786: dvander@2503: class SDKTools_API : public ISDKTools dvander@2503: { dvander@2503: public: dvander@2503: virtual const char *GetInterfaceName() dvander@2503: { dvander@2503: return SMINTERFACE_SDKTOOLS_NAME; dvander@2503: } dvander@2503: dvander@2503: virtual unsigned int GetInterfaceVersion() dvander@2503: { dvander@2503: return SMINTERFACE_SDKTOOLS_VERSION; dvander@2503: } dvander@2503: dvander@2503: virtual IServer *GetIServer() dvander@2503: { dvander@2503: return iserver; dvander@2503: } skamonkey@3157: skamonkey@3157: virtual void *GetGameRules() skamonkey@3157: { skamonkey@3157: if (!g_pGameRules) skamonkey@3157: return NULL; skamonkey@3157: skamonkey@3157: return *g_pGameRules; skamonkey@3157: } dvander@2503: } g_SDKTools_API; dvander@2503: dvander@2503: static void InitSDKToolsAPI() dvander@2503: { dvander@2503: g_pSDKTools = &g_SDKTools_API; dvander@2503: sharesys->AddInterface(myself, g_pSDKTools); dvander@2503: }