core/logic_bridge.cpp
author Ruben Gonzalez <drifter01620@gmail.com>
Thu May 15 21:22:24 2014 -0400 (2014-05-15)
changeset 4362 8a15e967d983
parent 4320 bdf9028efe94
permissions -rw-r--r--
Update gamedata for CS:S update.
     1 /**
     2  * vim: set ts=4 sw=4 tw=99 noet:
     3  * =============================================================================
     4  * SourceMod
     5  * Copyright (C) 2004-2010 AlliedModders LLC.  All rights reserved.
     6  * =============================================================================
     7  *
     8  * This program is free software; you can redistribute it and/or modify it under
     9  * the terms of the GNU General Public License, version 3.0, as published by the
    10  * Free Software Foundation.
    11  * 
    12  * This program is distributed in the hope that it will be useful, but WITHOUT
    13  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
    14  * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
    15  * details.
    16  *
    17  * You should have received a copy of the GNU General Public License along with
    18  * this program.  If not, see <http://www.gnu.org/licenses/>.
    19  *
    20  * As a special exception, AlliedModders LLC gives you permission to link the
    21  * code of this program (as well as its derivative works) to "Half-Life 2," the
    22  * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
    23  * by the Valve Corporation.  You must obey the GNU General Public License in
    24  * all respects for all other code used.  Additionally, AlliedModders LLC grants
    25  * this exception to all derivative works.  AlliedModders LLC defines further
    26  * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
    27  * or <http://www.sourcemod.net/license.php>.
    28  *
    29  * Version: $Id$
    30  */
    31 #include <stdio.h>
    32 #include <assert.h>
    33 #include "sourcemod.h"
    34 #include "sourcemm_api.h"
    35 #include "sm_globals.h"
    36 #include "sm_autonatives.h"
    37 #include "logic/intercom.h"
    38 #include "LibrarySys.h"
    39 #include "sm_stringutil.h"
    40 #include "Logger.h"
    41 #include "sm_srvcmds.h"
    42 #include "TimerSys.h"
    43 #include "logic_bridge.h"
    44 #include "PlayerManager.h"
    45 #include "AdminCache.h"
    46 #include "HalfLife2.h"
    47 #include "CoreConfig.h"
    48 #include "IDBDriver.h"
    49 #if SOURCE_ENGINE == SE_DOTA
    50 #include "convar_sm_dota.h"
    51 #elif SOURCE_ENGINE >= SE_ALIENSWARM
    52 #include "convar_sm_swarm.h"
    53 #elif SOURCE_ENGINE >= SE_LEFT4DEAD
    54 #include "convar_sm_l4d.h"
    55 #elif SOURCE_ENGINE >= SE_ORANGEBOX
    56 #include "convar_sm_ob.h"
    57 #else
    58 #include "convar_sm.h"
    59 #endif
    60 
    61 #if defined _WIN32
    62 	#define MATCHMAKINGDS_SUFFIX	""
    63 	#define MATCHMAKINGDS_EXT	"dll"
    64 #elif defined __APPLE__
    65 	#define MATCHMAKINGDS_SUFFIX	""
    66 	#define MATCHMAKINGDS_EXT	"dylib"
    67 #elif defined __linux__
    68 #if SOURCE_ENGINE < SE_LEFT4DEAD2
    69 	#define MATCHMAKINGDS_SUFFIX	"_i486"
    70 #else
    71 	#define MATCHMAKINGDS_SUFFIX	""
    72 #endif
    73 	#define MATCHMAKINGDS_EXT	"so"
    74 #endif
    75 
    76 static ILibrary *g_pLogic = NULL;
    77 static LogicInitFunction logic_init_fn;
    78 
    79 IThreader *g_pThreader;
    80 ITextParsers *textparsers;
    81 sm_logic_t logicore;
    82 ITranslator *translator;
    83 IScriptManager *scripts;
    84 IShareSys *sharesys;
    85 IExtensionSys *extsys;
    86 IHandleSys *handlesys;
    87 IForwardManager *forwardsys;
    88 
    89 class VEngineServer_Logic : public IVEngineServer_Logic
    90 {
    91 public:
    92 	virtual bool IsMapValid(const char *map)
    93 	{
    94 		return !!engine->IsMapValid(map);
    95 	}
    96 
    97 	virtual void ServerCommand(const char *cmd)
    98 	{
    99 		engine->ServerCommand(cmd);
   100 	}
   101 };
   102 
   103 static VEngineServer_Logic logic_engine;
   104 
   105 
   106 class VFileSystem_Logic : public IFileSystem_Logic
   107 {
   108 public:
   109 	const char *FindFirstEx(const char *pWildCard, const char *pPathID, FileFindHandle_t *pHandle)
   110 	{
   111 		return filesystem->FindFirstEx(pWildCard, pPathID, pHandle);
   112 	}
   113 	const char *FindNext(FileFindHandle_t handle)
   114 	{
   115 		return filesystem->FindNext(handle);
   116 	}
   117 	void FindClose(FileFindHandle_t handle)
   118 	{
   119 		filesystem->FindClose(handle);
   120 	}
   121 	FileHandle_t Open(const char *pFileName, const char *pOptions, const char *pathID = 0)
   122 	{
   123 		return filesystem->Open(pFileName, pOptions, pathID);
   124 	}
   125 	void Close(FileHandle_t file)
   126 	{
   127 		filesystem->Close(file);
   128 	}
   129 	char *ReadLine(char *pOutput, int maxChars, FileHandle_t file)
   130 	{
   131 		return filesystem->ReadLine(pOutput, maxChars, file);
   132 	}
   133 	bool EndOfFile(FileHandle_t file)
   134 	{
   135 		return filesystem->EndOfFile(file);
   136 	}
   137 	bool FileExists(const char *pFileName, const char *pPathID = 0)
   138 	{
   139 		return filesystem->FileExists(pFileName, pPathID);
   140 	}
   141 	unsigned int Size(const char *pFileName, const char *pPathID = 0)
   142 	{
   143 		return filesystem->Size(pFileName, pPathID);
   144 	}
   145 };
   146 
   147 static VFileSystem_Logic logic_filesystem;
   148 
   149 
   150 static ConVar *find_convar(const char *name)
   151 {
   152 	return icvar->FindVar(name);
   153 }
   154 
   155 static void log_error(const char *fmt, ...)
   156 {
   157 	va_list ap;
   158 
   159 	va_start(ap, fmt);
   160 	g_Logger.LogErrorEx(fmt, ap);
   161 	va_end(ap);
   162 }
   163 
   164 static void log_fatal(const char *fmt, ...)
   165 {
   166 	va_list ap;
   167 
   168 	va_start(ap, fmt);
   169 	g_Logger.LogFatalEx(fmt, ap);
   170 	va_end(ap);
   171 }
   172 
   173 static void log_message(const char *fmt, ...)
   174 {
   175 	va_list ap;
   176 	va_start(ap, fmt);
   177 	g_Logger.LogMessageEx(fmt, ap);
   178 	va_end(ap);
   179 }
   180 
   181 static void log_to_file(FILE *fp, const char *fmt, ...)
   182 {
   183 	va_list ap;
   184 	va_start(ap, fmt);
   185 	g_Logger.LogToOpenFileEx(fp, fmt, ap);
   186 	va_end(ap);
   187 }
   188 
   189 static void log_to_game(const char *message)
   190 {
   191 	Engine_LogPrintWrapper(message);
   192 }
   193 
   194 static const char *get_cvar_string(ConVar* cvar)
   195 {
   196 	return cvar->GetString();
   197 }
   198 
   199 static bool get_game_name(char *buffer, size_t maxlength)
   200 {
   201 	KeyValues *pGameInfo = new KeyValues("GameInfo");
   202 	if (g_HL2.KVLoadFromFile(pGameInfo, basefilesystem, "gameinfo.txt"))
   203 	{
   204 		const char *str;
   205 		if ((str = pGameInfo->GetString("game", NULL)) != NULL)
   206 		{
   207 			strncopy(buffer, str, maxlength);
   208 			pGameInfo->deleteThis();
   209 			return true;
   210 		}
   211 	}
   212 	pGameInfo->deleteThis();
   213 	return false;
   214 }
   215 
   216 static const char *get_game_description()
   217 {
   218 	return SERVER_CALL(GetGameDescription)();
   219 }
   220 
   221 static const char *get_source_engine_name()
   222 {
   223 #if !defined SOURCE_ENGINE
   224 # error "Unknown engine type"
   225 #endif
   226 #if SOURCE_ENGINE == SE_EPISODEONE
   227 	return "original";
   228 #elif SOURCE_ENGINE == SE_DARKMESSIAH
   229 	return "darkmessiah";
   230 #elif SOURCE_ENGINE == SE_ORANGEBOX
   231 	return "orangebox";
   232 #elif SOURCE_ENGINE == SE_BLOODYGOODTIME
   233 	return "bloodygoodtime";
   234 #elif SOURCE_ENGINE == SE_EYE
   235 	return "eye";
   236 #elif SOURCE_ENGINE == SE_CSS
   237 	return "css";
   238 #elif SOURCE_ENGINE == SE_HL2DM
   239 	return "hl2dm";
   240 #elif SOURCE_ENGINE == SE_DODS
   241 	return "dods";
   242 #elif SOURCE_ENGINE == SE_SDK2013
   243 	return "sdk2013";
   244 #elif SOURCE_ENGINE == SE_TF2
   245 	return "tf2";
   246 #elif SOURCE_ENGINE == SE_LEFT4DEAD
   247 	return "left4dead";
   248 #elif SOURCE_ENGINE == SE_NUCLEARDAWN
   249 	return "nucleardawn";
   250 #elif SOURCE_ENGINE == SE_CONTAGION
   251 	return "contagion";
   252 #elif SOURCE_ENGINE == SE_LEFT4DEAD2
   253 	return "left4dead2";
   254 #elif SOURCE_ENGINE == SE_ALIENSWARM
   255 	return "alienswarm";
   256 #elif SOURCE_ENGINE == SE_PORTAL2
   257 	return "portal2";
   258 #elif SOURCE_ENGINE == SE_BLADE
   259 	return "blade";
   260 #elif SOURCE_ENGINE == SE_INSURGENCY
   261 	return "insurgency";
   262 #elif SOURCE_ENGINE == SE_CSGO
   263 	return "csgo";
   264 #elif SOURCE_ENGINE == SE_DOTA
   265 	return "dota";
   266 #endif
   267 }
   268 
   269 static bool symbols_are_hidden()
   270 {
   271 #if (SOURCE_ENGINE == SE_CSS)            \
   272 	|| (SOURCE_ENGINE == SE_HL2DM)       \
   273 	|| (SOURCE_ENGINE == SE_DODS)        \
   274 	|| (SOURCE_ENGINE == SE_SDK2013)     \
   275 	|| (SOURCE_ENGINE == SE_TF2)         \
   276 	|| (SOURCE_ENGINE == SE_LEFT4DEAD)   \
   277 	|| (SOURCE_ENGINE == SE_NUCLEARDAWN) \
   278 	|| (SOURCE_ENGINE == SE_LEFT4DEAD2)  \
   279 	|| (SOURCE_ENGINE == SE_INSURGENCY)  \
   280 	|| (SOURCE_ENGINE == SE_BLADE)       \
   281 	|| (SOURCE_ENGINE == SE_CSGO)        \
   282 	|| (SOURCE_ENGINE == SE_DOTA)
   283 	return true;
   284 #else
   285 	return false;
   286 #endif
   287 }
   288 
   289 static const char* get_core_config_value(const char* key)
   290 {
   291 	return g_CoreConfig.GetCoreConfigValue(key);
   292 }
   293 
   294 static bool is_map_loading()
   295 {
   296 	return g_SourceMod.IsMapLoading();
   297 }
   298 
   299 static bool is_map_running()
   300 {
   301 	return g_SourceMod.IsMapRunning();
   302 }
   303 
   304 static DatabaseInfo keyvalues_to_dbinfo(KeyValues *kv)
   305 {
   306 	DatabaseInfo info;
   307 	info.database = kv->GetString("database", "");
   308 	info.driver = kv->GetString("driver", "default");
   309 	info.host = kv->GetString("host", "");
   310 	info.maxTimeout = kv->GetInt("timeout", 0);
   311 	info.pass = kv->GetString("pass", "");
   312 	info.port = kv->GetInt("port", 0);
   313 	info.user = kv->GetString("user", "");
   314 	return info;
   315 }
   316 
   317 int read_cmd_argc(const CCommand &args)
   318 {
   319 	return args.ArgC();
   320 }
   321 
   322 static const char *read_cmd_arg(const CCommand &args, int arg)
   323 {
   324 	return args.Arg(arg);
   325 }
   326 
   327 static int load_mms_plugin(const char *file, bool *ok, char *error, size_t maxlength)
   328 {
   329 	bool ignore_already;
   330 	PluginId id = g_pMMPlugins->Load(file, g_PLID, ignore_already, error, maxlength);
   331 
   332 	Pl_Status status;
   333 
   334 #ifndef METAMOD_PLAPI_VERSION
   335 	const char *filep;
   336 	PluginId source;
   337 #endif
   338 
   339 	if (!id || (
   340 #ifndef METAMOD_PLAPI_VERSION
   341 		g_pMMPlugins->Query(id, filep, status, source)
   342 #else
   343 		g_pMMPlugins->Query(id, NULL, &status, NULL)
   344 #endif
   345 		&& status < Pl_Paused))
   346 	{
   347 		*ok = false;
   348 	}
   349 	else
   350 	{
   351 		*ok = true;
   352 	}
   353 
   354 	return id;
   355 }
   356 
   357 static void unload_mms_plugin(int id)
   358 {
   359 	char ignore[255];
   360 	g_pMMPlugins->Unload(id, true, ignore, sizeof(ignore));
   361 }
   362 
   363 void do_global_plugin_loads()
   364 {
   365 	g_SourceMod.DoGlobalPluginLoads();
   366 }
   367 
   368 #if defined METAMOD_PLAPI_VERSION
   369 #if SOURCE_ENGINE == SE_LEFT4DEAD
   370 #define GAMEFIX "2.l4d"
   371 #elif SOURCE_ENGINE == SE_LEFT4DEAD2
   372 #define GAMEFIX "2.l4d2"
   373 #elif SOURCE_ENGINE == SE_NUCLEARDAWN
   374 #define GAMEFIX "2.nd"
   375 #elif SOURCE_ENGINE == SE_ALIENSWARM
   376 #define GAMEFIX "2.swarm"
   377 #elif SOURCE_ENGINE == SE_ORANGEBOX
   378 #define GAMEFIX "2.ep2"
   379 #elif SOURCE_ENGINE == SE_BLOODYGOODTIME
   380 #define GAMEFIX "2.bgt"
   381 #elif SOURCE_ENGINE == SE_EYE
   382 #define GAMEFIX "2.eye"
   383 #elif SOURCE_ENGINE == SE_CSS
   384 #define GAMEFIX "2.css"
   385 #elif SOURCE_ENGINE == SE_HL2DM
   386 #define GAMEFIX "2.hl2dm"
   387 #elif SOURCE_ENGINE == SE_DODS
   388 #define GAMEFIX "2.dods"
   389 #elif SOURCE_ENGINE == SE_SDK2013
   390 #define GAMEFIX "2.sdk2013"
   391 #elif SOURCE_ENGINE == SE_TF2
   392 #define GAMEFIX "2.tf2"
   393 #elif SOURCE_ENGINE == SE_DARKMESSIAH
   394 #define GAMEFIX "2.darkm"
   395 #elif SOURCE_ENGINE == SE_PORTAL2
   396 #define GAMEFIX "2.portal2"
   397 #elif SOURCE_ENGINE == SE_BLADE
   398 #define GAMEFIX "2.blade"
   399 #elif SOURCE_ENGINE == SE_INSURGENCY
   400 #define GAMEFIX "2.insurgency"
   401 #elif SOURCE_ENGINE == SE_CSGO
   402 #define GAMEFIX "2.csgo"
   403 #elif SOURCE_ENGINE == SE_DOTA
   404 #define GAMEFIX "2.dota"
   405 #elif SOURCE_ENGINE == SE_CONTAGION
   406 #define GAMEFIX "2.contagion"
   407 #else
   408 #define GAMEFIX "2.ep1"
   409 #endif //(SOURCE_ENGINE == SE_LEFT4DEAD) || (SOURCE_ENGINE == SE_LEFT4DEAD2)
   410 #else  //METAMOD_PLAPI_VERSION
   411 #define GAMEFIX "1.ep1"
   412 #endif //METAMOD_PLAPI_VERSION
   413 
   414 static ServerGlobals serverGlobals;
   415 
   416 static sm_core_t core_bridge =
   417 {
   418 	/* Objects */
   419 	&g_SourceMod,
   420 	&g_LibSys,
   421 	reinterpret_cast<IVEngineServer*>(&logic_engine),
   422 	reinterpret_cast<IFileSystem*>(&logic_filesystem),
   423 	&g_RootMenu,
   424 	&g_Timers,
   425 	&g_Players,
   426 	&g_Admins,
   427 	&g_HL2,
   428 	&g_pSourcePawn,
   429 	&g_pSourcePawn2,
   430 	/* Functions */
   431 	find_convar,
   432 	strncopy,
   433 	UTIL_TrimWhitespace,
   434 	log_error,
   435 	log_fatal,
   436 	log_message,
   437 	log_to_file,
   438 	log_to_game,
   439 	get_cvar_string,
   440 	UTIL_Format,
   441 	UTIL_FormatArgs,
   442 	gnprintf,
   443 	atcprintf,
   444 	get_game_name,
   445 	get_game_description,
   446 	get_source_engine_name,
   447 	symbols_are_hidden,
   448 	get_core_config_value,
   449 	is_map_loading,
   450 	is_map_running,
   451 	read_cmd_argc,
   452 	read_cmd_arg,
   453 	load_mms_plugin,
   454 	unload_mms_plugin,
   455 	do_global_plugin_loads,
   456 	SM_AreConfigsExecuted,
   457 	SM_ExecuteForPlugin,
   458 	keyvalues_to_dbinfo,
   459 	GAMEFIX,
   460 	&serverGlobals
   461 };
   462 
   463 void InitLogicBridge()
   464 {
   465 	serverGlobals.universalTime = g_pUniversalTime;
   466 	serverGlobals.frametime = &gpGlobals->frametime;
   467 	serverGlobals.interval_per_tick = &gpGlobals->interval_per_tick;
   468 
   469 	core_bridge.engineFactory = (void *)g_SMAPI->GetEngineFactory(false);
   470 	core_bridge.serverFactory = (void *)g_SMAPI->GetServerFactory(false);
   471 	core_bridge.listeners = SMGlobalClass::head;
   472 
   473 	ILibrary *mmlib;
   474 	char path[PLATFORM_MAX_PATH];
   475 
   476 	g_LibSys.PathFormat(path, sizeof(path), "%s/bin/matchmaking_ds%s.%s", g_SMAPI->GetBaseDir(), MATCHMAKINGDS_SUFFIX, MATCHMAKINGDS_EXT);
   477 
   478 	if ((mmlib = g_LibSys.OpenLibrary(path, NULL, 0)))
   479 	{
   480 		core_bridge.matchmakingDSFactory = mmlib->GetSymbolAddress("CreateInterface");
   481 		mmlib->CloseLibrary();
   482 	}
   483 	
   484 	logic_init_fn(&core_bridge, &logicore);
   485 
   486 	/* Add SMGlobalClass instances */
   487 	SMGlobalClass* glob = SMGlobalClass::head;
   488 	while (glob->m_pGlobalClassNext != NULL)
   489 	{
   490 		glob = glob->m_pGlobalClassNext;
   491 	}
   492 	assert(glob->m_pGlobalClassNext == NULL);
   493 	glob->m_pGlobalClassNext = logicore.head;
   494 
   495 	g_pThreader = logicore.threader;
   496 	g_pSourcePawn2->SetProfiler(logicore.profiler);
   497 	translator = logicore.translator;
   498 	scripts = logicore.scripts;
   499 	sharesys = logicore.sharesys;
   500 	extsys = logicore.extsys;
   501 	g_pCoreIdent = logicore.core_ident;
   502 	handlesys = logicore.handlesys;
   503 	forwardsys = logicore.forwardsys;
   504 }
   505 
   506 bool StartLogicBridge(char *error, size_t maxlength)
   507 {
   508 	char file[PLATFORM_MAX_PATH];
   509 
   510 	/* Now it's time to load the logic binary */
   511 	g_SMAPI->PathFormat(file,
   512 		sizeof(file),
   513 		"%s/bin/sourcemod.logic." PLATFORM_LIB_EXT,
   514 		g_SourceMod.GetSourceModPath());
   515 
   516 	char myerror[255];
   517 	g_pLogic = g_LibSys.OpenLibrary(file, myerror, sizeof(myerror));
   518 
   519 	if (!g_pLogic)
   520 	{
   521 		if (error && maxlength)
   522 		{
   523 			UTIL_Format(error, maxlength, "failed to load %s: %s", file, myerror);
   524 		}
   525 		return false;
   526 	}
   527 
   528 	LogicLoadFunction llf = (LogicLoadFunction)g_pLogic->GetSymbolAddress("logic_load");
   529 	if (llf == NULL)
   530 	{
   531 		g_pLogic->CloseLibrary();
   532 		if (error && maxlength)
   533 		{
   534 			UTIL_Format(error, maxlength, "could not find logic_load function");
   535 		}
   536 		return false;
   537 	}
   538 
   539 	GetITextParsers getitxt = (GetITextParsers)g_pLogic->GetSymbolAddress("get_textparsers");
   540 	textparsers = getitxt();
   541 
   542 	logic_init_fn = llf(SM_LOGIC_MAGIC);
   543 
   544 	return true;
   545 }
   546 
   547 void ShutdownLogicBridge()
   548 {
   549 	g_pLogic->CloseLibrary();
   550 }
   551