core/sourcemod.cpp
author David Anderson <dvander@alliedmods.net>
Mon Jan 01 19:50:16 2007 +0000 (2007-01-01)
changeset 252 ce166c465bad
parent 214 4d97709c9376
child 255 236589ed0c92
permissions -rw-r--r--
added usage of the Handle System to begin experimenting
     1 #include <stdio.h>
     2 #include "sourcemod.h"
     3 #include "sourcemm_api.h"
     4 #include "systems/LibrarySys.h"
     5 #include "vm/sp_vm_engine.h"
     6 #include <sh_string.h>
     7 #include "PluginSys.h"
     8 #include "ShareSys.h"
     9 
    10 SH_DECL_HOOK6(IServerGameDLL, LevelInit, SH_NOATTRIB, false, bool, const char *, const char *, const char *, const char *, bool, bool);
    11 
    12 SourcePawnEngine g_SourcePawn;
    13 SourceModBase g_SourceMod;
    14 
    15 ILibrary *g_pJIT = NULL;
    16 SourceHook::String g_BaseDir;
    17 ISourcePawnEngine *g_pSourcePawn = &g_SourcePawn;
    18 IVirtualMachine *g_pVM;
    19 IdentityToken_t *g_pCoreIdent = NULL;
    20 
    21 typedef int (*GIVEENGINEPOINTER)(ISourcePawnEngine *);
    22 typedef unsigned int (*GETEXPORTCOUNT)();
    23 typedef IVirtualMachine *(*GETEXPORT)(unsigned int);
    24 typedef void (*NOTIFYSHUTDOWN)();
    25 
    26 void ShutdownJIT()
    27 {
    28 	NOTIFYSHUTDOWN notify = (NOTIFYSHUTDOWN)g_pJIT->GetSymbolAddress("NotifyShutdown");
    29 	if (notify)
    30 	{
    31 		notify();
    32 	}
    33 
    34 	g_pJIT->CloseLibrary();
    35 }
    36 
    37 SourceModBase::SourceModBase()
    38 {
    39 	m_IsMapLoading = false;
    40 }
    41 
    42 bool SourceModBase::InitializeSourceMod(char *error, size_t err_max, bool late)
    43 {
    44 	g_BaseDir.assign(g_SMAPI->GetBaseDir());
    45 	g_LibSys.PathFormat(m_SMBaseDir, sizeof(m_SMBaseDir), "%s/addons/sourcemod", g_BaseDir.c_str());
    46 
    47 	/* Attempt to load the JIT! */
    48 	char file[PLATFORM_MAX_PATH];
    49 	char myerror[255];
    50 	g_SMAPI->PathFormat(file, sizeof(file), "%s/bin/sourcepawn.jit.x86.%s",
    51 		GetSMBaseDir(),
    52 		PLATFORM_LIB_EXT
    53 		);
    54 
    55 	g_pJIT = g_LibSys.OpenLibrary(file, myerror, sizeof(myerror));
    56 	if (!g_pJIT)
    57 	{
    58 		if (error && err_max)
    59 		{
    60 			snprintf(error, err_max, "%s (failed to load bin/sourcepawn.jit.x86.%s)", 
    61 				myerror,
    62 				PLATFORM_LIB_EXT);
    63 		}
    64 		return false;
    65 	}
    66 
    67 	int err;
    68 	GIVEENGINEPOINTER jit_init = (GIVEENGINEPOINTER)g_pJIT->GetSymbolAddress("GiveEnginePointer");
    69 	if (!jit_init)
    70 	{
    71 		ShutdownJIT();
    72 		if (error && err_max)
    73 		{
    74 			snprintf(error, err_max, "Failed to find GiveEnginePointer in JIT!");
    75 		}
    76 		return false;
    77 	}
    78 
    79 	if ((err=jit_init(g_pSourcePawn)) != 0)
    80 	{
    81 		ShutdownJIT();
    82 		if (error && err_max)
    83 		{
    84 			snprintf(error, err_max, "GiveEnginePointer returned %d in the JIT", err);
    85 		}
    86 		return false;
    87 	}
    88 
    89 	GETEXPORTCOUNT jit_getnum = (GETEXPORTCOUNT)g_pJIT->GetSymbolAddress("GetExportCount");
    90 	GETEXPORT jit_get = (GETEXPORT)g_pJIT->GetSymbolAddress("GetExport");
    91 	if (!jit_get)
    92 	{
    93 		ShutdownJIT();
    94 		if (error && err_max)
    95 		{
    96 			snprintf(error, err_max, "JIT is missing a necessary export!");
    97 		}
    98 		return false;
    99 	}
   100 
   101 	unsigned int num = jit_getnum();
   102 	if (!num || ((g_pVM=jit_get(0)) == NULL))
   103 	{
   104 		ShutdownJIT();
   105 		if (error && err_max)
   106 		{
   107 			snprintf(error, err_max, "JIT did not export any virtual machines!");
   108 		}
   109 		return false;
   110 	}
   111 
   112 	unsigned int api = g_pVM->GetAPIVersion();
   113 	if (api != SOURCEPAWN_VM_API_VERSION)
   114 	{
   115 		ShutdownJIT();
   116 		if (error && err_max)
   117 		{
   118 			snprintf(error, err_max, "JIT is not a compatible version");
   119 		}
   120 		return false;
   121 	}
   122 
   123 	StartSourceMod(late);
   124 
   125 	return true;
   126 }
   127 
   128 void SourceModBase::StartSourceMod(bool late)
   129 {
   130 	/* First initialize the global hooks we need */
   131 	SH_ADD_HOOK_MEMFUNC(IServerGameDLL, LevelInit, gamedll, this, &SourceModBase::LevelInit, false);
   132 
   133 	m_IsLateLoadInMap = late;
   134 
   135 	/* Notify! */
   136 	SMGlobalClass *pBase = SMGlobalClass::head;
   137 	while (pBase)
   138 	{
   139 		pBase->OnSourceModStartup(m_IsLateLoadInMap);
   140 		pBase = pBase->m_pGlobalClassNext;
   141 	}
   142 
   143 	/* Make the global core identity */
   144 	g_pCoreIdent = g_ShareSys.CreateCoreIdentity();
   145 
   146 	/* Notify! */
   147 	pBase = SMGlobalClass::head;
   148 	while (pBase)
   149 	{
   150 		pBase->OnSourceModAllInitialized();
   151 		pBase = pBase->m_pGlobalClassNext;
   152 	}
   153 
   154 	/* If we're late, automatically load plugins now */
   155 	if (late)
   156 	{
   157 		DoGlobalPluginLoads();
   158 	}
   159 }
   160 
   161 bool SourceModBase::LevelInit(char const *pMapName, char const *pMapEntities, char const *pOldLevel, char const *pLandmarkName, bool loadGame, bool background)
   162 {
   163 	m_IsMapLoading = true;
   164 	m_IsLateLoadInMap = false;
   165 
   166 	DoGlobalPluginLoads();
   167 
   168 	m_IsMapLoading = false;
   169 
   170 	RETURN_META_VALUE(MRES_IGNORED, true);
   171 }
   172 
   173 void SourceModBase::DoGlobalPluginLoads()
   174 {
   175 	char config_path[PLATFORM_MAX_PATH];
   176 	char plugins_path[PLATFORM_MAX_PATH];
   177 
   178 	g_SMAPI->PathFormat(config_path, 
   179 		sizeof(config_path),
   180 		"%s/configs/plugin_settings.cfg",
   181 		GetSMBaseDir());
   182 	g_SMAPI->PathFormat(plugins_path,
   183 		sizeof(plugins_path),
   184 		"%s/plugins",
   185 		GetSMBaseDir());
   186 
   187 	g_PluginSys.LoadAll_FirstPass(config_path, plugins_path);
   188 
   189 	/* No modules yet, it's safe to call this from here */
   190 	g_PluginSys.LoadAll_SecondPass();
   191 }
   192 
   193 bool SourceModBase::IsLateLoadInMap()
   194 {
   195 	return m_IsLateLoadInMap;
   196 }
   197 
   198 const char *SourceModBase::GetSMBaseDir()
   199 {
   200 	return m_SMBaseDir;
   201 }
   202 
   203 SMGlobalClass *SMGlobalClass::head = NULL;
   204 
   205 SMGlobalClass::SMGlobalClass()
   206 {
   207 	m_pGlobalClassNext = SMGlobalClass::head;
   208 	SMGlobalClass::head = this;
   209 }