core/logic_bridge.cpp
author Ryan Stecker <voidedweasel@gmail.com>
Wed Jul 03 23:14:55 2013 -0400 (2013-07-03)
changeset 3929 0bc0ffdb2eba
parent 3899 fd4ec50a0d6c
child 3961 0dc477c29792
permissions -rw-r--r--
Fixed ReadMapList not seeing maps in all valveFS paths (bug 5715, r=asherkin).
     1 /**
     2  * vim: set ts=4 sw=4 :
     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 "ForwardSys.h"
    43 #include "TimerSys.h"
    44 #include "logic_bridge.h"
    45 #include "PlayerManager.h"
    46 #include "AdminCache.h"
    47 #include "HalfLife2.h"
    48 #include "CoreConfig.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 
    88 class VEngineServer_Logic : public IVEngineServer_Logic
    89 {
    90 public:
    91 	virtual bool IsMapValid(const char *map)
    92 	{
    93 		return !!engine->IsMapValid(map);
    94 	}
    95 
    96 	virtual void ServerCommand(const char *cmd)
    97 	{
    98 		engine->ServerCommand(cmd);
    99 	}
   100 };
   101 
   102 static VEngineServer_Logic logic_engine;
   103 
   104 
   105 class VFileSystem_Logic : public IFileSystem_Logic
   106 {
   107 public:
   108 	const char *FindFirstEx(const char *pWildCard, const char *pPathID, FileFindHandle_t *pHandle)
   109 	{
   110 		return filesystem->FindFirstEx(pWildCard, pPathID, pHandle);
   111 	}
   112 	const char *FindNext(FileFindHandle_t handle)
   113 	{
   114 		return filesystem->FindNext(handle);
   115 	}
   116 	void FindClose(FileFindHandle_t handle)
   117 	{
   118 		filesystem->FindClose(handle);
   119 	}
   120 };
   121 
   122 static VFileSystem_Logic logic_filesystem;
   123 
   124 
   125 static ConVar *find_convar(const char *name)
   126 {
   127 	return icvar->FindVar(name);
   128 }
   129 
   130 static void log_error(const char *fmt, ...)
   131 {
   132 	va_list ap;
   133 
   134 	va_start(ap, fmt);
   135 	g_Logger.LogErrorEx(fmt, ap);
   136 	va_end(ap);
   137 }
   138 
   139 static void log_fatal(const char *fmt, ...)
   140 {
   141 	va_list ap;
   142 
   143 	va_start(ap, fmt);
   144 	g_Logger.LogFatalEx(fmt, ap);
   145 	va_end(ap);
   146 }
   147 
   148 static void log_message(const char *fmt, ...)
   149 {
   150 	va_list ap;
   151 	va_start(ap, fmt);
   152 	g_Logger.LogMessageEx(fmt, ap);
   153 	va_end(ap);
   154 }
   155 
   156 static void log_to_file(FILE *fp, const char *fmt, ...)
   157 {
   158 	va_list ap;
   159 	va_start(ap, fmt);
   160 	g_Logger.LogToOpenFileEx(fp, fmt, ap);
   161 	va_end(ap);
   162 }
   163 
   164 static void log_to_game(const char *message)
   165 {
   166 	Engine_LogPrintWrapper(message);
   167 }
   168 
   169 static bool file_exists(const char *path)
   170 {
   171 	return basefilesystem->FileExists(path);
   172 }
   173 
   174 static const char *get_cvar_string(ConVar* cvar)
   175 {
   176 	return cvar->GetString();
   177 }
   178 
   179 static bool get_game_name(char *buffer, size_t maxlength)
   180 {
   181 	KeyValues *pGameInfo = new KeyValues("GameInfo");
   182 	if (g_HL2.KVLoadFromFile(pGameInfo, basefilesystem, "gameinfo.txt"))
   183 	{
   184 		const char *str;
   185 		if ((str = pGameInfo->GetString("game", NULL)) != NULL)
   186 		{
   187 			strncopy(buffer, str, maxlength);
   188 			return true;
   189 		}
   190 	}
   191 	pGameInfo->deleteThis();
   192 	return false;
   193 }
   194 
   195 static const char *get_game_description()
   196 {
   197 	return SERVER_CALL(GetGameDescription)();
   198 }
   199 
   200 static const char *get_source_engine_name()
   201 {
   202 #if !defined SOURCE_ENGINE
   203 # error "Unknown engine type"
   204 #endif
   205 #if SOURCE_ENGINE == SE_EPISODEONE
   206 	return "original";
   207 #elif SOURCE_ENGINE == SE_DARKMESSIAH
   208 	return "darkmessiah";
   209 #elif SOURCE_ENGINE == SE_ORANGEBOX
   210 	return "orangebox";
   211 #elif SOURCE_ENGINE == SE_BLOODYGOODTIME
   212 	return "bloodygoodtime";
   213 #elif SOURCE_ENGINE == SE_EYE
   214 	return "eye";
   215 #elif SOURCE_ENGINE == SE_CSS
   216 	return "css";
   217 #elif SOURCE_ENGINE == SE_ORANGEBOXVALVE
   218 	return "orangebox_valve";
   219 #elif SOURCE_ENGINE == SE_LEFT4DEAD
   220 	return "left4dead";
   221 #elif SOURCE_ENGINE == SE_LEFT4DEAD2
   222 	return "left4dead2";
   223 #elif SOURCE_ENGINE == SE_ALIENSWARM
   224 	return "alienswarm";
   225 #elif SOURCE_ENGINE == SE_PORTAL2
   226 	return "portal2";
   227 #elif SOURCE_ENGINE == SE_CSGO
   228 	return "csgo";
   229 #elif SOURCE_ENGINE == SE_DOTA
   230 	return "dota";
   231 #endif
   232 }
   233 
   234 static bool symbols_are_hidden()
   235 {
   236 #if (SOURCE_ENGINE == SE_CSS) || (SOURCE_ENGINE == SE_ORANGEBOXVALVE) || (SOURCE_ENGINE == SE_LEFT4DEAD) || (SOURCE_ENGINE == SE_LEFT4DEAD2) || (SOURCE_ENGINE == SE_CSGO) || (SOURCE_ENGINE == SE_DOTA)
   237 	return true;
   238 #else
   239 	return false;
   240 #endif
   241 }
   242 
   243 static const char* get_core_config_value(const char* key)
   244 {
   245 	return g_CoreConfig.GetCoreConfigValue(key);
   246 }
   247 
   248 static bool is_map_loading()
   249 {
   250 	return g_SourceMod.IsMapLoading();
   251 }
   252 
   253 static bool is_map_running()
   254 {
   255 	return g_SourceMod.IsMapRunning();
   256 }
   257 
   258 int read_cmd_argc(const CCommand &args)
   259 {
   260 	return args.ArgC();
   261 }
   262 
   263 static const char *read_cmd_arg(const CCommand &args, int arg)
   264 {
   265 	return args.Arg(arg);
   266 }
   267 
   268 static int load_mms_plugin(const char *file, bool *ok, char *error, size_t maxlength)
   269 {
   270 	bool ignore_already;
   271 	PluginId id = g_pMMPlugins->Load(file, g_PLID, ignore_already, error, maxlength);
   272 
   273 	Pl_Status status;
   274 
   275 #ifndef METAMOD_PLAPI_VERSION
   276 	const char *filep;
   277 	PluginId source;
   278 #endif
   279 
   280 	if (!id || (
   281 #ifndef METAMOD_PLAPI_VERSION
   282 		g_pMMPlugins->Query(id, filep, status, source)
   283 #else
   284 		g_pMMPlugins->Query(id, NULL, &status, NULL)
   285 #endif
   286 		&& status < Pl_Paused))
   287 	{
   288 		*ok = false;
   289 	}
   290 	else
   291 	{
   292 		*ok = true;
   293 	}
   294 
   295 	return id;
   296 }
   297 
   298 static void unload_mms_plugin(int id)
   299 {
   300 	char ignore[255];
   301 	g_pMMPlugins->Unload(id, true, ignore, sizeof(ignore));
   302 }
   303 
   304 void do_global_plugin_loads()
   305 {
   306 	g_SourceMod.DoGlobalPluginLoads();
   307 }
   308 
   309 #if defined METAMOD_PLAPI_VERSION
   310 #if SOURCE_ENGINE == SE_LEFT4DEAD
   311 #define GAMEFIX "2.l4d"
   312 #elif SOURCE_ENGINE == SE_LEFT4DEAD2
   313 #define GAMEFIX "2.l4d2"
   314 #elif SOURCE_ENGINE == SE_ALIENSWARM
   315 #define GAMEFIX "2.swarm"
   316 #elif SOURCE_ENGINE == SE_ORANGEBOX
   317 #define GAMEFIX "2.ep2"
   318 #elif SOURCE_ENGINE == SE_BLOODYGOODTIME
   319 #define GAMEFIX "2.bgt"
   320 #elif SOURCE_ENGINE == SE_EYE
   321 #define GAMEFIX "2.eye"
   322 #elif SOURCE_ENGINE == SE_CSS
   323 #define GAMEFIX "2.css"
   324 #elif SOURCE_ENGINE == SE_ORANGEBOXVALVE
   325 #define GAMEFIX "2.ep2v"
   326 #elif SOURCE_ENGINE == SE_DARKMESSIAH
   327 #define GAMEFIX "2.darkm"
   328 #elif SOURCE_ENGINE == SE_PORTAL2
   329 #define GAMEFIX "2.portal2"
   330 #elif SOURCE_ENGINE == SE_CSGO
   331 #define GAMEFIX "2.csgo"
   332 #elif SOURCE_ENGINE == SE_DOTA
   333 #define GAMEFIX "2.dota"
   334 #else
   335 #define GAMEFIX "2.ep1"
   336 #endif //(SOURCE_ENGINE == SE_LEFT4DEAD) || (SOURCE_ENGINE == SE_LEFT4DEAD2)
   337 #else  //METAMOD_PLAPI_VERSION
   338 #define GAMEFIX "1.ep1"
   339 #endif //METAMOD_PLAPI_VERSION
   340 
   341 static ServerGlobals serverGlobals;
   342 
   343 static sm_core_t core_bridge =
   344 {
   345 	/* Objects */
   346 	&g_SourceMod,
   347 	&g_LibSys,
   348 	reinterpret_cast<IVEngineServer*>(&logic_engine),
   349 	reinterpret_cast<IFileSystem*>(&logic_filesystem),
   350 	&g_RootMenu,
   351 	&g_Forwards,
   352 	&g_Timers,
   353 	&g_Players,
   354 	&g_Admins,
   355 	&g_HL2,
   356 	&g_pSourcePawn,
   357 	&g_pSourcePawn2,
   358 	/* Functions */
   359 	find_convar,
   360 	strncopy,
   361 	UTIL_TrimWhitespace,
   362 	log_error,
   363 	log_fatal,
   364 	log_message,
   365 	log_to_file,
   366 	log_to_game,
   367 	file_exists,
   368 	get_cvar_string,
   369 	UTIL_Format,
   370 	UTIL_FormatArgs,
   371 	gnprintf,
   372 	atcprintf,
   373 	get_game_name,
   374 	get_game_description,
   375 	get_source_engine_name,
   376 	symbols_are_hidden,
   377 	get_core_config_value,
   378 	is_map_loading,
   379 	is_map_running,
   380 	read_cmd_argc,
   381 	read_cmd_arg,
   382 	load_mms_plugin,
   383 	unload_mms_plugin,
   384 	do_global_plugin_loads,
   385 	SM_AreConfigsExecuted,
   386 	SM_ExecuteForPlugin,
   387 	GAMEFIX,
   388 	&serverGlobals
   389 };
   390 
   391 void InitLogicBridge()
   392 {
   393 	serverGlobals.universalTime = g_pUniversalTime;
   394 	serverGlobals.frametime = &gpGlobals->frametime;
   395 	serverGlobals.interval_per_tick = &gpGlobals->interval_per_tick;
   396 
   397 	core_bridge.engineFactory = (void *)g_SMAPI->GetEngineFactory(false);
   398 	core_bridge.serverFactory = (void *)g_SMAPI->GetServerFactory(false);
   399 
   400 	ILibrary *mmlib;
   401 	char path[PLATFORM_MAX_PATH];
   402 
   403 	g_LibSys.PathFormat(path, sizeof(path), "%s/bin/matchmaking_ds%s.%s", g_SMAPI->GetBaseDir(), MATCHMAKINGDS_SUFFIX, MATCHMAKINGDS_EXT);
   404 
   405 	if ((mmlib = g_LibSys.OpenLibrary(path, NULL, 0)))
   406 	{
   407 		core_bridge.matchmakingDSFactory = mmlib->GetSymbolAddress("CreateInterface");
   408 		mmlib->CloseLibrary();
   409 	}
   410 	
   411 	logic_init_fn(&core_bridge, &logicore);
   412 
   413 	/* Add SMGlobalClass instances */
   414 	SMGlobalClass* glob = SMGlobalClass::head;
   415 	while (glob->m_pGlobalClassNext != NULL)
   416 	{
   417 		glob = glob->m_pGlobalClassNext;
   418 	}
   419 	assert(glob->m_pGlobalClassNext == NULL);
   420 	glob->m_pGlobalClassNext = logicore.head;
   421 
   422 	g_pThreader = logicore.threader;
   423 	g_pSourcePawn2->SetProfiler(logicore.profiler);
   424 	translator = logicore.translator;
   425 	scripts = logicore.scripts;
   426 	sharesys = logicore.sharesys;
   427 	extsys = logicore.extsys;
   428 	g_pCoreIdent = logicore.core_ident;
   429 	handlesys = logicore.handlesys;
   430 }
   431 
   432 bool StartLogicBridge(char *error, size_t maxlength)
   433 {
   434 	char file[PLATFORM_MAX_PATH];
   435 
   436 	/* Now it's time to load the logic binary */
   437 	g_SMAPI->PathFormat(file,
   438 		sizeof(file),
   439 		"%s/bin/sourcemod.logic." PLATFORM_LIB_EXT,
   440 		g_SourceMod.GetSourceModPath());
   441 
   442 	char myerror[255];
   443 	g_pLogic = g_LibSys.OpenLibrary(file, myerror, sizeof(myerror));
   444 
   445 	if (!g_pLogic)
   446 	{
   447 		if (error && maxlength)
   448 		{
   449 			UTIL_Format(error, maxlength, "failed to load %s: %s", file, myerror);
   450 		}
   451 		return false;
   452 	}
   453 
   454 	LogicLoadFunction llf = (LogicLoadFunction)g_pLogic->GetSymbolAddress("logic_load");
   455 	if (llf == NULL)
   456 	{
   457 		g_pLogic->CloseLibrary();
   458 		if (error && maxlength)
   459 		{
   460 			UTIL_Format(error, maxlength, "could not find logic_load function");
   461 		}
   462 		return false;
   463 	}
   464 
   465 	GetITextParsers getitxt = (GetITextParsers)g_pLogic->GetSymbolAddress("get_textparsers");
   466 	textparsers = getitxt();
   467 
   468 	logic_init_fn = llf(SM_LOGIC_MAGIC);
   469 
   470 	return true;
   471 }
   472 
   473 void ShutdownLogicBridge()
   474 {
   475 	g_pLogic->CloseLibrary();
   476 }
   477