core/sourcemod.cpp
author David Anderson <dvander@alliedmods.net>
Thu Jan 25 06:19:17 2007 +0000 (2007-01-25)
changeset 347 aa2dfce8bff6
parent 345 df0b05b4f50d
child 370 d3a484f98f6d
permissions -rw-r--r--
added an easier format string Function
changed normal log names to be more consistent
added logging natives
dvander@160
     1
#include <stdio.h>
dvander@160
     2
#include "sourcemod.h"
dvander@160
     3
#include "sourcemm_api.h"
dvander@160
     4
#include "systems/LibrarySys.h"
dvander@160
     5
#include "vm/sp_vm_engine.h"
dvander@160
     6
#include <sh_string.h>
dvander@176
     7
#include "PluginSys.h"
dvander@252
     8
#include "ShareSys.h"
faluco@281
     9
#include "CLogger.h"
dvander@315
    10
#include "ExtensionSys.h"
dvander@340
    11
#include "AdminCache.h"
dvander@347
    12
#include "sm_stringutil.h"
dvander@160
    13
dvander@209
    14
SH_DECL_HOOK6(IServerGameDLL, LevelInit, SH_NOATTRIB, false, bool, const char *, const char *, const char *, const char *, bool, bool);
faluco@333
    15
SH_DECL_HOOK0_void(IServerGameDLL, LevelShutdown, SH_NOATTRIB, false);
dvander@209
    16
dvander@160
    17
SourcePawnEngine g_SourcePawn;
dvander@160
    18
SourceModBase g_SourceMod;
dvander@160
    19
dvander@160
    20
ILibrary *g_pJIT = NULL;
dvander@160
    21
SourceHook::String g_BaseDir;
dvander@160
    22
ISourcePawnEngine *g_pSourcePawn = &g_SourcePawn;
dvander@160
    23
IVirtualMachine *g_pVM;
dvander@252
    24
IdentityToken_t *g_pCoreIdent = NULL;
dvander@160
    25
dvander@160
    26
typedef int (*GIVEENGINEPOINTER)(ISourcePawnEngine *);
dvander@160
    27
typedef unsigned int (*GETEXPORTCOUNT)();
dvander@160
    28
typedef IVirtualMachine *(*GETEXPORT)(unsigned int);
dvander@160
    29
typedef void (*NOTIFYSHUTDOWN)();
dvander@160
    30
dvander@160
    31
void ShutdownJIT()
dvander@160
    32
{
dvander@160
    33
	NOTIFYSHUTDOWN notify = (NOTIFYSHUTDOWN)g_pJIT->GetSymbolAddress("NotifyShutdown");
dvander@160
    34
	if (notify)
dvander@160
    35
	{
dvander@160
    36
		notify();
dvander@160
    37
	}
dvander@160
    38
dvander@160
    39
	g_pJIT->CloseLibrary();
dvander@160
    40
}
dvander@160
    41
dvander@209
    42
SourceModBase::SourceModBase()
dvander@209
    43
{
dvander@209
    44
	m_IsMapLoading = false;
faluco@333
    45
	m_ExecPluginReload = false;
dvander@209
    46
}
dvander@209
    47
dvander@160
    48
