Merge.
authorScott Ehlert <ds@alliedmods.net>
Wed Feb 18 02:30:21 2009 -0600 (2009-02-18)
changeset 25846972eb067f48
parent 2583 d3b2571c378b
parent 2582 81a9781157c7
child 2585 92495cc13d1a
Merge.
core/CoreConfig.cpp
core/GameConfigs.cpp
     1.1 --- a/configs/core.cfg	Wed Feb 18 02:19:22 2009 -0600
     1.2 +++ b/configs/core.cfg	Wed Feb 18 02:30:21 2009 -0600
     1.3 @@ -5,14 +5,6 @@
     1.4  "Core"
     1.5  {
     1.6  	/**
     1.7 -	 * Relative path to SourceMod's base directory. This is relative to the game/mod directory.
     1.8 -	 * Only change this if you have installed SourceMod in a non-default location.
     1.9 -	 *
    1.10 -	 * The default value is "addons/sourcemod"
    1.11 -	 */
    1.12 -	"BasePath"		"addons/sourcemod"
    1.13 -	
    1.14 -	/**
    1.15  	 * This option determines if SourceMod logging is enabled.
    1.16  	 *
    1.17  	 * "on"		- Logging is enabled (default)
    1.18 @@ -105,6 +97,12 @@
    1.19  	"ForceRestartAfterUpdate"	"no"
    1.20  
    1.21  	/**
    1.22 +	 * URL to use for retrieving update information.
    1.23 +	 * SSL is not yet supported.
    1.24 +	 */
    1.25 +	"AutoUpdateURL"				"http://www.sourcemod.net/update/"
    1.26 +
    1.27 +	/**
    1.28  	 * Whether to show debug spew.  
    1.29  	 * Currently this will log details about the gamedata updating process.
    1.30  	 */
     2.1 --- a/core/CoreConfig.cpp	Wed Feb 18 02:19:22 2009 -0600
     2.2 +++ b/core/CoreConfig.cpp	Wed Feb 18 02:30:21 2009 -0600
     2.3 @@ -79,9 +79,7 @@
     2.4  
     2.5  	const char *arg = cmd.Arg(1);
     2.6  
     2.7 -	if (!g_bServerExecd 
     2.8 -		&& arg != NULL 
     2.9 -		&& strcmp(arg, g_ServerCfgFile->GetString()) == 0)
    2.10 +	if (!g_bServerExecd && arg != NULL && strcmp(arg, g_ServerCfgFile->GetString()) == 0)
    2.11  	{
    2.12  		g_bGotTrigger = true;
    2.13  	}
    2.14 @@ -103,8 +101,7 @@
    2.15  
    2.16  void CheckAndFinalizeConfigs()
    2.17  {
    2.18 -	if ((g_bServerExecd || g_ServerCfgFile == NULL) 
    2.19 -		&& g_bGotServerStart)
    2.20 +	if ((g_bServerExecd || g_ServerCfgFile == NULL) && g_bGotServerStart)
    2.21  	{
    2.22  #if SOURCE_ENGINE >= SE_ORANGEBOX
    2.23          g_PendingInternalPush = true;
    2.24 @@ -122,6 +119,14 @@
    2.25  	g_pOnAutoConfigsBuffered = g_Forwards.CreateForward("OnAutoConfigsBuffered", ET_Ignore, 0, NULL);
    2.26  }
    2.27  
    2.28 +CoreConfig::CoreConfig() : m_Strings(512)
    2.29 +{
    2.30 +}
    2.31 +
    2.32 +CoreConfig::~CoreConfig()
    2.33 +{
    2.34 +}
    2.35 +
    2.36  void CoreConfig::OnSourceModShutdown()
    2.37  {
    2.38  	g_RootMenu.RemoveRootConsoleCommand("config", this);
    2.39 @@ -218,6 +223,10 @@
    2.40  	/* Format path to config file */
    2.41  	g_LibSys.PathFormat(filePath, sizeof(filePath), "%s/%s", g_SourceMod.GetGamePath(), corecfg);
    2.42  
    2.43 +	/* Reset cached key values */
    2.44 +	m_KeyValues.clear();
    2.45 +	m_Strings.Reset();
    2.46 +
    2.47  	/* Parse config file */
    2.48  	if ((err=textparsers->ParseFile_SMC(filePath, this, NULL)) != SMCError_Okay)
    2.49  	{
    2.50 @@ -256,9 +265,21 @@
    2.51  		pBase = pBase->m_pGlobalClassNext;
    2.52  	}
    2.53  
    2.54 +	m_KeyValues.replace(option, m_Strings.AddString(value));
    2.55 +
    2.56  	return ConfigResult_Ignore;
    2.57  }
    2.58  
    2.59 +const char *CoreConfig::GetCoreConfigValue(const char *key)
    2.60 +{
    2.61 +	int *pKey = m_KeyValues.retrieve(key);
    2.62 +	if (pKey == NULL)
    2.63 +	{
    2.64 +		return NULL;
    2.65 +	}
    2.66 +	return m_Strings.GetString(*pKey);
    2.67 +}
    2.68 +
    2.69  bool SM_AreConfigsExecuted()
    2.70  {
    2.71  	return g_bConfigsExecd;
     3.1 --- a/core/CoreConfig.h	Wed Feb 18 02:19:22 2009 -0600
     3.2 +++ b/core/CoreConfig.h	Wed Feb 18 02:30:21 2009 -0600
     3.3 @@ -35,6 +35,8 @@
     3.4  #include "sm_globals.h"
     3.5  #include <ITextParsers.h>
     3.6  #include <IRootConsoleMenu.h>
     3.7 +#include <sm_trie_tpl.h>
     3.8 +#include "sm_memtable.h"
     3.9  
    3.10  using namespace SourceMod;
    3.11  
    3.12 @@ -43,6 +45,9 @@
    3.13  	public ITextListener_SMC,
    3.14  	public IRootConsoleCommand
    3.15  {
    3.16 +public:
    3.17 +	CoreConfig();
    3.18 +	~CoreConfig();
    3.19  public: // SMGlobalClass
    3.20  	void OnSourceModAllInitialized();
    3.21  	void OnSourceModShutdown();
    3.22 @@ -56,11 +61,15 @@
    3.23  	 * Initializes CoreConfig by reading from core.cfg file
    3.24  	 */
    3.25  	void Initialize();
    3.26 +	const char *GetCoreConfigValue(const char *key);
    3.27  private:
    3.28  	/**
    3.29  	 * Sets configuration option by notifying SourceMod components that rely on core.cfg
    3.30  	 */
    3.31  	ConfigResult SetConfigOption(const char *option, const char *value, ConfigSource, char *Error, size_t maxlength);
    3.32 +private:
    3.33 +	BaseStringTable m_Strings;
    3.34 +	KTrie<int> m_KeyValues;
    3.35  };
    3.36  
    3.37  extern bool SM_AreConfigsExecuted();
     4.1 --- a/core/GameConfigs.cpp	Wed Feb 18 02:19:22 2009 -0600
     4.2 +++ b/core/GameConfigs.cpp	Wed Feb 18 02:30:21 2009 -0600
     4.3 @@ -749,6 +749,44 @@
     4.4  		}
     4.5  	}
     4.6  
     4.7 +	/* Parse the contents of the 'custom' directory */
     4.8 +	g_SourceMod.BuildPath(Path_SM, path, sizeof(path), "gamedata/%s/custom", m_File);
     4.9 +	IDirectory *customDir = g_LibSys.OpenDirectory(path);
    4.10 +
    4.11 +	if (!customDir)
    4.12 +	{
    4.13 +		return true;
    4.14 +	}
    4.15 +
    4.16 +	while (customDir->MoreFiles())
    4.17 +	{
    4.18 +		if (!customDir->IsEntryFile())
    4.19 +		{
    4.20 +			customDir->NextEntry();
    4.21 +			continue;
    4.22 +		}
    4.23 +		
    4.24 +		const char *curFile = customDir->GetEntryName();
    4.25 +
    4.26 +		/* Only allow .txt files */
    4.27 +		int len = strlen(curFile);
    4.28 +		if (len > 4 && strcmp(&curFile[len-4], ".txt") != 0)
    4.29 +		{
    4.30 +			customDir->NextEntry();
    4.31 +			continue;	
    4.32 +		}
    4.33 +
    4.34 +		UTIL_Format(path, sizeof(path), "%s/custom/%s", m_File, curFile);
    4.35 +		if (!EnterFile(path, error, maxlength))
    4.36 +		{
    4.37 +			g_LibSys.CloseDirectory(customDir);
    4.38 +			return false;
    4.39 +		}
    4.40 +
    4.41 +		customDir->NextEntry();
    4.42 +	}
    4.43 +
    4.44 +	g_LibSys.CloseDirectory(customDir);
    4.45  	return true;
    4.46  }
    4.47  
    4.48 @@ -764,15 +802,11 @@
    4.49  	bShouldBeReadingDefault = true;
    4.50  	m_ParseState = PSTATE_NONE;
    4.51  
    4.52 -	g_GameConfigs.AcquireLock();
    4.53 -
    4.54  	if ((err=textparsers->ParseSMCFile(m_CurFile, this, &state, error, maxlength))
    4.55  		!= SMCError_Okay)
    4.56  	{
    4.57  		const char *msg;
    4.58  
    4.59 -		g_GameConfigs.ReleaseLock();
    4.60 -
    4.61  		msg = textparsers->GetSMCErrorString(err);
    4.62  
    4.63  		g_Logger.LogError("[SM] Error parsing gameconfig file \"%s\":", m_CurFile);
    4.64 @@ -793,8 +827,6 @@
    4.65  		return false;
    4.66  	}
    4.67  
    4.68 -	g_GameConfigs.ReleaseLock();
    4.69 -
    4.70  	return true;
    4.71  }
    4.72  
    4.73 @@ -862,8 +894,6 @@
    4.74  
    4.75  void GameConfigManager::OnSourceModStartup(bool late)
    4.76  {
    4.77 -	m_FileLock = g_pThreader->MakeMutex();
    4.78 -
    4.79  	LoadGameConfigFile("core.games", &g_pGameConf, NULL, 0);
    4.80  
    4.81  	strncopy(g_Game, g_SourceMod.GetGameFolderName(), sizeof(g_Game));
    4.82 @@ -898,7 +928,6 @@
    4.83  void GameConfigManager::OnSourceModAllShutdown()
    4.84  {
    4.85  	CloseGameConfigFile(g_pGameConf);
    4.86 -	m_FileLock->DestroyThis();
    4.87  }
    4.88  
    4.89  bool GameConfigManager::LoadGameConfigFile(const char *file, IGameConfig **_pConfig, char *error, size_t maxlength)
    4.90 @@ -993,10 +1022,8 @@
    4.91  
    4.92  void GameConfigManager::AcquireLock()
    4.93  {
    4.94 -	m_FileLock->Lock();
    4.95  }
    4.96  
    4.97  void GameConfigManager::ReleaseLock()
    4.98  {
    4.99 -	m_FileLock->Unlock();
   4.100  }
     5.1 --- a/core/GameConfigs.h	Wed Feb 18 02:19:22 2009 -0600
     5.2 +++ b/core/GameConfigs.h	Wed Feb 18 02:30:21 2009 -0600
     5.3 @@ -120,7 +120,6 @@
     5.4  private:
     5.5  	List<CGameConfig *> m_cfgs;
     5.6  	Trie *m_pLookup;
     5.7 -	IMutex *m_FileLock;
     5.8  public:
     5.9  	KTrie<ITextListener_SMC *> m_customHandlers;
    5.10  };
     6.1 --- a/core/UserMessages.cpp	Wed Feb 18 02:19:22 2009 -0600
     6.2 +++ b/core/UserMessages.cpp	Wed Feb 18 02:30:21 2009 -0600
     6.3 @@ -348,6 +348,8 @@
     6.4  	MsgIter iter;
     6.5  	ListenerInfo *pInfo;
     6.6  
     6.7 +	m_InHook = false;
     6.8 +
     6.9  	pList = &m_msgIntercepts[m_CurId];
    6.10  	for (iter=pList->begin(); iter!=pList->end(); )
    6.11  	{
    6.12 @@ -367,8 +369,6 @@
    6.13  		iter++;
    6.14  	}
    6.15  
    6.16 -	m_InHook = false;
    6.17 -
    6.18  	pList = &m_msgHooks[m_CurId];
    6.19  	for (iter=pList->begin(); iter!=pList->end(); )
    6.20  	{
     7.1 --- a/core/sourcemod.cpp	Wed Feb 18 02:19:22 2009 -0600
     7.2 +++ b/core/sourcemod.cpp	Wed Feb 18 02:30:21 2009 -0600
     7.3 @@ -70,6 +70,12 @@
     7.4  typedef ISourcePawnEngine2 *(*GET_SP_V2)();
     7.5  typedef void (*NOTIFYSHUTDOWN)();
     7.6  
     7.7 +#ifdef PLATFORM_WINDOWS
     7.8 +ConVar sm_basepath("sm_basepath", "addons\\sourcemod", 0, "SourceMod base path (set via command line)");
     7.9 +#elif defined PLATFORM_LINUX || defined PLATFORM_APPLE
    7.10 +ConVar sm_basepath("sm_basepath", "addons/sourcemod", 0, "SourceMod base path (set via command line)");
    7.11 +#endif
    7.12 +
    7.13  void ShutdownJIT()
    7.14  {
    7.15  	NOTIFYSHUTDOWN notify = (NOTIFYSHUTDOWN)g_pJIT->GetSymbolAddress("NotifyShutdown");
    7.16 @@ -145,16 +151,26 @@
    7.17  		}
    7.18  	}
    7.19  
    7.20 -	/* Initialize CoreConfig so we can get SourceMod base path properly - this basically parses core.cfg */
    7.21 +	const char *basepath = icvar->GetCommandLineValue("sm_basepath");
    7.22 +	/* Set a custom base path if there is one. */
    7.23 +	if (basepath != NULL && basepath[0] != '\0')
    7.24 +	{
    7.25 +		m_GotBasePath = true;
    7.26 +	}
    7.27 +	/* Otherwise, use a default and keep the m_GotBasePath unlocked. */
    7.28 +	else
    7.29 +	{
    7.30 +		basepath = sm_basepath.GetDefault();
    7.31 +	}
    7.32 +
    7.33 +	g_LibSys.PathFormat(m_SMBaseDir, sizeof(m_SMBaseDir), "%s/%s", g_BaseDir.c_str(), basepath);
    7.34 +	g_LibSys.PathFormat(m_SMRelDir, sizeof(m_SMRelDir), "%s", basepath);
    7.35 +
    7.36 +	/* Initialize CoreConfig to get the SourceMod base path properly - this parses core.cfg */
    7.37  	g_CoreConfig.Initialize();
    7.38  
    7.39 -	/* This shouldn't happen, but can't hurt to be safe */
    7.40 -	if (!g_LibSys.PathExists(m_SMBaseDir) || !m_GotBasePath)
    7.41 -	{
    7.42 -		g_LibSys.PathFormat(m_SMBaseDir, sizeof(m_SMBaseDir), "%s/addons/sourcemod", g_BaseDir.c_str());
    7.43 -		g_LibSys.PathFormat(m_SMRelDir, sizeof(m_SMRelDir), "addons/sourcemod");
    7.44 -		m_GotBasePath = true;
    7.45 -	}
    7.46 +	/* There will always be a path by this point, since it was force-set above. */
    7.47 +	m_GotBasePath = true;
    7.48  
    7.49  	/* Attempt to load the JIT! */
    7.50  	char file[PLATFORM_MAX_PATH];
    7.51 @@ -696,6 +712,11 @@
    7.52  	::AddFrameAction(FrameAction(fn, data));
    7.53  }
    7.54  
    7.55 +const char *SourceModBase::GetCoreConfigValue(const char *key)
    7.56 +{
    7.57 +	return g_CoreConfig.GetCoreConfigValue(key);
    7.58 +}
    7.59 +
    7.60  SMGlobalClass *SMGlobalClass::head = NULL;
    7.61  
    7.62  SMGlobalClass::SMGlobalClass()
     8.1 --- a/core/sourcemod.h	Wed Feb 18 02:19:22 2009 -0600
     8.2 +++ b/core/sourcemod.h	Wed Feb 18 02:30:21 2009 -0600
     8.3 @@ -132,6 +132,7 @@
     8.4  	size_t Format(char *buffer, size_t maxlength, const char *fmt, ...);
     8.5  	size_t FormatArgs(char *buffer, size_t maxlength, const char *fmt, va_list ap);
     8.6  	void AddFrameAction(FRAMEACTION fn, void *data);
     8.7 +	const char *GetCoreConfigValue(const char *key);
     8.8  private:
     8.9  	CStack<CDataPack *> m_freepacks;
    8.10  	char m_SMBaseDir[PLATFORM_MAX_PATH];
     9.1 --- a/extensions/updater/Updater.cpp	Wed Feb 18 02:19:22 2009 -0600
     9.2 +++ b/extensions/updater/Updater.cpp	Wed Feb 18 02:30:21 2009 -0600
     9.3 @@ -34,8 +34,6 @@
     9.4  #include "Updater.h"
     9.5  #include "md5.h"
     9.6  
     9.7 -#define UPDATE_URL			"http://www.sourcemod.net/update/"
     9.8 -
     9.9  #define USTATE_NONE			0
    9.10  #define USTATE_FOLDERS		1
    9.11  #define USTATE_CHANGED		2
    9.12 @@ -43,7 +41,7 @@
    9.13  
    9.14  using namespace SourceMod;
    9.15  
    9.16 -UpdateReader::UpdateReader()
    9.17 +UpdateReader::UpdateReader() : partFirst(NULL), partLast(NULL)
    9.18  {
    9.19  }
    9.20  
    9.21 @@ -125,7 +123,7 @@
    9.22  			}
    9.23  			else if (strcmp(key, "location") == 0)
    9.24  			{
    9.25 -				url.assign(UPDATE_URL);
    9.26 +				url.assign(update_url);
    9.27  				url.append(value);
    9.28  			}
    9.29  			break;
    9.30 @@ -174,6 +172,21 @@
    9.31  	return SMCResult_Continue;
    9.32  }
    9.33  
    9.34 +void UpdateReader::LinkPart(UpdatePart *part)
    9.35 +{
    9.36 +	part->next = NULL;
    9.37 +	if (partFirst == NULL)
    9.38 +	{
    9.39 +		partFirst = part;
    9.40 +		partLast = part;
    9.41 +	}
    9.42 +	else
    9.43 +	{
    9.44 +		partLast->next = part;
    9.45 +		partLast = part;
    9.46 +	}
    9.47 +}
    9.48 +
    9.49  void UpdateReader::HandleFile()
    9.50  {
    9.51  	MD5 md5;
    9.52 @@ -192,6 +205,12 @@
    9.53  	md5.finalize();
    9.54  	md5.hex_digest(real_checksum);
    9.55  
    9.56 +	if (mdl.GetSize() == 0)
    9.57 +	{
    9.58 +		AddUpdateError("Zero-length file returned for \"%s\"", curfile.c_str());
    9.59 +		return;
    9.60 +	}
    9.61 +
    9.62  	if (strcasecmp(checksum, real_checksum) != 0)
    9.63  	{
    9.64  		AddUpdateError("Checksums for file \"%s\" do not match:", curfile.c_str());
    9.65 @@ -199,45 +218,20 @@
    9.66  		return;
    9.67  	}
    9.68  
    9.69 -	char path[PLATFORM_MAX_PATH];
    9.70 -	smutils->BuildPath(Path_SM, path, sizeof(path), "gamedata/%s", curfile.c_str());
    9.71 -
    9.72 -	gameconfs->AcquireLock();
    9.73 -	
    9.74 -	FILE *fp = fopen(path, "wt");
    9.75 -	if (fp == NULL)
    9.76 -	{
    9.77 -		gameconfs->ReleaseLock();
    9.78 -		AddUpdateError("Could not open %s for writing", path);
    9.79 -		return;
    9.80 -	}
    9.81 -
    9.82 -	fwrite(mdl.GetBuffer(), 1, mdl.GetSize(), fp);
    9.83 -	fclose(fp);
    9.84 -
    9.85 -	gameconfs->ReleaseLock();
    9.86 -
    9.87 -	AddUpdateMessage("Successfully updated gamedata file \"%s\"", curfile.c_str());
    9.88 +	UpdatePart *part = new UpdatePart;
    9.89 +	part->data = (char*)malloc(mdl.GetSize());
    9.90 +	part->file = strdup(curfile.c_str());
    9.91 +	part->length = mdl.GetSize();
    9.92 +	LinkPart(part);
    9.93  }
    9.94  
    9.95  void UpdateReader::HandleFolder(const char *folder)
    9.96  {
    9.97 -	char path[PLATFORM_MAX_PATH];
    9.98 -
    9.99 -	smutils->BuildPath(Path_SM, path, sizeof(path), "gamedata/%s", folder);
   9.100 -	if (libsys->IsPathDirectory(path))
   9.101 -	{
   9.102 -		return;
   9.103 -	}
   9.104 -
   9.105 -	if (!libsys->CreateFolder(path))
   9.106 -	{
   9.107 -		AddUpdateError("Could not create folder: %s", path);
   9.108 -	}
   9.109 -	else
   9.110 -	{
   9.111 -		AddUpdateMessage("Created folder \"%s\" from updater", folder);
   9.112 -	}
   9.113 +	UpdatePart *part = new UpdatePart;
   9.114 +	part->data = NULL;
   9.115 +	part->length = 0;
   9.116 +	part->file = strdup(folder);
   9.117 +	LinkPart(part);
   9.118  }
   9.119  
   9.120  static bool md5_file(const char *file, char checksum[33])
   9.121 @@ -334,18 +328,18 @@
   9.122  	libsys->CloseDirectory(dir);
   9.123  }
   9.124  
   9.125 -void UpdateReader::PerformUpdate()
   9.126 +void UpdateReader::PerformUpdate(const char *url)
   9.127  {
   9.128  	IWebForm *form;
   9.129  	MemoryDownloader master;
   9.130  	SMCStates states = {0, 0};
   9.131  
   9.132 +	update_url = url;
   9.133 +
   9.134  	form = webternet->CreateForm();
   9.135  	xfer = webternet->CreateSession();
   9.136  	xfer->SetFailOnHTTPError(true);
   9.137  
   9.138 -	const char *root_url = UPDATE_URL "gamedata.php";
   9.139 -
   9.140  	form->AddString("version", SVN_FULL_VERSION);
   9.141  	form->AddString("build", SM_BUILD_UNIQUEID);
   9.142  
   9.143 @@ -356,9 +350,9 @@
   9.144  	smutils->Format(temp, sizeof(temp), "%d", num_files);
   9.145  	form->AddString("files", temp);
   9.146  
   9.147 -	if (!xfer->PostAndDownload(root_url, form, &master, NULL))
   9.148 +	if (!xfer->PostAndDownload(url, form, &master, NULL))
   9.149  	{
   9.150 -		AddUpdateError("Could not download \"%s\"", root_url);
   9.151 +		AddUpdateError("Could not download \"%s\"", url);
   9.152  		AddUpdateError("Error: %s", xfer->LastErrorMessage());
   9.153  		goto cleanup;
   9.154  	}
   9.155 @@ -381,3 +375,14 @@
   9.156  	delete xfer;
   9.157  	delete form;
   9.158  }
   9.159 +
   9.160 +UpdatePart *UpdateReader::DetachParts()
   9.161 +{
   9.162 +	UpdatePart *first;
   9.163 +
   9.164 +	first = partFirst;
   9.165 +	partFirst = NULL;
   9.166 +	partLast = NULL;
   9.167 +
   9.168 +	return first;
   9.169 +}
    10.1 --- a/extensions/updater/Updater.h	Wed Feb 18 02:19:22 2009 -0600
    10.2 +++ b/extensions/updater/Updater.h	Wed Feb 18 02:30:21 2009 -0600
    10.3 @@ -37,6 +37,14 @@
    10.4  #include <sh_string.h>
    10.5  #include "MemoryDownloader.h"
    10.6  
    10.7 +struct UpdatePart
    10.8 +{
    10.9 +	UpdatePart* next;
   10.10 +	char *file;
   10.11 +	char *data;
   10.12 +	size_t length;
   10.13 +};
   10.14 +
   10.15  namespace SourceMod
   10.16  {
   10.17  	class UpdateReader : 
   10.18 @@ -51,10 +59,12 @@
   10.19  		SMCResult ReadSMC_KeyValue(const SMCStates *states, const char *key, const char *value);
   10.20  		SMCResult ReadSMC_LeavingSection(const SMCStates *states);
   10.21  	public:
   10.22 -		void PerformUpdate();
   10.23 +		void PerformUpdate(const char *url);
   10.24 +		UpdatePart *DetachParts();
   10.25  	private:
   10.26  		void HandleFile();
   10.27  		void HandleFolder(const char *folder);
   10.28 +		void LinkPart(UpdatePart *part);
   10.29  	private:
   10.30  		IWebTransfer *xfer;
   10.31  		MemoryDownloader mdl;
   10.32 @@ -63,6 +73,9 @@
   10.33  		SourceHook::String curfile;
   10.34  		SourceHook::String url;
   10.35  		char checksum[33];
   10.36 +		UpdatePart *partFirst;
   10.37 +		UpdatePart *partLast;
   10.38 +		const char *update_url;
   10.39  	};
   10.40  }
   10.41  
    11.1 --- a/extensions/updater/extension.cpp	Wed Feb 18 02:19:22 2009 -0600
    11.2 +++ b/extensions/updater/extension.cpp	Wed Feb 18 02:30:21 2009 -0600
    11.3 @@ -38,6 +38,8 @@
    11.4  #include <sh_list.h>
    11.5  #include <sh_string.h>
    11.6  
    11.7 +#define DEFAULT_UPDATE_URL			"http://www.sourcemod.net/update/"
    11.8 +
    11.9  using namespace SourceHook;
   11.10  
   11.11  SmUpdater g_Updater;		/**< Global singleton for extension's main interface */
   11.12 @@ -45,8 +47,8 @@
   11.13  
   11.14  IWebternet *webternet;
   11.15  static List<String *> update_errors;
   11.16 -static List<String *> update_messages;
   11.17  static IThreadHandle *update_thread;
   11.18 +static String update_url;
   11.19  
   11.20  bool SmUpdater::SDK_OnLoad(char *error, size_t maxlength, bool late)
   11.21  {
   11.22 @@ -65,6 +67,13 @@
   11.23  		return false;
   11.24  	}
   11.25  
   11.26 +	const char *url = smutils->GetCoreConfigValue("AutoUpdateURL");
   11.27 +	if (url == NULL)
   11.28 +	{
   11.29 +		url = DEFAULT_UPDATE_URL;
   11.30 +	}
   11.31 +	update_url.assign(url);
   11.32 +
   11.33  	return true;
   11.34  }
   11.35  
   11.36 @@ -85,10 +94,6 @@
   11.37  	{
   11.38  		iter = update_errors.erase(iter);
   11.39  	}
   11.40 -	while (iter != update_messages.end())
   11.41 -	{
   11.42 -		iter = update_messages.erase(iter);
   11.43 -	}
   11.44  }
   11.45  
   11.46  bool SmUpdater::QueryInterfaceDrop(SourceMod::SMInterface *pInterface)
   11.47 @@ -112,11 +117,61 @@
   11.48  	}
   11.49  }
   11.50  
   11.51 -static void LogAllMessages(void *data)
   11.52 +static void PumpUpdate(void *data)
   11.53  {
   11.54  	String *str;
   11.55  	List<String *>::iterator iter;
   11.56  
   11.57 +	char path[PLATFORM_MAX_PATH];
   11.58 +	UpdatePart *temp;
   11.59 +	UpdatePart *part = (UpdatePart*)data;
   11.60 +	while (part != NULL)
   11.61 +	{
   11.62 +		if (strstr(part->file, "..") != NULL)
   11.63 +		{
   11.64 +			/* Naughty naughty */
   11.65 +			AddUpdateError("Detected invalid path escape (..): %s", part->file);
   11.66 +			goto skip_create;
   11.67 +		}
   11.68 +		if (part->data == NULL)
   11.69 +		{
   11.70 +			smutils->BuildPath(Path_SM, path, sizeof(path), "gamedata/%s", part->file);
   11.71 +			if (libsys->IsPathDirectory(path))
   11.72 +			{
   11.73 +				continue;
   11.74 +			}
   11.75 +			if (!libsys->CreateFolder(path))
   11.76 +			{
   11.77 +				AddUpdateError("Could not create folder: %s", path);
   11.78 +			}
   11.79 +			else
   11.80 +			{
   11.81 +				smutils->LogMessage(myself, "Created folder \"%s\" from updater", path);
   11.82 +			}
   11.83 +		}
   11.84 +		else
   11.85 +		{
   11.86 +			smutils->BuildPath(Path_SM, path, sizeof(path), "gamedata/%s", part->file);
   11.87 +			FILE *fp = fopen(path, "wt");
   11.88 +			if (fp == NULL)
   11.89 +			{
   11.90 +				AddUpdateError("Could not open %s for writing", path);
   11.91 +				return;
   11.92 +			}
   11.93 +			fwrite(part->data, 1, part->length, fp);
   11.94 +			fclose(fp);
   11.95 +			smutils->LogMessage(myself,
   11.96 +				"Successfully updated gamedata file \"%s\"",
   11.97 +				part->file);
   11.98 +		}
   11.99 +skip_create:
  11.100 +		temp = part->next;
  11.101 +		free(part->data);
  11.102 +		free(part->file);
  11.103 +		delete part;
  11.104 +		part = temp;
  11.105 +	}
  11.106 +
  11.107  	if (update_errors.size())
  11.108  	{
  11.109  		smutils->LogError(myself, "--- BEGIN ERRORS FROM AUTOMATIC UPDATER ---");
  11.110 @@ -131,44 +186,21 @@
  11.111  
  11.112  		smutils->LogError(myself, "--- END ERRORS FROM AUTOMATIC UPDATER ---");
  11.113  	}
  11.114 -
  11.115 -	for (iter = update_messages.begin();
  11.116 -		 iter != update_messages.end();
  11.117 -		 iter++)
  11.118 -	{
  11.119 -		str = (*iter);
  11.120 -		smutils->LogMessage(myself, "%s", str->c_str());
  11.121 -	}
  11.122  }
  11.123  
  11.124  void SmUpdater::RunThread(IThreadHandle *pHandle)
  11.125  {
  11.126  	UpdateReader ur;
  11.127  
  11.128 -	ur.PerformUpdate();
  11.129 +	ur.PerformUpdate(update_url.c_str());
  11.130  
  11.131 -	if (update_errors.size() || update_messages.size())
  11.132 -	{
  11.133 -		smutils->AddFrameAction(LogAllMessages, NULL);
  11.134 -	}
  11.135 +	smutils->AddFrameAction(PumpUpdate, ur.DetachParts());
  11.136  }
  11.137  
  11.138  void SmUpdater::OnTerminate(IThreadHandle *pHandle, bool cancel)
  11.139  {
  11.140  }
  11.141  
  11.142 -void AddUpdateMessage(const char *fmt, ...)
  11.143 -{
  11.144 -	va_list ap;
  11.145 -	char buffer[2048];
  11.146 -
  11.147 -	va_start(ap, fmt);
  11.148 -	smutils->FormatArgs(buffer, sizeof(buffer), fmt, ap);
  11.149 -	va_end(ap);
  11.150 -
  11.151 -	update_messages.push_back(new String(buffer));
  11.152 -}
  11.153 -
  11.154  void AddUpdateError(const char *fmt, ...)
  11.155  {
  11.156  	va_list ap;
    12.1 --- a/gamedata/sm-tf2.games.txt	Wed Feb 18 02:19:22 2009 -0600
    12.2 +++ b/gamedata/sm-tf2.games.txt	Wed Feb 18 02:30:21 2009 -0600
    12.3 @@ -38,7 +38,7 @@
    12.4  			{
    12.5  				"library"		"server"
    12.6  				"linux"		"@_ZN8CTFKnife26CalcIsAttackCriticalHelperEv"
    12.7 -				"windows"	"\x33\xC0\x83\xB9\x08\x13\x00\x00\x01\x0F\x94\xC0\xC3"
    12.8 +				"windows"	"\x33\xC0\x83\xB9\x30\x13\x00\x00\x01\x0F\x94\xC0\xC3"
    12.9  			}
   12.10  
   12.11  		}
    13.1 --- a/public/IGameConfigs.h	Wed Feb 18 02:19:22 2009 -0600
    13.2 +++ b/public/IGameConfigs.h	Wed Feb 18 02:30:21 2009 -0600
    13.3 @@ -163,12 +163,12 @@
    13.4  		virtual void RemoveUserConfigHook(const char *sectionname, ITextListener_SMC *listener) =0;
    13.5  
    13.6  		/**
    13.7 -		 * @brief Acquires a file reading lock on the gamedata system.  
    13.8 +		 * @brief Does nothing.
    13.9  		 */
   13.10  		virtual void AcquireLock() = 0;
   13.11  
   13.12  		/**
   13.13 -		 * @brief Releases the file reading lock.
   13.14 +		 * @brief Does nothing.
   13.15  		 */
   13.16  		virtual void ReleaseLock() = 0;
   13.17  	};
    14.1 --- a/public/ISourceMod.h	Wed Feb 18 02:19:22 2009 -0600
    14.2 +++ b/public/ISourceMod.h	Wed Feb 18 02:30:21 2009 -0600
    14.3 @@ -43,7 +43,7 @@
    14.4  #include <time.h>
    14.5  
    14.6  #define SMINTERFACE_SOURCEMOD_NAME		"ISourceMod"
    14.7 -#define SMINTERFACE_SOURCEMOD_VERSION	9
    14.8 +#define SMINTERFACE_SOURCEMOD_VERSION	10
    14.9  
   14.10  /**
   14.11  * @brief Forward declaration of the KeyValues class.
   14.12 @@ -287,6 +287,15 @@
   14.13  		 * @param data		Data to pass to function.
   14.14  		 */
   14.15  		virtual void AddFrameAction(FRAMEACTION fn, void *data) = 0;
   14.16 +
   14.17 +		/**
   14.18 +		 * @brief Retrieves a core.cfg configuration value.
   14.19 +		 *
   14.20 +		 * @param key		Core.cfg key phrase.
   14.21 +		 * @return			Value string, or NULL on failure.
   14.22 +		 *					The string will be destroyed on core.cfg reparses.
   14.23 +		 */
   14.24 +		virtual const char *GetCoreConfigValue(const char *key) = 0;
   14.25  	};
   14.26  }
   14.27