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