bool SourceModBase::InitializeSourceMod(char *error, size_t err_max, bool late)
dvander@160
    49
{
dvander@160
    50
	g_BaseDir.assign(g_SMAPI->GetBaseDir());
dvander@209
    51
	g_LibSys.PathFormat(m_SMBaseDir, sizeof(m_SMBaseDir), "%s/addons/sourcemod", g_BaseDir.c_str());
dvander@345
    52
	g_LibSys.PathFormat(m_SMRelDir, sizeof(m_SMRelDir), "addons/sourcemod");
dvander@160
    53
dvander@160
    54
	/* Attempt to load the JIT! */
dvander@160
    55
	char file[PLATFORM_MAX_PATH];
dvander@160
    56
	char myerror[255];
dvander@209
    57
	g_SMAPI->PathFormat(file, sizeof(file), "%s/bin/sourcepawn.jit.x86.%s",
dvander@317
    58
		GetSourceModPath(),
dvander@160
    59
		PLATFORM_LIB_EXT
dvander@160
    60
		);
dvander@160
    61
dvander@160
    62
	g_pJIT = g_LibSys.OpenLibrary(file, myerror, sizeof(myerror));
dvander@160
    63
	if (!g_pJIT)
dvander@160
    64
	{
dvander@160
    65
		if (error && err_max)
dvander@160
    66
		{
dvander@160
    67
			snprintf(error, err_max, "%s (failed to load bin/sourcepawn.jit.x86.%s)", 
dvander@160
    68
				myerror,
dvander@160
    69
				PLATFORM_LIB_EXT);
dvander@160
    70
		}
dvander@160
    71
		return false;
dvander@160
    72
	}
dvander@160
    73
dvander@160
    74
	int err;
dvander@160
    75
	GIVEENGINEPOINTER jit_init = (GIVEENGINEPOINTER)g_pJIT->GetSymbolAddress("GiveEnginePointer");
dvander@160
    76
	if (!jit_init)
dvander@160
    77
	{
dvander@160
    78
		ShutdownJIT();
dvander@160
    79
		if (error && err_max)
dvander@160
    80
		{
dvander@160
    81
			snprintf(error, err_max, "Failed to find GiveEnginePointer in JIT!");
dvander@160
    82
		}
dvander@160
    83
		return false;
dvander@160
    84
	}
dvander@160
    85
dvander@160
    86
	if ((err=jit_init(g_pSourcePawn)) != 0)
dvander@160
    87
	{
dvander@160
    88
		ShutdownJIT();
dvander@160
    89
		if (error && err_max)
dvander@160
    90
		{
dvander@160
    91
			snprintf(error, err_max, "GiveEnginePointer returned %d in the JIT", err);
dvander@160
    92
		}
dvander@160
    93
		return false;
dvander@160
    94
	}
dvander@160
    95
dvander@160
    96
	GETEXPORTCOUNT jit_getnum = (GETEXPORTCOUNT)g_pJIT->GetSymbolAddress("GetExportCount");
dvander@160
    97
	GETEXPORT jit_get = (GETEXPORT)g_pJIT->GetSymbolAddress("GetExport");
dvander@160
    98
	if (!jit_get)
dvander@160
    99
	{
dvander@160
   100
		ShutdownJIT();
dvander@160
   101
		if (error && err_max)
dvander@160
   102
		{
dvander@160
   103
			snprintf(error, err_max, "JIT is missing a necessary export!");
dvander@160
   104
		}
dvander@160
   105
		return false;
dvander@160
   106
	}
dvander@160
   107
dvander@160
   108
	unsigned int num = jit_getnum();
dvander@160
   109
	if (!num || ((g_pVM=jit_get(0)) == NULL))
dvander@160
   110
	{
dvander@160
   111
		ShutdownJIT();
dvander@160
   112
		if (error && err_max)
dvander@160
   113
		{
dvander@160
   114
			snprintf(error, err_max, "JIT did not export any virtual machines!");
dvander@160
   115
		}
dvander@160
   116
		return false;
dvander@160
   117
	}
dvander@160
   118
dvander@176
   119
	unsigned int api = g_pVM->GetAPIVersion();
dvander@176
   120
	if (api != SOURCEPAWN_VM_API_VERSION)
dvander@176
   121
	{
dvander@176
   122
		ShutdownJIT();
dvander@176
   123
		if (error && err_max)
dvander@176
   124
		{
dvander@176
   125
			snprintf(error, err_max, "JIT is not a compatible version");
dvander@176
   126
		}
dvander@176
   127
		return false;
dvander@176
   128
	}
dvander@176
   129
dvander@209
   130
	StartSourceMod(late);
dvander@176
   131
dvander@160
   132
	return true;
dvander@160
   133
}
dvander@209
   134
dvander@209
   135
void SourceModBase::StartSourceMod(bool late)
dvander@209
   136
{
dvander@209
   137
	/* First initialize the global hooks we need */
dvander@209
   138
	SH_ADD_HOOK_MEMFUNC(IServerGameDLL, LevelInit, gamedll, this, &SourceModBase::LevelInit, false);
faluco@333
   139
	SH_ADD_HOOK_MEMFUNC(IServerGameDLL, LevelShutdown, gamedll, this, &SourceModBase::LevelShutdown, false);
dvander@209
   140
dvander@214
   141
	/* Notify! */
dvander@214
   142
	SMGlobalClass *pBase = SMGlobalClass::head;
dvander@214
   143
	while (pBase)
dvander@214
   144
	{
dvander@315
   145
		pBase->OnSourceModStartup(false);
dvander@214
   146
		pBase = pBase->m_pGlobalClassNext;
dvander@214
   147
	}
dvander@214
   148
dvander@252
   149
	/* Make the global core identity */
dvander@252
   150
	g_pCoreIdent = g_ShareSys.CreateCoreIdentity();
dvander@252
   151
dvander@214
   152
	/* Notify! */
dvander@214
   153
	pBase = SMGlobalClass::head;
dvander@214
   154
	while (pBase)
dvander@214
   155
	{
dvander@214
   156
		pBase->OnSourceModAllInitialized();
dvander@214
   157
		pBase = pBase->m_pGlobalClassNext;
dvander@214
   158
	}
dvander@317
   159
dvander@317
   160
	/* Add us now... */
dvander@317
   161
	g_ShareSys.AddInterface(NULL, this);
dvander@209
   162
}
dvander@209
   163
