dvander@2726: /** dvander@2726: * vim: set ts=4 sw=4 : dvander@2726: * ============================================================================= dvander@2726: * SourceMod ds@3099: * Copyright (C) 2004-2010 AlliedModders LLC. All rights reserved. dvander@2726: * ============================================================================= dvander@2726: * dvander@2726: * This program is free software; you can redistribute it and/or modify it under dvander@2726: * the terms of the GNU General Public License, version 3.0, as published by the dvander@2726: * Free Software Foundation. dvander@2726: * dvander@2726: * This program is distributed in the hope that it will be useful, but WITHOUT dvander@2726: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS dvander@2726: * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more dvander@2726: * details. dvander@2726: * dvander@2726: * You should have received a copy of the GNU General Public License along with dvander@2726: * this program. If not, see . dvander@2726: * dvander@2726: * As a special exception, AlliedModders LLC gives you permission to link the dvander@2726: * code of this program (as well as its derivative works) to "Half-Life 2," the dvander@2726: * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software dvander@2726: * by the Valve Corporation. You must obey the GNU General Public License in dvander@2726: * all respects for all other code used. Additionally, AlliedModders LLC grants dvander@2726: * this exception to all derivative works. AlliedModders LLC defines further dvander@2726: * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), dvander@2726: * or . dvander@2726: * dvander@2726: * Version: $Id$ dvander@2726: */ dvander@2726: #include dvander@2726: #include dvander@2726: #include "sourcemod.h" dvander@2726: #include "sourcemm_api.h" dvander@2726: #include "sm_globals.h" dvander@2726: #include "sm_autonatives.h" dvander@2726: #include "logic/intercom.h" dvander@2726: #include "LibrarySys.h" dvander@2726: #include "sm_stringutil.h" dvander@2726: #include "Logger.h" dvander@2728: #include "sm_srvcmds.h" dvander@2730: #include "ForwardSys.h" dvander@2989: #include "TimerSys.h" dvander@2906: #include "logic_bridge.h" dvander@2996: #include "PlayerManager.h" dvander@3000: #include "AdminCache.h" dvander@3001: #include "HalfLife2.h" fyrenmoo@3366: #include "CoreConfig.h" skamonkey@3899: #if SOURCE_ENGINE == SE_DOTA skamonkey@3899: #include "convar_sm_dota.h" skamonkey@3899: #elif SOURCE_ENGINE >= SE_ALIENSWARM dvander@3872: #include "convar_sm_swarm.h" dvander@3872: #elif SOURCE_ENGINE >= SE_LEFT4DEAD dvander@3872: #include "convar_sm_l4d.h" dvander@3872: #elif SOURCE_ENGINE >= SE_ORANGEBOX dvander@3872: #include "convar_sm_ob.h" dvander@3872: #else dvander@3872: #include "convar_sm.h" dvander@3872: #endif dvander@2726: dvander@3791: #if defined _WIN32 dvander@3791: #define MATCHMAKINGDS_SUFFIX "" dvander@3791: #define MATCHMAKINGDS_EXT "dll" dvander@3791: #elif defined __APPLE__ dvander@3791: #define MATCHMAKINGDS_SUFFIX "" dvander@3791: #define MATCHMAKINGDS_EXT "dylib" dvander@3791: #elif defined __linux__ skamonkey@3320: #if SOURCE_ENGINE < SE_LEFT4DEAD2 skamonkey@3320: #define MATCHMAKINGDS_SUFFIX "_i486" skamonkey@3320: #else skamonkey@3320: #define MATCHMAKINGDS_SUFFIX "" dvander@3791: #endif dvander@3791: #define MATCHMAKINGDS_EXT "so" skamonkey@3320: #endif skamonkey@3320: dvander@2726: static ILibrary *g_pLogic = NULL; dvander@2726: static LogicInitFunction logic_init_fn; dvander@2726: dvander@2726: IThreader *g_pThreader; dvander@2726: ITextParsers *textparsers; dvander@3002: sm_logic_t logicore; dvander@3004: ITranslator *translator; dvander@3872: IScriptManager *scripts; dvander@3872: IShareSys *sharesys; dvander@3872: IExtensionSys *extsys; dvander@3872: IHandleSys *handlesys; dvander@2726: dvander@2726: class VEngineServer_Logic : public IVEngineServer_Logic dvander@2726: { dvander@2726: public: dvander@2726: virtual bool IsMapValid(const char *map) dvander@2726: { dvander@3872: return !!engine->IsMapValid(map); dvander@2726: } dvander@3001: dvander@3001: virtual void ServerCommand(const char *cmd) dvander@3001: { dvander@3001: engine->ServerCommand(cmd); dvander@3001: } dvander@2726: }; dvander@2726: dvander@2726: static VEngineServer_Logic logic_engine; dvander@2726: voidedweasel@3929: voidedweasel@3929: class VFileSystem_Logic : public IFileSystem_Logic voidedweasel@3929: { voidedweasel@3929: public: voidedweasel@3929: const char *FindFirstEx(const char *pWildCard, const char *pPathID, FileFindHandle_t *pHandle) voidedweasel@3929: { voidedweasel@3929: return filesystem->FindFirstEx(pWildCard, pPathID, pHandle); voidedweasel@3929: } voidedweasel@3929: const char *FindNext(FileFindHandle_t handle) voidedweasel@3929: { voidedweasel@3929: return filesystem->FindNext(handle); voidedweasel@3929: } voidedweasel@3929: void FindClose(FileFindHandle_t handle) voidedweasel@3929: { voidedweasel@3929: filesystem->FindClose(handle); voidedweasel@3929: } voidedweasel@3929: }; voidedweasel@3929: voidedweasel@3929: static VFileSystem_Logic logic_filesystem; voidedweasel@3929: voidedweasel@3929: dvander@2726: static ConVar *find_convar(const char *name) dvander@2726: { dvander@2726: return icvar->FindVar(name); dvander@2726: } dvander@2726: dvander@2726: static void log_error(const char *fmt, ...) dvander@2726: { dvander@2726: va_list ap; dvander@2726: dvander@2726: va_start(ap, fmt); dvander@2726: g_Logger.LogErrorEx(fmt, ap); dvander@2726: va_end(ap); dvander@2726: } dvander@2726: dvander@3872: static void log_fatal(const char *fmt, ...) dvander@3872: { dvander@3872: va_list ap; dvander@3872: dvander@3872: va_start(ap, fmt); dvander@3872: g_Logger.LogFatalEx(fmt, ap); dvander@3872: va_end(ap); dvander@3872: } dvander@3872: dvander@3791: static void log_message(const char *fmt, ...) dvander@3791: { dvander@3791: va_list ap; dvander@3791: va_start(ap, fmt); dvander@3791: g_Logger.LogMessageEx(fmt, ap); dvander@3791: va_end(ap); dvander@3791: } dvander@3791: dvander@3791: static void log_to_file(FILE *fp, const char *fmt, ...) dvander@3791: { dvander@3791: va_list ap; dvander@3791: va_start(ap, fmt); dvander@3791: g_Logger.LogToOpenFileEx(fp, fmt, ap); dvander@3791: va_end(ap); dvander@3791: } dvander@3791: dvander@3791: static void log_to_game(const char *message) dvander@3791: { dvander@3791: Engine_LogPrintWrapper(message); dvander@3791: } dvander@3791: dvander@3791: static bool file_exists(const char *path) dvander@3791: { dvander@3791: return basefilesystem->FileExists(path); dvander@3791: } dvander@3791: dvander@2726: static const char *get_cvar_string(ConVar* cvar) dvander@2726: { dvander@2726: return cvar->GetString(); dvander@2726: } dvander@2726: dvander@3010: static bool get_game_name(char *buffer, size_t maxlength) dvander@3010: { dvander@3010: KeyValues *pGameInfo = new KeyValues("GameInfo"); dvander@3010: if (g_HL2.KVLoadFromFile(pGameInfo, basefilesystem, "gameinfo.txt")) dvander@3010: { dvander@3010: const char *str; dvander@3010: if ((str = pGameInfo->GetString("game", NULL)) != NULL) dvander@3010: { dvander@3010: strncopy(buffer, str, maxlength); dvander@3010: return true; dvander@3010: } dvander@3010: } dvander@3010: pGameInfo->deleteThis(); dvander@3010: return false; dvander@3010: } dvander@3010: dvander@3010: static const char *get_game_description() dvander@3010: { dvander@3010: return SERVER_CALL(GetGameDescription)(); dvander@3010: } dvander@3010: dvander@3010: static const char *get_source_engine_name() dvander@3010: { dvander@3010: #if !defined SOURCE_ENGINE dvander@3010: # error "Unknown engine type" dvander@3010: #endif dvander@3010: #if SOURCE_ENGINE == SE_EPISODEONE dvander@3010: return "original"; dvander@3010: #elif SOURCE_ENGINE == SE_DARKMESSIAH dvander@3010: return "darkmessiah"; dvander@3010: #elif SOURCE_ENGINE == SE_ORANGEBOX dvander@3010: return "orangebox"; skamonkey@3180: #elif SOURCE_ENGINE == SE_BLOODYGOODTIME skamonkey@3180: return "bloodygoodtime"; skamonkey@3373: #elif SOURCE_ENGINE == SE_EYE skamonkey@3373: return "eye"; skamonkey@3613: #elif SOURCE_ENGINE == SE_CSS skamonkey@3613: return "css"; skamonkey@3961: #elif SOURCE_ENGINE == SE_HL2DM skamonkey@3961: return "hl2dm"; skamonkey@3961: #elif SOURCE_ENGINE == SE_DODS skamonkey@3961: return "dods"; skamonkey@3961: #elif SOURCE_ENGINE == SE_TF2 skamonkey@3961: return "tf2"; dvander@3010: #elif SOURCE_ENGINE == SE_LEFT4DEAD dvander@3010: return "left4dead"; skamonkey@3961: #elif SOURCE_ENGINE == SE_NUCLEARDAWN skamonkey@3961: return "nucleardawn"; dvander@3010: #elif SOURCE_ENGINE == SE_LEFT4DEAD2 dvander@3010: return "left4dead2"; ds@3099: #elif SOURCE_ENGINE == SE_ALIENSWARM ds@3099: return "alienswarm"; skamonkey@3515: #elif SOURCE_ENGINE == SE_PORTAL2 skamonkey@3515: return "portal2"; skamonkey@3515: #elif SOURCE_ENGINE == SE_CSGO skamonkey@3515: return "csgo"; skamonkey@3853: #elif SOURCE_ENGINE == SE_DOTA skamonkey@3853: return "dota"; dvander@3010: #endif dvander@3010: } dvander@3010: dvander@3010: static bool symbols_are_hidden() dvander@3010: { skamonkey@3961: #if (SOURCE_ENGINE == SE_CSS) || (SOURCE_ENGINE == SE_HL2DM) || (SOURCE_ENGINE == SE_DODS) || (SOURCE_ENGINE == SE_TF2) || (SOURCE_ENGINE == SE_LEFT4DEAD) || (SOURCE_ENGINE == SE_NUCLEARDAWN) || (SOURCE_ENGINE == SE_LEFT4DEAD2) || (SOURCE_ENGINE == SE_CSGO) || (SOURCE_ENGINE == SE_DOTA) dvander@3010: return true; dvander@3010: #else dvander@3010: return false; dvander@3010: #endif dvander@3010: } dvander@3010: fyrenmoo@3366: static const char* get_core_config_value(const char* key) fyrenmoo@3366: { fyrenmoo@3366: return g_CoreConfig.GetCoreConfigValue(key); dvander@3872: } dvander@3872: dvander@3872: static bool is_map_loading() dvander@3872: { dvander@3872: return g_SourceMod.IsMapLoading(); dvander@3872: } dvander@3872: dvander@3872: static bool is_map_running() dvander@3872: { dvander@3872: return g_SourceMod.IsMapRunning(); dvander@3872: } dvander@3872: dvander@3872: int read_cmd_argc(const CCommand &args) dvander@3872: { dvander@3872: return args.ArgC(); dvander@3872: } dvander@3872: dvander@3872: static const char *read_cmd_arg(const CCommand &args, int arg) dvander@3872: { dvander@3872: return args.Arg(arg); dvander@3872: } dvander@3872: dvander@3872: static int load_mms_plugin(const char *file, bool *ok, char *error, size_t maxlength) dvander@3872: { dvander@3872: bool ignore_already; dvander@3872: PluginId id = g_pMMPlugins->Load(file, g_PLID, ignore_already, error, maxlength); dvander@3872: dvander@3872: Pl_Status status; dvander@3872: dvander@3872: #ifndef METAMOD_PLAPI_VERSION dvander@3874: const char *filep; dvander@3872: PluginId source; dvander@3872: #endif dvander@3872: dvander@3872: if (!id || ( dvander@3872: #ifndef METAMOD_PLAPI_VERSION dvander@3874: g_pMMPlugins->Query(id, filep, status, source) dvander@3872: #else dvander@3872: g_pMMPlugins->Query(id, NULL, &status, NULL) dvander@3872: #endif dvander@3872: && status < Pl_Paused)) dvander@3872: { dvander@3872: *ok = false; dvander@3872: } dvander@3872: else dvander@3872: { dvander@3872: *ok = true; dvander@3872: } dvander@3872: dvander@3872: return id; dvander@3872: } dvander@3872: dvander@3872: static void unload_mms_plugin(int id) dvander@3872: { dvander@3872: char ignore[255]; dvander@3872: g_pMMPlugins->Unload(id, true, ignore, sizeof(ignore)); dvander@3872: } dvander@3872: dvander@3872: void do_global_plugin_loads() dvander@3872: { dvander@3872: g_SourceMod.DoGlobalPluginLoads(); dvander@3872: } fyrenmoo@3366: dvander@3882: #if defined METAMOD_PLAPI_VERSION dvander@3882: #if SOURCE_ENGINE == SE_LEFT4DEAD dvander@3882: #define GAMEFIX "2.l4d" dvander@3882: #elif SOURCE_ENGINE == SE_LEFT4DEAD2 dvander@3882: #define GAMEFIX "2.l4d2" dvander@3882: #elif SOURCE_ENGINE == SE_ALIENSWARM dvander@3882: #define GAMEFIX "2.swarm" dvander@3882: #elif SOURCE_ENGINE == SE_ORANGEBOX dvander@3882: #define GAMEFIX "2.ep2" dvander@3882: #elif SOURCE_ENGINE == SE_BLOODYGOODTIME dvander@3882: #define GAMEFIX "2.bgt" dvander@3882: #elif SOURCE_ENGINE == SE_EYE dvander@3882: #define GAMEFIX "2.eye" dvander@3882: #elif SOURCE_ENGINE == SE_CSS dvander@3882: #define GAMEFIX "2.css" skamonkey@3961: #elif SOURCE_ENGINE == SE_HL2DM skamonkey@3961: #define GAMEFIX "2.hl2dm" skamonkey@3961: #elif SOURCE_ENGINE == SE_DODS skamonkey@3961: #define GAMEFIX "2.dods" skamonkey@3961: #elif SOURCE_ENGINE == SE_TF2 skamonkey@3961: #define GAMEFIX "2.tf2" dvander@3882: #elif SOURCE_ENGINE == SE_DARKMESSIAH dvander@3882: #define GAMEFIX "2.darkm" dvander@3882: #elif SOURCE_ENGINE == SE_PORTAL2 dvander@3882: #define GAMEFIX "2.portal2" dvander@3882: #elif SOURCE_ENGINE == SE_CSGO dvander@3882: #define GAMEFIX "2.csgo" dvander@3882: #elif SOURCE_ENGINE == SE_DOTA dvander@3882: #define GAMEFIX "2.dota" dvander@3882: #else dvander@3882: #define GAMEFIX "2.ep1" dvander@3882: #endif //(SOURCE_ENGINE == SE_LEFT4DEAD) || (SOURCE_ENGINE == SE_LEFT4DEAD2) dvander@3882: #else //METAMOD_PLAPI_VERSION dvander@3882: #define GAMEFIX "1.ep1" dvander@3882: #endif //METAMOD_PLAPI_VERSION dvander@3882: dvander@2989: static ServerGlobals serverGlobals; dvander@2989: dvander@2726: static sm_core_t core_bridge = dvander@2726: { dvander@2726: /* Objects */ dvander@2726: &g_SourceMod, dvander@2726: &g_LibSys, dvander@2726: reinterpret_cast(&logic_engine), voidedweasel@3929: reinterpret_cast(&logic_filesystem), dvander@2728: &g_RootMenu, dvander@2730: &g_Forwards, dvander@2989: &g_Timers, dvander@2996: &g_Players, dvander@3000: &g_Admins, dvander@3001: &g_HL2, skamonkey@3800: &g_pSourcePawn, skamonkey@3800: &g_pSourcePawn2, dvander@2726: /* Functions */ dvander@2726: find_convar, dvander@2726: strncopy, dvander@2726: UTIL_TrimWhitespace, dvander@2726: log_error, dvander@3872: log_fatal, dvander@3791: log_message, dvander@3791: log_to_file, dvander@3791: log_to_game, dvander@3791: file_exists, dvander@2726: get_cvar_string, dvander@2884: UTIL_Format, dvander@3792: UTIL_FormatArgs, dvander@3004: gnprintf, dvander@3006: atcprintf, dvander@3010: get_game_name, dvander@3010: get_game_description, dvander@3010: get_source_engine_name, dvander@3010: symbols_are_hidden, fyrenmoo@3366: get_core_config_value, dvander@3872: is_map_loading, dvander@3872: is_map_running, dvander@3872: read_cmd_argc, dvander@3872: read_cmd_arg, dvander@3872: load_mms_plugin, dvander@3872: unload_mms_plugin, dvander@3872: do_global_plugin_loads, dvander@3872: SM_AreConfigsExecuted, dvander@3872: SM_ExecuteForPlugin, dvander@3882: GAMEFIX, dvander@2989: &serverGlobals dvander@2726: }; dvander@2726: dvander@2726: void InitLogicBridge() dvander@2726: { dvander@2989: serverGlobals.universalTime = g_pUniversalTime; dvander@2989: serverGlobals.frametime = &gpGlobals->frametime; dvander@2989: serverGlobals.interval_per_tick = &gpGlobals->interval_per_tick; dvander@2989: dvander@3010: core_bridge.engineFactory = (void *)g_SMAPI->GetEngineFactory(false); dvander@3010: core_bridge.serverFactory = (void *)g_SMAPI->GetServerFactory(false); skamonkey@3320: skamonkey@3320: ILibrary *mmlib; skamonkey@3320: char path[PLATFORM_MAX_PATH]; skamonkey@3320: skamonkey@3320: g_LibSys.PathFormat(path, sizeof(path), "%s/bin/matchmaking_ds%s.%s", g_SMAPI->GetBaseDir(), MATCHMAKINGDS_SUFFIX, MATCHMAKINGDS_EXT); skamonkey@3320: skamonkey@3321: if ((mmlib = g_LibSys.OpenLibrary(path, NULL, 0))) skamonkey@3320: { skamonkey@3320: core_bridge.matchmakingDSFactory = mmlib->GetSymbolAddress("CreateInterface"); skamonkey@3320: mmlib->CloseLibrary(); skamonkey@3320: } skamonkey@3320: dvander@3002: logic_init_fn(&core_bridge, &logicore); dvander@2726: dvander@2726: /* Add SMGlobalClass instances */ dvander@2726: SMGlobalClass* glob = SMGlobalClass::head; dvander@2726: while (glob->m_pGlobalClassNext != NULL) dvander@2726: { dvander@2726: glob = glob->m_pGlobalClassNext; dvander@2726: } dvander@2726: assert(glob->m_pGlobalClassNext == NULL); dvander@3002: glob->m_pGlobalClassNext = logicore.head; dvander@2726: dvander@3002: g_pThreader = logicore.threader; dvander@3002: g_pSourcePawn2->SetProfiler(logicore.profiler); dvander@3004: translator = logicore.translator; dvander@3872: scripts = logicore.scripts; dvander@3872: sharesys = logicore.sharesys; dvander@3872: extsys = logicore.extsys; dvander@3872: g_pCoreIdent = logicore.core_ident; dvander@3872: handlesys = logicore.handlesys; dvander@2726: } dvander@2726: dvander@2726: bool StartLogicBridge(char *error, size_t maxlength) dvander@2726: { dvander@2726: char file[PLATFORM_MAX_PATH]; dvander@2726: dvander@2726: /* Now it's time to load the logic binary */ dvander@2726: g_SMAPI->PathFormat(file, dvander@2726: sizeof(file), dvander@2726: "%s/bin/sourcemod.logic." PLATFORM_LIB_EXT, dvander@2726: g_SourceMod.GetSourceModPath()); dvander@2726: dvander@2726: char myerror[255]; dvander@2726: g_pLogic = g_LibSys.OpenLibrary(file, myerror, sizeof(myerror)); dvander@2726: dvander@2726: if (!g_pLogic) dvander@2726: { dvander@2726: if (error && maxlength) dvander@2726: { dvander@2726: UTIL_Format(error, maxlength, "failed to load %s: %s", file, myerror); dvander@2726: } dvander@2726: return false; dvander@2726: } dvander@2726: dvander@2726: LogicLoadFunction llf = (LogicLoadFunction)g_pLogic->GetSymbolAddress("logic_load"); dvander@2726: if (llf == NULL) dvander@2726: { dvander@2726: g_pLogic->CloseLibrary(); dvander@2726: if (error && maxlength) dvander@2726: { dvander@2726: UTIL_Format(error, maxlength, "could not find logic_load function"); dvander@2726: } dvander@2726: return false; dvander@2726: } dvander@2726: dvander@2726: GetITextParsers getitxt = (GetITextParsers)g_pLogic->GetSymbolAddress("get_textparsers"); dvander@2726: textparsers = getitxt(); dvander@2726: dvander@2726: logic_init_fn = llf(SM_LOGIC_MAGIC); dvander@2726: dvander@2726: return true; dvander@2726: } dvander@2726: dvander@2726: void ShutdownLogicBridge() dvander@2726: { dvander@2726: g_pLogic->CloseLibrary(); dvander@2726: } dvander@2726: