core/logic_bridge.cpp
author Scott Ehlert <ds@alliedmods.net>
Mon Mar 03 05:20:40 2014 -0600 (2014-03-03)
changeset 4272 8b39aa02b05b
parent 4199 6e0c63e83c8a
child 4301 5a9c242fa868
permissions -rw-r--r--
Add gamedata for EntityFactoryDictionary and IServer for Dota 2 on Linux (bug 6068, r=psychonic).
     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_LEFT4DEAD2
   251 	return "left4dead2";
   252 #elif SOURCE_ENGINE == SE_ALIENSWARM
   253 	return "alienswarm";
   254 #elif SOURCE_ENGINE == SE_PORTAL2
   255 	return "portal2";
   256 #elif SOURCE_ENGINE == SE_BLADE
   257 	return "blade";
   258 #elif SOURCE_ENGINE == SE_INSURGENCY
   259 	return "insurgency";
   260 #elif SOURCE_ENGINE == SE_CSGO
   261 	return "csgo";
   262 #elif SOURCE_ENGINE == SE_DOTA
   263 	return "dota";
   264 #endif
   265 }
   266 
   267 static bool symbols_are_hidden()
   268 {
   269 #if (SOURCE_ENGINE == SE_CSS)            \
   270 	|| (SOURCE_ENGINE == SE_HL2DM)       \
   271 	|| (SOURCE_ENGINE == SE_DODS)        \
   272 	|| (SOURCE_ENGINE == SE_SDK2013)     \
   273 	|| (SOURCE_ENGINE == SE_TF2)         \
   274 	|| (SOURCE_ENGINE == SE_LEFT4DEAD)   \
   275 	|| (SOURCE_ENGINE == SE_NUCLEARDAWN) \
   276 	|| (SOURCE_ENGINE == SE_LEFT4DEAD2)  \
   277 	|| (SOURCE_ENGINE == SE_INSURGENCY)  \
   278 	|| (SOURCE_ENGINE == SE_BLADE)       \
   279 	|| (SOURCE_ENGINE == SE_CSGO)        \
   280 	|| (SOURCE_ENGINE == SE_DOTA)
   281 	return true;
   282 #else
   283 	return false;
   284 #endif
   285 }
   286 
   287 static const char* get_core_config_value(const char* key)
   288 {
   289 	return g_CoreConfig.GetCoreConfigValue(key);
   290 }
   291 
   292 static bool is_map_loading()
   293 {
   294 	return g_SourceMod.IsMapLoading();
   295 }
   296 
   297 static bool is_map_running()
   298 {
   299 	return g_SourceMod.IsMapRunning();
   300 }
   301 
   302 static DatabaseInfo keyvalues_to_dbinfo(KeyValues *kv)
   303 {
   304 	DatabaseInfo info;
   305 	info.database = kv->GetString("database", "");
   306 	info.driver = kv->GetString("driver", "default");
   307 	info.host = kv->GetString("host", "");
   308 	info.maxTimeout = kv->GetInt("timeout", 0);
   309 	info.pass = kv->GetString("pass", "");
   310 	info.port = kv->GetInt("port", 0);
   311 	info.user = kv->GetString("user", "");
   312 	return info;
   313 }
   314 
   315 int read_cmd_argc(const CCommand &args)
   316 {
   317 	return args.ArgC();
   318 }
   319 
   320 static const char *read_cmd_arg(const CCommand &args, int arg)
   321 {
   322 	return args.Arg(arg);
   323 }
   324 
   325 static int load_mms_plugin(const char *file, bool *ok, char *error, size_t maxlength)
   326 {
   327 	bool ignore_already;
   328 	PluginId id = g_pMMPlugins->Load(file, g_PLID, ignore_already, error, maxlength);
   329 
   330 	Pl_Status status;
   331 
   332 #ifndef METAMOD_PLAPI_VERSION
   333 	const char *filep;
   334 	PluginId source;
   335 #endif
   336 
   337 	if (!id || (
   338 #ifndef METAMOD_PLAPI_VERSION
   339 		g_pMMPlugins->Query(id, filep, status, source)
   340 #else
   341 		g_pMMPlugins->Query(id, NULL, &status, NULL)
   342 #endif
   343 		&& status < Pl_Paused))
   344 	{
   345 		*ok = false;
   346 	}
   347 	else
   348 	{
   349 		*ok = true;
   350 	}
   351 
   352 	return id;
   353 }
   354 
   355 static void unload_mms_plugin(int id)
   356 {
   357 	char ignore[255];
   358 	g_pMMPlugins->Unload(id, true, ignore, sizeof(ignore));
   359 }
   360 
   361 void do_global_plugin_loads()
   362 {
   363 	g_SourceMod.DoGlobalPluginLoads();
   364 }
   365 
   366 #if defined METAMOD_PLAPI_VERSION
   367 #if SOURCE_ENGINE == SE_LEFT4DEAD
   368 #define GAMEFIX "2.l4d"
   369 #elif SOURCE_ENGINE == SE_LEFT4DEAD2
   370 #define GAMEFIX "2.l4d2"
   371 #elif SOURCE_ENGINE == SE_ALIENSWARM
   372 #define GAMEFIX "2.swarm"
   373 #elif SOURCE_ENGINE == SE_ORANGEBOX
   374 #define GAMEFIX "2.ep2"
   375 #elif SOURCE_ENGINE == SE_BLOODYGOODTIME
   376 #define GAMEFIX "2.bgt"
   377 #elif SOURCE_ENGINE == SE_EYE
   378 #define GAMEFIX "2.eye"
   379 #elif SOURCE_ENGINE == SE_CSS
   380 #define GAMEFIX "2.css"
   381 #elif SOURCE_ENGINE == SE_HL2DM
   382 #define GAMEFIX "2.hl2dm"
   383 #elif SOURCE_ENGINE == SE_DODS
   384 #define GAMEFIX "2.dods"
   385 #elif SOURCE_ENGINE == SE_SDK2013
   386 #define GAMEFIX "2.sdk2013"
   387 #elif SOURCE_ENGINE == SE_TF2
   388 #define GAMEFIX "2.tf2"
   389 #elif SOURCE_ENGINE == SE_DARKMESSIAH
   390 #define GAMEFIX "2.darkm"
   391 #elif SOURCE_ENGINE == SE_PORTAL2
   392 #define GAMEFIX "2.portal2"
   393 #elif SOURCE_ENGINE == SE_BLADE
   394 #define GAMEFIX "2.blade"
   395 #elif SOURCE_ENGINE == SE_INSURGENCY
   396 #define GAMEFIX "2.insurgency"
   397 #elif SOURCE_ENGINE == SE_CSGO
   398 #define GAMEFIX "2.csgo"
   399 #elif SOURCE_ENGINE == SE_DOTA
   400 #define GAMEFIX "2.dota"
   401 #else
   402 #define GAMEFIX "2.ep1"
   403 #endif //(SOURCE_ENGINE == SE_LEFT4DEAD) || (SOURCE_ENGINE == SE_LEFT4DEAD2)
   404 #else  //METAMOD_PLAPI_VERSION
   405 #define GAMEFIX "1.ep1"
   406 #endif //METAMOD_PLAPI_VERSION
   407 
   408 static ServerGlobals serverGlobals;
   409 
   410 static sm_core_t core_bridge =
   411 {
   412 	/* Objects */
   413 	&g_SourceMod,
   414 	&g_LibSys,
   415 	reinterpret_cast<IVEngineServer*>(&logic_engine),
   416 	reinterpret_cast<IFileSystem*>(&logic_filesystem),
   417 	&g_RootMenu,
   418 	&g_Timers,
   419 	&g_Players,
   420 	&g_Admins,
   421 	&g_HL2,
   422 	&g_pSourcePawn,
   423 	&g_pSourcePawn2,
   424 	/* Functions */
   425 	find_convar,
   426 	strncopy,
   427 	UTIL_TrimWhitespace,
   428 	log_error,
   429 	log_fatal,
   430 	log_message,
   431 	log_to_file,
   432 	log_to_game,
   433 	get_cvar_string,
   434 	UTIL_Format,
   435 	UTIL_FormatArgs,
   436 	gnprintf,
   437 	atcprintf,
   438 	get_game_name,
   439 	get_game_description,
   440 	get_source_engine_name,
   441 	symbols_are_hidden,
   442 	get_core_config_value,
   443 	is_map_loading,
   444 	is_map_running,
   445 	read_cmd_argc,
   446 	read_cmd_arg,
   447 	load_mms_plugin,
   448 	unload_mms_plugin,
   449 	do_global_plugin_loads,
   450 	SM_AreConfigsExecuted,
   451 	SM_ExecuteForPlugin,
   452 	keyvalues_to_dbinfo,
   453 	GAMEFIX,
   454 	&serverGlobals
   455 };
   456 
   457 void InitLogicBridge()
   458 {
   459 	serverGlobals.universalTime = g_pUniversalTime;
   460 	serverGlobals.frametime = &gpGlobals->frametime;
   461 	serverGlobals.interval_per_tick = &gpGlobals->interval_per_tick;
   462 
   463 	core_bridge.engineFactory = (void *)g_SMAPI->GetEngineFactory(false);
   464 	core_bridge.serverFactory = (void *)g_SMAPI->GetServerFactory(false);
   465 	core_bridge.listeners = SMGlobalClass::head;
   466 
   467 	ILibrary *mmlib;
   468 	char path[PLATFORM_MAX_PATH];
   469 
   470 	g_LibSys.PathFormat(path, sizeof(path), "%s/bin/matchmaking_ds%s.%s", g_SMAPI->GetBaseDir(), MATCHMAKINGDS_SUFFIX, MATCHMAKINGDS_EXT);
   471 
   472 	if ((mmlib = g_LibSys.OpenLibrary(path, NULL, 0)))
   473 	{
   474 		core_bridge.matchmakingDSFactory = mmlib->GetSymbolAddress("CreateInterface");
   475 		mmlib->CloseLibrary();
   476 	}
   477 	
   478 	logic_init_fn(&core_bridge, &logicore);
   479 
   480 	/* Add SMGlobalClass instances */
   481 	SMGlobalClass* glob = SMGlobalClass::head;
   482 	while (glob->m_pGlobalClassNext != NULL)
   483 	{
   484 		glob = glob->m_pGlobalClassNext;
   485 	}
   486 	assert(glob->m_pGlobalClassNext == NULL);
   487 	glob->m_pGlobalClassNext = logicore.head;
   488 
   489 	g_pThreader = logicore.threader;
   490 	g_pSourcePawn2->SetProfiler(logicore.profiler);
   491 	translator = logicore.translator;
   492 	scripts = logicore.scripts;
   493 	sharesys = logicore.sharesys;
   494 	extsys = logicore.extsys;
   495 	g_pCoreIdent = logicore.core_ident;
   496 	handlesys = logicore.handlesys;
   497 	forwardsys = logicore.forwardsys;
   498 }
   499 
   500 bool StartLogicBridge(char *error, size_t maxlength)
   501 {
   502 	char file[PLATFORM_MAX_PATH];
   503 
   504 	/* Now it's time to load the logic binary */
   505 	g_SMAPI->PathFormat(file,
   506 		sizeof(file),
   507 		"%s/bin/sourcemod.logic." PLATFORM_LIB_EXT,
   508 		g_SourceMod.GetSourceModPath());
   509 
   510 	char myerror[255];
   511 	g_pLogic = g_LibSys.OpenLibrary(file, myerror, sizeof(myerror));
   512 
   513 	if (!g_pLogic)
   514 	{
   515 		if (error && maxlength)
   516 		{
   517 			UTIL_Format(error, maxlength, "failed to load %s: %s", file, myerror);
   518 		}
   519 		return false;
   520 	}
   521 
   522 	LogicLoadFunction llf = (LogicLoadFunction)g_pLogic->GetSymbolAddress("logic_load");
   523 	if (llf == NULL)
   524 	{
   525 		g_pLogic->CloseLibrary();
   526 		if (error && maxlength)
   527 		{
   528 			UTIL_Format(error, maxlength, "could not find logic_load function");
   529 		}
   530 		return false;
   531 	}
   532 
   533 	GetITextParsers getitxt = (GetITextParsers)g_pLogic->GetSymbolAddress("get_textparsers");
   534 	textparsers = getitxt();
   535 
   536 	logic_init_fn = llf(SM_LOGIC_MAGIC);
   537 
   538 	return true;
   539 }
   540 
   541 void ShutdownLogicBridge()
   542 {
   543 	g_pLogic->CloseLibrary();
   544 }
   545