dvander@209
   164
bool SourceModBase::LevelInit(char const *pMapName, char const *pMapEntities, char const *pOldLevel, char const *pLandmarkName, bool loadGame, bool background)
dvander@209
   165
{
dvander@209
   166
	m_IsMapLoading = true;
faluco@333
   167
	m_ExecPluginReload = true;
dvander@209
   168
faluco@281
   169
	g_Logger.MapChange(pMapName);
faluco@281
   170
dvander@209
   171
	DoGlobalPluginLoads();
dvander@209
   172
dvander@209
   173
	m_IsMapLoading = false;
dvander@209
   174
dvander@340
   175
	g_Admins.DumpAdminCache(ADMIN_CACHE_GROUPS|ADMIN_CACHE_ADMINS|ADMIN_CACHE_OVERRIDES, true);
dvander@340
   176
dvander@209
   177
	RETURN_META_VALUE(MRES_IGNORED, true);
dvander@209
   178
}
dvander@209
   179
faluco@333
   180
void SourceModBase::LevelShutdown()
faluco@333
   181
{
faluco@333
   182
	if (m_ExecPluginReload)
faluco@333
   183
	{
faluco@333
   184
		g_PluginSys.ReloadOrUnloadPlugins();
faluco@333
   185
		m_ExecPluginReload = false;
faluco@333
   186
	}
faluco@333
   187
}
faluco@333
   188
dvander@315
   189
bool SourceModBase::IsMapLoading()
dvander@315
   190
{
dvander@315
   191
	return m_IsMapLoading;
dvander@315
   192
}
dvander@315
   193
dvander@209
   194
void SourceModBase::DoGlobalPluginLoads()
dvander@209
   195
{
dvander@209
   196
	char config_path[PLATFORM_MAX_PATH];
dvander@209
   197
	char plugins_path[PLATFORM_MAX_PATH];
dvander@209
   198
dvander@317
   199
	BuildPath(Path_SM, config_path, 
dvander@209
   200
		sizeof(config_path),
dvander@317
   201
		"configs/plugin_settings.cfg");
dvander@317
   202
	BuildPath(Path_SM, plugins_path,
dvander@209
   203
		sizeof(plugins_path),
dvander@317
   204
		"plugins");
dvander@209
   205
dvander@315
   206
	/* Run the first pass */
dvander@211
   207
	g_PluginSys.LoadAll_FirstPass(config_path, plugins_path);
dvander@213
   208
dvander@315
   209
	/* Mark any extensions as loaded */
dvander@315
   210
	g_Extensions.MarkAllLoaded();
dvander@315
   211
dvander@213
   212
	/* No modules yet, it's safe to call this from here */
dvander@213
   213
	g_PluginSys.LoadAll_SecondPass();
dvander@315
   214
dvander@315
   215
	/* Re-mark any extensions as loaded */
dvander@315
   216
	g_Extensions.MarkAllLoaded();
dvander@211
   217
}
dvander@211
   218
dvander@317
   219
size_t SourceModBase::BuildPath(PathType type, char *buffer, size_t maxlength, char *format, ...)
dvander@317
   220
{
dvander@317
   221
	char _buffer[PLATFORM_MAX_PATH+1];
dvander@317
   222
	va_list ap;
dvander@317
   223
dvander@317
   224
	va_start(ap, format);
dvander@317
   225
	vsnprintf(_buffer, PLATFORM_MAX_PATH, format, ap);
dvander@317
   226
	va_end(ap);
dvander@317
   227
dvander@317
   228
	const char *base = NULL;
dvander@317
   229
	if (type == Path_Game)
dvander@317
   230
	{
dvander@317
   231
		base = GetModPath();
dvander@317
   232
	} else if (type == Path_SM) {
dvander@317
   233
		base = GetSourceModPath();
dvander@345
   234
	} else if (type == Path_SM_Rel) {
dvander@345
   235
		base = m_SMRelDir;
dvander@317
   236
	}
dvander@317
   237
dvander@317
   238
	if (base)
dvander@317
   239
	{
dvander@317
   240
		return g_LibSys.PathFormat(buffer, maxlength, "%s/%s", base, _buffer);
dvander@317
   241
	} else {
dvander@317
   242
		return g_LibSys.PathFormat(buffer, maxlength, "%s", _buffer);
dvander@317
   243
	}
dvander@317
   244
}
dvander@317
   245
faluco@289
   246
