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"
skamonkey@3816: #include "teamnatives.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:
kyle@3819: SH_ADD_HOOK(IServerGameDLL, LevelInit, gamedll, SH_MEMBER(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:
kyle@3819: SH_REMOVE_HOOK(IServerGameDLL, LevelInit, gamedll, SH_MEMBER(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);
skamonkey@3854: #if SOURCE_ENGINE != SE_DOTA
faluco@1560: GET_V_IFACE_ANY(GetEngineFactory, pluginhelpers, IServerPluginHelpers, INTERFACEVERSION_ISERVERPLUGINHELPERS);
skamonkey@3854: #endif
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:
skamonkey@3816: void SDKTools::OnCoreMapStart(edict_t *pEdictList, int edictCount, int clientMax)
skamonkey@3816: {
skamonkey@3816: InitTeamNatives();
skamonkey@3816: GetResourceEntity();
skamonkey@3816: }
skamonkey@3816:
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: {
asherkin@3630: return SM_VERSION_STRING;
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: }