core/logic_bridge.cpp
author Kyle Sanderson <kyle.leet@gmail.com>
Mon Aug 12 00:44:22 2013 +0100 (2013-08-12)
changeset 3995 e94dfd569130
parent 3961 0dc477c29792
child 4029 cf8bdfcf6503
permissions -rw-r--r--
Fixed various memory issues. (bug 5766, 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_HL2DM
   218 	return "hl2dm";
   219 #elif SOURCE_ENGINE == SE_DODS
   220 	return "dods";
   221 #elif SOURCE_ENGINE == SE_TF2
   222 	return "tf2";
   223 #elif SOURCE_ENGINE == SE_LEFT4DEAD
   224 	return "left4dead";
   225 #elif SOURCE_ENGINE == SE_NUCLEARDAWN
   226 	return "nucleardawn";
   227 #elif SOURCE_ENGINE == SE_LEFT4DEAD2
   228 	return "left4dead2";
   229 #elif SOURCE_ENGINE == SE_ALIENSWARM
   230 	return "alienswarm";
   231 #elif SOURCE_ENGINE == SE_PORTAL2
   232 	return "portal2";
   233 #elif SOURCE_ENGINE == SE_CSGO
   234 	return "csgo";
   235 #elif SOURCE_ENGINE == SE_DOTA
   236 	return "dota";
   237 #endif
   238 }
   239 
   240 static bool symbols_are_hidden()
   241 {
   242 #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)
   243 	return true;
   244 #else
   245 	return false;
   246 #endif
   247 }
   248 
   249 static const char* get_core_config_value(const char* key)
   250 {
   251 	return g_CoreConfig.GetCoreConfigValue(key);
   252 }
   253 
   254 static bool is_map_loading()
   255 {
   256 	return g_SourceMod.IsMapLoading();
   257 }
   258 
   259 static bool is_map_running()
   260 {
   261 	return g_SourceMod.IsMapRunning();
   262 }
   263 
   264 int read_cmd_argc(const CCommand &args)
   265 {
   266 	return args.ArgC();
   267 }
   268 
   269 static const char *read_cmd_arg(const CCommand &args, int arg)
   270 {
   271 	return args.Arg(arg);
   272 }
   273 
   274 static int load_mms_plugin(const char *file, bool *ok, char *error, size_t maxlength)
   275 {
   276 	bool ignore_already;
   277 	PluginId id = g_pMMPlugins->Load(file, g_PLID, ignore_already, error, maxlength);
   278 
   279 	Pl_Status status;
   280 
   281 #ifndef METAMOD_PLAPI_VERSION
   282 	const char *filep;
   283 	PluginId source;
   284 #endif
   285 
   286 	if (!id || (
   287 #ifndef METAMOD_PLAPI_VERSION
   288 		g_pMMPlugins->Query(id, filep, status, source)
   289 #else
   290 		g_pMMPlugins->Query(id, NULL, &status, NULL)
   291 #endif
   292 		&& status < Pl_Paused))
   293 	{
   294 		*ok = false;
   295 	}
   296 	else
   297 	{
   298 		*ok = true;
   299 	}
   300 
   301 	return id;
   302 }
   303 
   304 static void unload_mms_plugin(int id)
   305 {
   306 	char ignore[255];
   307 	g_pMMPlugins->Unload(id, true, ignore, sizeof(ignore));
   308 }
   309 
   310 void do_global_plugin_loads()
   311 {
   312 	g_SourceMod.DoGlobalPluginLoads();
   313 }
   314 
   315 #if defined METAMOD_PLAPI_VERSION
   316 #if SOURCE_ENGINE == SE_LEFT4DEAD
   317 #define GAMEFIX "2.l4d"
   318 #elif SOURCE_ENGINE == SE_LEFT4DEAD2
   319 #define GAMEFIX "2.l4d2"
   320 #elif SOURCE_ENGINE == SE_ALIENSWARM
   321 #define GAMEFIX "2.swarm"
   322 #elif SOURCE_ENGINE == SE_ORANGEBOX
   323 #define GAMEFIX "2.ep2"
   324 #elif SOURCE_ENGINE == SE_BLOODYGOODTIME
   325 #define GAMEFIX "2.bgt"
   326 #elif SOURCE_ENGINE == SE_EYE
   327 #define GAMEFIX "2.eye"
   328 #elif SOURCE_ENGINE == SE_CSS
   329 #define GAMEFIX "2.css"
   330 #elif SOURCE_ENGINE == SE_HL2DM
   331 #define GAMEFIX "2.hl2dm"
   332 #elif SOURCE_ENGINE == SE_DODS
   333 #define GAMEFIX "2.dods"
   334 #elif SOURCE_ENGINE == SE_TF2
   335 #define GAMEFIX "2.tf2"
   336 #elif SOURCE_ENGINE == SE_DARKMESSIAH
   337 #define GAMEFIX "2.darkm"
   338 #elif SOURCE_ENGINE == SE_PORTAL2
   339 #define GAMEFIX "2.portal2"
   340 #elif SOURCE_ENGINE == SE_CSGO
   341 #define GAMEFIX "2.csgo"
   342 #elif SOURCE_ENGINE == SE_DOTA
   343 #define GAMEFIX "2.dota"
   344 #else
   345 #define GAMEFIX "2.ep1"
   346 #endif //(SOURCE_ENGINE == SE_LEFT4DEAD) || (SOURCE_ENGINE == SE_LEFT4DEAD2)
   347 #else  //METAMOD_PLAPI_VERSION
   348 #define GAMEFIX "1.ep1"
   349 #endif //METAMOD_PLAPI_VERSION
   350 
   351 static ServerGlobals serverGlobals;
   352 
   353 static sm_core_t core_bridge =
   354 {
   355 	/* Objects */
   356 	&g_SourceMod,
   357 	&g_LibSys,
   358 	reinterpret_cast<IVEngineServer*>(&logic_engine),
   359 	reinterpret_cast<IFileSystem*>(&logic_filesystem),
   360 	&g_RootMenu,
   361 	&g_Forwards,
   362 	&g_Timers,
   363 	&g_Players,
   364 	&g_Admins,
   365 	&g_HL2,
   366 	&g_pSourcePawn,
   367 	&g_pSourcePawn2,
   368 	/* Functions */
   369 	find_convar,
   370 	strncopy,
   371 	UTIL_TrimWhitespace,
   372 	log_error,
   373 	log_fatal,
   374 	log_message,
   375 	log_to_file,
   376 	log_to_game,
   377 	file_exists,
   378 	get_cvar_string,
   379 	UTIL_Format,
   380 	UTIL_FormatArgs,
   381 	gnprintf,
   382 	atcprintf,
   383 	get_game_name,
   384 	get_game_description,
   385 	get_source_engine_name,
   386 	symbols_are_hidden,
   387 	get_core_config_value,
   388 	is_map_loading,
   389 	is_map_running,
   390 	read_cmd_argc,
   391 	read_cmd_arg,
   392 	load_mms_plugin,
   393 	unload_mms_plugin,
   394 	do_global_plugin_loads,
   395 	SM_AreConfigsExecuted,
   396 	SM_ExecuteForPlugin,
   397 	GAMEFIX,
   398 	&serverGlobals
   399 };
   400 
   401 void InitLogicBridge()
   402 {
   403 	serverGlobals.universalTime = g_pUniversalTime;
   404 	serverGlobals.frametime = &gpGlobals->frametime;
   405 	serverGlobals.interval_per_tick = &gpGlobals->interval_per_tick;
   406 
   407 	core_bridge.engineFactory = (void *)g_SMAPI->GetEngineFactory(false);
   408 	core_bridge.serverFactory = (void *)g_SMAPI->GetServerFactory(false);
   409 
   410 	ILibrary *mmlib;
   411 	char path[PLATFORM_MAX_PATH];
   412 
   413 	g_LibSys.PathFormat(path, sizeof(path), "%s/bin/matchmaking_ds%s.%s", g_SMAPI->GetBaseDir(), MATCHMAKINGDS_SUFFIX, MATCHMAKINGDS_EXT);
   414 
   415 	if ((mmlib = g_LibSys.OpenLibrary(path, NULL, 0)))
   416 	{
   417 		core_bridge.matchmakingDSFactory = mmlib->GetSymbolAddress("CreateInterface");
   418 		mmlib->CloseLibrary();
   419 	}
   420 	
   421 	logic_init_fn(&core_bridge, &logicore);
   422 
   423 	/* Add SMGlobalClass instances */
   424 	SMGlobalClass* glob = SMGlobalClass::head;
   425 	while (glob->m_pGlobalClassNext != NULL)
   426 	{
   427 		glob = glob->m_pGlobalClassNext;
   428 	}
   429 	assert(glob->m_pGlobalClassNext == NULL);
   430 	glob->m_pGlobalClassNext = logicore.head;
   431 
   432 	g_pThreader = logicore.threader;
   433 	g_pSourcePawn2->SetProfiler(logicore.profiler);
   434 	translator = logicore.translator;
   435 	scripts = logicore.scripts;
   436 	sharesys = logicore.sharesys;
   437 	extsys = logicore.extsys;
   438 	g_pCoreIdent = logicore.core_ident;
   439 	handlesys = logicore.handlesys;
   440 }
   441 
   442 bool StartLogicBridge(char *error, size_t maxlength)
   443 {
   444 	char file[PLATFORM_MAX_PATH];
   445 
   446 	/* Now it's time to load the logic binary */
   447 	g_SMAPI->PathFormat(file,
   448 		sizeof(file),
   449 		"%s/bin/sourcemod.logic." PLATFORM_LIB_EXT,
   450 		g_SourceMod.GetSourceModPath());
   451 
   452 	char myerror[255];
   453 	g_pLogic = g_LibSys.OpenLibrary(file, myerror, sizeof(myerror));
   454 
   455 	if (!g_pLogic)
   456 	{
   457 		if (error && maxlength)
   458 		{
   459 			UTIL_Format(error, maxlength, "failed to load %s: %s", file, myerror);
   460 		}
   461 		return false;
   462 	}
   463 
   464 	LogicLoadFunction llf = (LogicLoadFunction)g_pLogic->GetSymbolAddress("logic_load");
   465 	if (llf == NULL)
   466 	{
   467 		g_pLogic->CloseLibrary();
   468 		if (error && maxlength)
   469 		{
   470 			UTIL_Format(error, maxlength, "could not find logic_load function");
   471 		}
   472 		return false;
   473 	}
   474 
   475 	GetITextParsers getitxt = (GetITextParsers)g_pLogic->GetSymbolAddress("get_textparsers");
   476 	textparsers = getitxt();
   477 
   478 	logic_init_fn = llf(SM_LOGIC_MAGIC);
   479 
   480 	return true;
   481 }
   482 
   483 void ShutdownLogicBridge()
   484 {
   485 	g_pLogic->CloseLibrary();
   486 }
   487