Example #1
0
bool CGameConfig::EnterFile(const char *file, char *error, size_t maxlength)
{
	build_pathname_r(m_CurrentPath, sizeof(m_CurrentPath), "%s/gamedata/%s", get_localinfo("amxx_datadir", "addons/amxmodx/data"), file);

	m_IgnoreLevel = 0;
	m_ShouldBeReadingDefault = true;
	m_ParseState = PSTATE_NONE;

	SMCError err;
	SMCStates state = { 0, 0 };

	if ((err = textparsers->ParseSMCFile(m_CurrentPath, this, &state, error, maxlength)) != SMCError_Okay)
	{
		const char *msg = textparsers->GetSMCErrorString(err);

		AMXXLOG_Error("Error parsing gameconfig file \"%s\":", m_CurrentPath);
		AMXXLOG_Error("Error %d on line %d, col %d: %s", err, state.line, state.col, msg ? msg : "Unknown error");

		if (m_ParseState == PSTATE_GAMEDEFS_CUSTOM)
		{
			m_CustomHandler->ReadSMC_ParseEnd(true, true);
			m_CustomHandler = nullptr;
			m_CustomLevel = 0;
		}

		return false;
	}

	return true;
}
Example #2
0
void BuildPluginFileList(const char *initialdir, CStack<ke::AString *> & files)
{
	char path[255];
#if defined WIN32
	build_pathname_r(path, sizeof(path)-1, "%s/*.ini", initialdir);
	_finddata_t fd;
	intptr_t handle = _findfirst(path, &fd);

	if (handle < 0)
	{
		return;
	}

	while (!_findnext(handle, &fd))
	{
		ParseAndOrAdd(files, fd.name);
	}

	_findclose(handle);
#elif defined(__linux__) || defined(__APPLE__)
	build_pathname_r(path, sizeof(path)-1, "%s/", initialdir);
	struct dirent *ep;
	DIR *dp;

	if ((dp = opendir(path)) == NULL)
	{
		return;
	}

	while ( (ep=readdir(dp)) != NULL )
	{
		ParseAndOrAdd(files, ep->d_name);
	}

	closedir (dp);
#endif
}
Example #3
0
CPluginMngr::CPlugin::CPlugin(int i, const char* p, const char* n, char* e, int d , const char * shortName ) : name(n), title(n)
{
	const char* unk = "unknown";
	
	failcounter = 0;
	title.assign(unk);
	author.assign(unk);
	version.assign(unk);
	
	char file[256];
	char* path = build_pathname_r(file, sizeof(file) - 1, "%s/%s", p, n);

	code = 0;
	memset(&amx, 0, sizeof(AMX));
	int err = load_amxscript(&amx, &code, path, e, d , shortName );
	
	if (err == AMX_ERR_NONE)
	{
		status = ps_running;
	} else {
		status = ps_bad_load;
	}
	
	amx.userdata[UD_FINDPLUGIN] = this;
	paused_fun = 0;
	next = 0;
	id = i;
	
	if (status == ps_running)
	{
		m_PauseFwd = registerSPForwardByName(&amx, "plugin_pause", FP_DONE);
		m_UnpauseFwd = registerSPForwardByName(&amx, "plugin_unpause", FP_DONE);
		
		if (amx.flags & AMX_FLAG_DEBUG)
		{
			m_Debug = true;
		} else {
			m_Debug = false;
		}
	}
}
Example #4
0
CPluginMngr::CPlugin::CPlugin(int i, const char* p, const char* n, char* e, size_t m, int d) : name(n), title(n), m_pNullStringOfs(nullptr), m_pNullVectorOfs(nullptr)
{
	const char* unk = "unknown";

	failcounter = 0;
	title = unk;
	author = unk;
	version = unk;

	char file[PLATFORM_MAX_PATH];
	char* path = build_pathname_r(file, sizeof(file), "%s/%s", p, n);
	code = 0;
	memset(&amx, 0, sizeof(AMX));
	int err = load_amxscript_ex(&amx, &code, path, e, m, d);

	if (err == AMX_ERR_NONE)
	{
		status = ps_running;
	} else {
		status = ps_bad_load;
	}

	amx.userdata[UD_FINDPLUGIN] = this;
	paused_fun = 0;
	next = 0;
	id = i;

	if (status == ps_running)
	{
		m_PauseFwd = registerSPForwardByName(&amx, "plugin_pause", FP_DONE);
		m_UnpauseFwd = registerSPForwardByName(&amx, "plugin_unpause", FP_DONE);

		if (amx.flags & AMX_FLAG_DEBUG)
		{
			m_Debug = true;
		} else {
			m_Debug = false;
		}
	}
}
Example #5
0
bool BinLog::Open()
{
    const char *data = get_localinfo("amxmodx_datadir", "addons/amxmodx/data");
    char path[255];
    build_pathname_r(path, sizeof(path)-1, "%s/binlogs", data);

    if (!DirExists(path))
    {
        mkdir(path
#if defined(__linux__) || defined(__APPLE__)
              , 0755
#endif
             );
        if (!DirExists(path))
            return false;
    }

    char file[255];
    build_pathname_r(file, sizeof(file)-1, "%s/binlogs/lastlog", data);

    unsigned int lastcntr = 0;
    FILE *lastlog = fopen(file, "rb");
    if (lastlog)
    {
        if (fread(&lastcntr, sizeof(int), 1, lastlog) != 1)
            lastcntr = 0;
        fclose(lastlog);
    }
    lastlog = fopen(file, "wb");
    if (lastlog)
    {
        lastcntr++;
        fwrite(&lastcntr, sizeof(int), 1, lastlog);
        fclose(lastlog);
    }
    build_pathname_r(file, sizeof(file)-1, "%s/binlogs/binlog%04d.blg", data, lastcntr);
    m_logfile = file;

    /**
    * it's now safe to create the binary log
    */
    FILE *fp = fopen(m_logfile.chars(), "wb");
    if (!fp)
        return false;

    int magic = BINLOG_MAGIC;
    short vers = BINLOG_VERSION;
    char c = sizeof(time_t);
    fwrite(&magic, sizeof(int), 1, fp);
    fwrite(&vers, sizeof(short), 1, fp);
    fwrite(&c, sizeof(char), 1, fp);

    WritePluginDB(fp);
    fclose(fp);

    m_state = true;

    WriteOp(BinLog_Start, -1);

    return true;
}
Example #6
0
bool CGameConfig::Reparse(char *error, size_t maxlength)
{
	m_Offsets.clear();
	m_OffsetsByClass.clear();
	m_Keys.clear();
	m_Addresses.clear();

	char path[PLATFORM_MAX_PATH];
	const char *dataDir = get_localinfo("amxx_datadir", "addons/amxmodx/data");

	build_pathname_r(path, sizeof(path), "%s/gamedata/%s/master.games.txt", dataDir, m_File);

	if (!g_LibSys.PathExists(path))
	{
		// Single config file without master
		g_LibSys.PathFormat(path, sizeof(path), "%s.txt", m_File);

		if (!EnterFile(path, error, maxlength))
		{
			return false;
		}

		// Allow customizations of default gamedata files
		build_pathname_r(path, sizeof(path), "%s/gamedata/custom/%s.txt", dataDir, m_File);

		if (g_LibSys.PathExists(path))
		{
			g_LibSys.PathFormat(path, sizeof(path), "custom/%s.txt", m_File);

			auto success = EnterFile(path, error, maxlength);

			if (success)
			{
				AMXXLOG_Log("[AMXX] Parsed custom gamedata override file: %s", path);
			}

			return success;
		}
		return true;
	}

	SMCError err;
	SMCStates state = { 0, 0 };

	ke::Vector<ke::AString> fileList;
	MasterReader.m_FileList = &fileList;

	err = textparsers->ParseSMCFile(path, &MasterReader, &state, error, maxlength);

	if (err != SMCError_Okay)
	{
		const char *msg = textparsers->GetSMCErrorString(err);

		AMXXLOG_Error("Error parsing master gameconf file \"%s\":", path);
		AMXXLOG_Error("Error %d on line %d, col %d: %s", err, state.line, state.col, msg ? msg : "Unknown error");

		return false;
	}

	for (size_t i = 0; i < fileList.length(); ++i)
	{
		g_LibSys.PathFormat(path, sizeof(path), "%s/%s", m_File, fileList[i].chars());

		if (!EnterFile(path, error, maxlength))
		{
			return false;
		}
	}

	build_pathname_r(path, sizeof(path), "%s/gamedata/%s/custom", dataDir, m_File);
	CDirectory *customDir = g_LibSys.OpenDirectory(path);

	if (!customDir)
	{
		return true;
	}

	while (customDir->MoreFiles())
	{
		if (!customDir->IsEntryFile())
		{
			customDir->NextEntry();
			continue;
		}

		const char *currentFile = customDir->GetEntryName();

		size_t length = strlen(currentFile);

		if (length > 4 && strcmp(&currentFile[length - 4], ".txt") != 0)
		{
			customDir->NextEntry();
			continue;
		}

		g_LibSys.PathFormat(path, sizeof(path), "%s/custom/%s", m_File, currentFile);

		if (!EnterFile(path, error, maxlength))
		{
			g_LibSys.CloseDirectory(customDir);
			return false;
		}

		AMXXLOG_Log("[AMXX] Parsed custom gamedata override file: %s", path);

		customDir->NextEntry();
	}

	g_LibSys.CloseDirectory(customDir);

	return true;
}
Example #7
0
void CPluginMngr::CALMFromFile(const char *file)
{
	char filename[PLATFORM_MAX_PATH];
	FILE *fp = fopen(build_pathname_r(filename, sizeof(filename), "%s", file), "rt");

	if (!fp)
	{
		return;
	}

	// Find now folder
	char pluginName[256];
	char line[256];
	char rline[256];

	while (!feof(fp))
	{
		fgets(line, sizeof(line)-1, fp);
		if (line[0] == ';' || line[0] == '\n' || line[0] == '\0')
		{
			continue;
		}

		/** quick hack */
		char *ptr = line;
		while (*ptr)
		{
			if (*ptr == ';')
			{
				*ptr = '\0';
			} else {
				ptr++;
			}
		}

		strncopy(rline, line, sizeof(rline));
		UTIL_TrimLeft(rline);
		UTIL_TrimRight(rline);

		pluginName[0] = '\0';
		sscanf(rline, "%s", pluginName);

		/* HACK: see if there's a 'disabled' coming up
		 * new block for scopying flexibility
		 */
		if (1)
		{
			const char *_ptr = rline + strlen(pluginName);
			while (*_ptr != '\0'  && isspace(*_ptr))
			{
				_ptr++;
			}
			if ((*_ptr != '\0') && !strcmp(_ptr, "disabled"))
			{
				ke::AString *pString = new ke::AString(pluginName);
				m_BlockList.push_back(pString);
				continue;
			}
		}

		if (!isalnum(*pluginName))
		{
			continue;
		}

		build_pathname_r(filename, sizeof(filename), "%s/%s", get_localinfo("amxx_pluginsdir", "addons/amxmodx/plugins"), pluginName);

		CacheAndLoadModules(filename);
	}

	fclose(fp);
}
Example #8
0
int CPluginMngr::loadPluginsFromFile(const char* filename, bool warn)
{
	char file[PLATFORM_MAX_PATH];
	FILE *fp = fopen(build_pathname_r(file, sizeof(file), "%s", filename), "rt");

	if (!fp)
	{
		if (warn)
		{
			AMXXLOG_Error("[AMXX] Plugins list not found (file \"%s\")", filename);
		}
		return 1;
	}

	// Find now folder
	char pluginName[256], error[256], debug[256];
	int debugFlag = 0;
	const char *pluginsDir = get_localinfo("amxx_pluginsdir", "addons/amxmodx/plugins");

	char line[512];

	List<ke::AString *>::iterator block_iter;

	while (!feof(fp))
	{
		pluginName[0] = '\0';

		debug[0] = '\0';
		debugFlag = 0;

		line[0] = '\0';
		fgets(line, sizeof(line), fp);

		/** quick hack */
		char *ptr = line;
		while (*ptr)
		{
			if (*ptr == ';')
			{
				*ptr = '\0';
			} else {
				ptr++;
			}
		}
		sscanf(line, "%s %s", pluginName, debug);

		if (!isalnum(*pluginName))
		{
			continue;
		}

		if (isalnum(*debug) && !strcmp(debug, "debug"))
		{
			debugFlag = 1;
		}

		bool skip = false;
		for (block_iter = m_BlockList.begin();
			 block_iter != m_BlockList.end();
			 block_iter++)
		{
			if ((*block_iter)->compare(pluginName) == 0)
			{
				skip = true;
				break;
			}
		}

		if (skip || !strcmp(debug, "disabled"))
		{
			continue;
		}

		if (findPlugin(pluginName) != NULL)
		{
			continue;
		}

		CPlugin* plugin = loadPlugin(pluginsDir, pluginName, error, sizeof(error), debugFlag);

		if (plugin->getStatusCode() == ps_bad_load)
		{
			char errorMsg[255];
			sprintf(errorMsg, "%s (plugin \"%s\")", error, pluginName);
			plugin->setError(errorMsg);
			AMXXLOG_Error("[AMXX] %s", plugin->getError());
		}
		else
		{
			cell addr;
			if (amx_FindPubVar(plugin->getAMX(), "MaxClients", &addr) != AMX_ERR_NOTFOUND)
			{
				*get_amxaddr(plugin->getAMX(), addr) = gpGlobals->maxClients;
			}

			if (amx_FindPubVar(plugin->getAMX(), "MapName", &addr) != AMX_ERR_NOTFOUND)
			{
				set_amxstring(plugin->getAMX(), addr, STRING(gpGlobals->mapname), MAX_MAPNAME_LENGTH - 1);
			}

			if (amx_FindPubVar(plugin->getAMX(), "NULL_STRING", &addr) != AMX_ERR_NOTFOUND)
			{
				plugin->m_pNullStringOfs = get_amxaddr(plugin->getAMX(), addr);
			}

			if (amx_FindPubVar(plugin->getAMX(), "NULL_VECTOR", &addr) != AMX_ERR_NOTFOUND)
			{
				plugin->m_pNullVectorOfs = get_amxaddr(plugin->getAMX(), addr);
			}
		}
	}

	fclose(fp);

	return pCounter;
}
Example #9
0
int CPluginMngr::loadPluginsFromFile(const char* filename, bool warn)
{
	char file[256];
	FILE *fp = fopen(build_pathname_r(file, sizeof(file) - 1, "%s", filename), "rt");

	if (!fp) 
	{
		if (warn)
		{
			AMXXLOG_Error("[AMXX] Plugins list not found (file \"%s\")", filename);
		}
		return 1;
	}
	
	// Find now folder
	char pluginName[256], error[256], debug[256];
	int debugFlag = 0;
	const char *pluginsDir = get_localinfo("amxx_pluginsdir", "addons/amxmodx/plugins");
	
	String line;

	List<String *>::iterator block_iter;

	while (!feof(fp)) 
	{
		pluginName[0] = '\0';
		
		debug[0] = '\0';
		debugFlag = 0;
		
		line.clear();
		line._fread(fp);
		/** quick hack */
		char *ptr = const_cast<char *>(line.c_str());
		while (*ptr)
		{
			if (*ptr == ';')
			{
				*ptr = '\0';
			} else {
				ptr++;
			}
		}
		sscanf(line.c_str(), "%s %s", pluginName, debug);
		
		if (!isalnum(*pluginName))
		{
			continue;
		}

		if (isalnum(*debug) && !strcmp(debug, "debug"))
		{
			debugFlag = 1;
		}

		bool skip = false;
		for (block_iter = m_BlockList.begin();
			 block_iter != m_BlockList.end();
			 block_iter++)
		{
			if ((*block_iter)->compare(pluginName) == 0)
			{
				skip = true;
				break;
			}
		}

		if (skip || !strcmp(debug, "disabled"))
		{
			continue;
		}

		if (findPlugin(pluginName) != NULL)
		{
			continue;
		}

		CPlugin* plugin = loadPlugin(pluginsDir, pluginName, error, debugFlag);
		
		if (plugin->getStatusCode() == ps_bad_load)
		{
			char errorMsg[255];
			sprintf(errorMsg, "%s (plugin \"%s\")", error, pluginName);
			plugin->setError(errorMsg);
			AMXXLOG_Error("[AMXX] %s", plugin->getError());
		}
	}

	fclose(fp);

	return pCounter;
}
Example #10
0
int CPluginMngr::loadPluginsFromDir(const char* dir, bool debug ){
	char pluginName[ 256 ],
		error[ 256 ],
		dirFull[ 256 ];

	char * ext = 0;

	#if defined WIN32
	build_pathname_r( dirFull , sizeof( dirFull ) , "%s\\*" , dir );

	_finddata_t fd;
	intptr_t handle = _findfirst( dirFull , &fd);

	if (handle < 0){
		return 0;
	}

	while (!_findnext(handle, &fd)){
		if ( !strcmp ( fd.name , ".") || !strcmp ( fd.name , "..") ){
		  continue;
		}

       	ext = strrchr( fd.name, '.' );

       	if( !ext || strcmp( ext , ".amxx" ) ){
       		continue;
       	}

       	*ext = '\0';

       	strncpy( pluginName , fd.name , ext - ( fd.name ) );

       	pluginName[ ext - ( fd.name ) ] = '\0';

		if ( findPlugin( pluginName ) != NULL ){
			continue;
		}

		CPlugin* plugin = loadPlugin( dir, fd.name, error, debug , pluginName );
		
		if (plugin->getStatusCode() == ps_bad_load){
			char errorMsg[255];
			sprintf(errorMsg, "%s (plugin \"%s\")", error, pluginName);
			plugin->setError(errorMsg);
			AMXXLOG_Error("[AMXX] %s", plugin->getError());
		}
	}

	_findclose(handle);
#elif defined(__linux__) || defined(__APPLE__)
	build_pathname_r( dirFull , sizeof( dirFull ) , "%s" , dir );
	struct dirent *ep;
	DIR *dp;

	if (( dp = opendir( dirFull ) ) == NULL ){
		return 0;
	}

	while ( ( ep = readdir( dp )) != NULL ){

		if ( !strcmp ( ep -> d_name , ".") || !strcmp ( ep -> d_name , "..") ){
            continue;
		}

       	ext = strrchr( ep -> d_name, '.' );

       	if( !ext || strcmp( ext , ".amxx" ) ){
       		continue;
       	}
       	strncpy( pluginName , ep -> d_name , ext - ( ep -> d_name ) );

       	pluginName[ ext - ( ep -> d_name ) ] = '\0';

		if ( findPlugin( pluginName ) != NULL ){
			continue;
		}

		CPlugin* plugin = loadPlugin( dir, ep -> d_name, error, debug , pluginName );
		
		if (plugin->getStatusCode() == ps_bad_load){
			char errorMsg[255];
			sprintf(errorMsg, "%s (plugin \"%s\")", error, pluginName);
			plugin->setError(errorMsg);
			AMXXLOG_Error("[AMXX] %s", plugin->getError());
		}
	}

	closedir (dp);
#endif

	return pCounter;
}
Example #11
0
// Very	first point	at map load
// Load	AMX	modules	for	new	native functions
// Initialize AMX stuff	and	load it's plugins from plugins.ini list
// Call	precache forward function from plugins
int	C_Spawn(edict_t *pent)
{
	if (g_initialized)
	{
		RETURN_META_VALUE(MRES_IGNORED, 0);
	}

	g_activated = false;
	g_initialized = true;
	g_forcedmodules = false;
	g_forcedsounds = false;

	g_srvindex = IS_DEDICATED_SERVER() ? 0 : 1;

	hostname = CVAR_GET_POINTER("hostname");
	mp_timelimit = CVAR_GET_POINTER("mp_timelimit");

	// Fix for crashing on mods that do not have mp_timelimit
	if (mp_timelimit == NULL)
	{
		static cvar_t timelimit_holder;

		timelimit_holder.name = "mp_timelimit";
		timelimit_holder.string = "0";
		timelimit_holder.flags = 0;
		timelimit_holder.value = 0.0;

		CVAR_REGISTER(&timelimit_holder);

		mp_timelimit = &timelimit_holder;

	}

	g_forwards.clear();

	g_log.MapChange();

	// ###### Initialize task manager
	g_tasksMngr.registerTimers(&gpGlobals->time, &mp_timelimit->value, &g_game_timeleft);

	// ###### Initialize commands prefixes
	g_commands.registerPrefix("amx");
	g_commands.registerPrefix("amxx");
	g_commands.registerPrefix("say");
	g_commands.registerPrefix("admin_");
	g_commands.registerPrefix("sm_");
	g_commands.registerPrefix("cm_");

	// make sure localinfos are set
	get_localinfo("amxx_basedir", "addons/amxmodx");
	get_localinfo("amxx_pluginsdir", "addons/amxmodx/plugins");
	get_localinfo("amxx_modulesdir", "addons/amxmodx/modules");
	get_localinfo("amxx_configsdir", "addons/amxmodx/configs");
	get_localinfo("amxx_customdir", "addons/amxmodx/custom");

	// make sure bcompat localinfos are set
	get_localinfo("amx_basedir", "addons/amxmodx");
	get_localinfo("amx_configdir", "addons/amxmodx/configs");
	get_localinfo("amx_langdir", "addons/amxmodx/data/amxmod-lang");
	get_localinfo("amx_modulesdir", "addons/amxmodx/modules");
	get_localinfo("amx_pluginsdir", "addons/amxmodx/plugins");
	get_localinfo("amx_logdir", "addons/amxmodx/logs");

	FlagMan.LoadFile();

	ArrayHandles.clear();
	TrieHandles.clear();
	TrieSnapshotHandles.clear();
	DataPackHandles.clear();
	TextParsersHandles.clear();
	GameConfigHandle.clear();

	char map_pluginsfile_path[256];
	char prefixed_map_pluginsfile[256];
	char configs_dir[256];

	// ###### Load modules
	loadModules(get_localinfo("amxx_modules", "addons/amxmodx/configs/modules.ini"), PT_ANYTIME);

	get_localinfo_r("amxx_configsdir", "addons/amxmodx/configs", configs_dir, sizeof(configs_dir)-1);
	g_plugins.CALMFromFile(get_localinfo("amxx_plugins", "addons/amxmodx/configs/plugins.ini"));
	LoadExtraPluginsToPCALM(configs_dir);
	char temporaryMap[64], *tmap_ptr;

	ke::SafeSprintf(temporaryMap, sizeof(temporaryMap), "%s", STRING(gpGlobals->mapname));

	prefixed_map_pluginsfile[0] = '\0';
	if ((tmap_ptr = strchr(temporaryMap, '_')) != NULL)
	{
		// this map has a prefix

		*tmap_ptr = '\0';
		ke::SafeSprintf(prefixed_map_pluginsfile,
			sizeof(prefixed_map_pluginsfile),
			"%s/maps/plugins-%s.ini",
			configs_dir,
			temporaryMap);
		g_plugins.CALMFromFile(prefixed_map_pluginsfile);
	}

	ke::SafeSprintf(map_pluginsfile_path,
		sizeof(map_pluginsfile_path),
		"%s/maps/plugins-%s.ini",
		configs_dir,
		STRING(gpGlobals->mapname));
	g_plugins.CALMFromFile(map_pluginsfile_path);

	int loaded = countModules(CountModules_Running); // Call after attachModules so all modules don't have pending stat
	
	// Set some info about amx version and modules
	CVAR_SET_STRING(init_amxmodx_version.name, AMXX_VERSION);
	char buffer[32];
	sprintf(buffer, "%d", loaded);
	CVAR_SET_STRING(init_amxmodx_modules.name, buffer);

	// ###### Load Vault
	char file[255];
	g_vault.setSource(build_pathname_r(file, sizeof(file) - 1, "%s", get_localinfo("amxx_vault", "addons/amxmodx/configs/vault.ini")));
	g_vault.loadVault();

	// ###### Init time and freeze tasks
	g_game_timeleft = g_bmod_dod ? 1.0f : 0.0f;
	g_task_time = gpGlobals->time + 99999.0f;
	g_auth_time = gpGlobals->time + 99999.0f;
#ifdef MEMORY_TEST
	g_next_memreport_time = gpGlobals->time + 99999.0f;
#endif
	g_players_num = 0;

	// Set server flags
	memset(g_players[0].flags, -1, sizeof(g_players[0].flags));

	g_opt_level = atoi(get_localinfo("optimizer", "7"));
	if (!g_opt_level)
		g_opt_level = 7;

	// ###### Load AMX Mod X plugins
	g_plugins.loadPluginsFromFile(get_localinfo("amxx_plugins", "addons/amxmodx/configs/plugins.ini"));
	LoadExtraPluginsFromDir(configs_dir);
	g_plugins.loadPluginsFromFile(map_pluginsfile_path, false);
	if (prefixed_map_pluginsfile[0] != '\0')
	{
		g_plugins.loadPluginsFromFile(prefixed_map_pluginsfile, false);
	}

	g_plugins.Finalize();
	g_plugins.InvalidateCache();

	// Register forwards
	FF_PluginInit = registerForward("plugin_init", ET_IGNORE, FP_DONE);
	FF_ClientCommand = registerForward("client_command", ET_STOP, FP_CELL, FP_DONE);
	FF_ClientConnect = registerForward("client_connect", ET_IGNORE, FP_CELL, FP_DONE);
	FF_ClientDisconnect = registerForward("client_disconnect", ET_IGNORE, FP_CELL, FP_DONE);
	FF_ClientDisconnected = registerForward("client_disconnected", ET_IGNORE, FP_CELL, FP_CELL, FP_ARRAY, FP_CELL, FP_DONE);
	FF_ClientRemove = registerForward("client_remove", ET_IGNORE, FP_CELL, FP_CELL, FP_STRING, FP_DONE);
	FF_ClientInfoChanged = registerForward("client_infochanged", ET_IGNORE, FP_CELL, FP_DONE);
	FF_ClientPutInServer = registerForward("client_putinserver", ET_IGNORE, FP_CELL, FP_DONE);
	FF_PluginCfg = registerForward("plugin_cfg", ET_IGNORE, FP_DONE);
	FF_PluginPrecache = registerForward("plugin_precache", ET_IGNORE, FP_DONE);
	FF_PluginLog = registerForward("plugin_log", ET_STOP, FP_DONE);
	FF_PluginEnd = registerForward("plugin_end", ET_IGNORE, FP_DONE);
	FF_InconsistentFile = registerForward("inconsistent_file", ET_STOP, FP_CELL, FP_STRING, FP_STRINGEX, FP_DONE);
	FF_ClientAuthorized = registerForward("client_authorized", ET_IGNORE, FP_CELL, FP_STRING, FP_DONE);
	FF_ChangeLevel = registerForward("server_changelevel", ET_STOP, FP_STRING, FP_DONE);
	FF_ClientConnectEx = registerForward("client_connectex", ET_STOP, FP_CELL, FP_STRING, FP_STRING, FP_ARRAY, FP_DONE);

	CoreCfg.OnAmxxInitialized();

#if defined BINLOG_ENABLED
	if (!g_BinLog.Open())
	{
		LOG_ERROR(PLID, "Binary log failed to open.");
	}
	g_binlog_level = atoi(get_localinfo("bin_logging", "17"));
	g_binlog_maxsize = atoi(get_localinfo("max_binlog_size", "20"));
#endif

	modules_callPluginsLoaded();

	TypeConversion.init();

	// ###### Call precache forward function
	g_dontprecache = false;
	executeForwards(FF_PluginPrecache);
	g_dontprecache = true;

	for (CList<ForceObject>::iterator a = g_forcegeneric.begin(); a; ++a)
	{
		PRECACHE_GENERIC((char*)(*a).getFilename());
		ENGINE_FORCE_UNMODIFIED((*a).getForceType(),
		(*a).getMin(), (*a).getMax(), (*a).getFilename());
	}

	RETURN_META_VALUE(MRES_IGNORED, 0);
}