void SourceModBase::CloseSourceMod()
faluco@289
   247
{
faluco@289
   248
	/* Notify! */
faluco@289
   249
	SMGlobalClass *pBase = SMGlobalClass::head;
faluco@289
   250
	while (pBase)
faluco@289
   251
	{
faluco@289
   252
		pBase->OnSourceModShutdown();
faluco@289
   253
		pBase = pBase->m_pGlobalClassNext;
faluco@289
   254
	}
faluco@289
   255
faluco@289
   256
	/* Notify! */
faluco@289
   257
	pBase = SMGlobalClass::head;
faluco@289
   258
	while (pBase)
faluco@289
   259
	{
faluco@289
   260
		pBase->OnSourceModAllShutdown();
faluco@289
   261
		pBase = pBase->m_pGlobalClassNext;
faluco@289
   262
	}
faluco@289
   263
faluco@333
   264
	SH_REMOVE_HOOK_MEMFUNC(IServerGameDLL, LevelInit, gamedll, this, &SourceModBase::LevelInit, false);
faluco@333
   265
	SH_REMOVE_HOOK_MEMFUNC(IServerGameDLL, LevelShutdown, gamedll, this, &SourceModBase::LevelShutdown, false);
faluco@333
   266
faluco@289
   267
	/* Rest In Peace */
faluco@289
   268
	ShutdownJIT();
faluco@289
   269
}
faluco@289
   270
dvander@317
   271
void SourceModBase::LogMessage(IExtension *pExt, const char *format, ...)
dvander@317
   272
{
dvander@317
   273
	IExtensionInterface *pAPI = pExt->GetAPI();
dvander@317
   274
	const char *tag = pAPI->GetExtensionTag();
dvander@317
   275
	char buffer[2048];
dvander@317
   276
	va_list ap;
dvander@317
   277
dvander@317
   278
	va_start(ap, format);
dvander@317
   279
	vsnprintf(buffer, sizeof(buffer), format, ap);
dvander@317
   280
	va_end(ap);
dvander@317
   281
dvander@317
   282
	if (tag)
dvander@317
   283
	{
dvander@317
   284
		g_Logger.LogMessage("[%s] %s", tag, buffer);
dvander@317
   285
	} else {
dvander@317
   286
		g_Logger.LogMessage("%s", buffer);
dvander@317
   287
	}
dvander@317
   288
}
dvander@317
   289
dvander@317
   290
void SourceModBase::LogError(IExtension *pExt, const char *format, ...)
dvander@317
   291
{
dvander@317
   292
	IExtensionInterface *pAPI = pExt->GetAPI();
dvander@317
   293
	const char *tag = pAPI->GetExtensionTag();
dvander@317
   294
	char buffer[2048];
dvander@317
   295
	va_list ap;
dvander@317
   296
dvander@317
   297
	va_start(ap, format);
dvander@317
   298
	vsnprintf(buffer, sizeof(buffer), format, ap);
dvander@317
   299
	va_end(ap);
dvander@317
   300
dvander@317
   301
	if (tag)
dvander@317
   302
	{
dvander@317
   303
		g_Logger.LogError("[%s] %s", tag, buffer);
dvander@317
   304
	} else {
dvander@317
   305
		g_Logger.LogError("%s", buffer);
dvander@317
   306
	}
dvander@317
   307
}
dvander@317
   308
dvander@347
   309
size_t SourceModBase::FormatString(char *buffer, size_t maxlength, IPluginContext *pContext, const cell_t *params, unsigned int param)
dvander@347
   310
{
dvander@347
   311
	char *fmt;
dvander@347
   312
dvander@347
   313
	pContext->LocalToString(params[param], &fmt);
dvander@347
   314
dvander@347
   315
	int lparam = ++param;
dvander@347
   316
dvander@347
   317
	return atcprintf(buffer, maxlength, fmt, pContext, params, &lparam);
dvander@347
   318
}
dvander@347
   319
dvander@317
   320
const char *SourceModBase::GetSourceModPath()
dvander@209
   321
{
dvander@209
   322
	return m_SMBaseDir;
dvander@209
   323
}
dvander@211
   324
dvander@317
   325
const char *SourceModBase::GetModPath()
dvander@255
   326
{
dvander@255
   327
	return g_BaseDir.c_str();
dvander@255
   328
}
dvander@255
   329
dvander@211
   330
SMGlobalClass *SMGlobalClass::head = NULL;
dvander@211
   331
dvander@211
   332
SMGlobalClass::SMGlobalClass()
dvander@211
   333
{
dvander@211
   334
	m_pGlobalClassNext = SMGlobalClass::head;
dvander@211
   335
	SMGlobalClass::head = this;
dvander@211
   336
}