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: