This commit is contained in:
Scott Ehlert 2009-02-18 02:30:21 -06:00
commit 75ebac822d
14 changed files with 249 additions and 114 deletions

View File

@ -4,14 +4,6 @@
*/ */
"Core" "Core"
{ {
/**
* Relative path to SourceMod's base directory. This is relative to the game/mod directory.
* Only change this if you have installed SourceMod in a non-default location.
*
* The default value is "addons/sourcemod"
*/
"BasePath" "addons/sourcemod"
/** /**
* This option determines if SourceMod logging is enabled. * This option determines if SourceMod logging is enabled.
* *
@ -104,6 +96,12 @@
*/ */
"ForceRestartAfterUpdate" "no" "ForceRestartAfterUpdate" "no"
/**
* URL to use for retrieving update information.
* SSL is not yet supported.
*/
"AutoUpdateURL" "http://www.sourcemod.net/update/"
/** /**
* Whether to show debug spew. * Whether to show debug spew.
* Currently this will log details about the gamedata updating process. * Currently this will log details about the gamedata updating process.

View File

@ -79,9 +79,7 @@ void Hook_ExecDispatchPre()
const char *arg = cmd.Arg(1); const char *arg = cmd.Arg(1);
if (!g_bServerExecd if (!g_bServerExecd && arg != NULL && strcmp(arg, g_ServerCfgFile->GetString()) == 0)
&& arg != NULL
&& strcmp(arg, g_ServerCfgFile->GetString()) == 0)
{ {
g_bGotTrigger = true; g_bGotTrigger = true;
} }
@ -103,8 +101,7 @@ void Hook_ExecDispatchPost()
void CheckAndFinalizeConfigs() void CheckAndFinalizeConfigs()
{ {
if ((g_bServerExecd || g_ServerCfgFile == NULL) if ((g_bServerExecd || g_ServerCfgFile == NULL) && g_bGotServerStart)
&& g_bGotServerStart)
{ {
#if SOURCE_ENGINE >= SE_ORANGEBOX #if SOURCE_ENGINE >= SE_ORANGEBOX
g_PendingInternalPush = true; g_PendingInternalPush = true;
@ -122,6 +119,14 @@ void CoreConfig::OnSourceModAllInitialized()
g_pOnAutoConfigsBuffered = g_Forwards.CreateForward("OnAutoConfigsBuffered", ET_Ignore, 0, NULL); g_pOnAutoConfigsBuffered = g_Forwards.CreateForward("OnAutoConfigsBuffered", ET_Ignore, 0, NULL);
} }
CoreConfig::CoreConfig() : m_Strings(512)
{
}
CoreConfig::~CoreConfig()
{
}
void CoreConfig::OnSourceModShutdown() void CoreConfig::OnSourceModShutdown()
{ {
g_RootMenu.RemoveRootConsoleCommand("config", this); g_RootMenu.RemoveRootConsoleCommand("config", this);
@ -218,6 +223,10 @@ void CoreConfig::Initialize()
/* Format path to config file */ /* Format path to config file */
g_LibSys.PathFormat(filePath, sizeof(filePath), "%s/%s", g_SourceMod.GetGamePath(), corecfg); g_LibSys.PathFormat(filePath, sizeof(filePath), "%s/%s", g_SourceMod.GetGamePath(), corecfg);
/* Reset cached key values */
m_KeyValues.clear();
m_Strings.Reset();
/* Parse config file */ /* Parse config file */
if ((err=textparsers->ParseFile_SMC(filePath, this, NULL)) != SMCError_Okay) if ((err=textparsers->ParseFile_SMC(filePath, this, NULL)) != SMCError_Okay)
{ {
@ -256,9 +265,21 @@ ConfigResult CoreConfig::SetConfigOption(const char *option, const char *value,
pBase = pBase->m_pGlobalClassNext; pBase = pBase->m_pGlobalClassNext;
} }
m_KeyValues.replace(option, m_Strings.AddString(value));
return ConfigResult_Ignore; return ConfigResult_Ignore;
} }
const char *CoreConfig::GetCoreConfigValue(const char *key)
{
int *pKey = m_KeyValues.retrieve(key);
if (pKey == NULL)
{
return NULL;
}
return m_Strings.GetString(*pKey);
}
bool SM_AreConfigsExecuted() bool SM_AreConfigsExecuted()
{ {
return g_bConfigsExecd; return g_bConfigsExecd;

View File

@ -35,6 +35,8 @@
#include "sm_globals.h" #include "sm_globals.h"
#include <ITextParsers.h> #include <ITextParsers.h>
#include <IRootConsoleMenu.h> #include <IRootConsoleMenu.h>
#include <sm_trie_tpl.h>
#include "sm_memtable.h"
using namespace SourceMod; using namespace SourceMod;
@ -43,6 +45,9 @@ class CoreConfig :
public ITextListener_SMC, public ITextListener_SMC,
public IRootConsoleCommand public IRootConsoleCommand
{ {
public:
CoreConfig();
~CoreConfig();
public: // SMGlobalClass public: // SMGlobalClass
void OnSourceModAllInitialized(); void OnSourceModAllInitialized();
void OnSourceModShutdown(); void OnSourceModShutdown();
@ -56,11 +61,15 @@ public:
* Initializes CoreConfig by reading from core.cfg file * Initializes CoreConfig by reading from core.cfg file
*/ */
void Initialize(); void Initialize();
const char *GetCoreConfigValue(const char *key);
private: private:
/** /**
* Sets configuration option by notifying SourceMod components that rely on core.cfg * Sets configuration option by notifying SourceMod components that rely on core.cfg
*/ */
ConfigResult SetConfigOption(const char *option, const char *value, ConfigSource, char *Error, size_t maxlength); ConfigResult SetConfigOption(const char *option, const char *value, ConfigSource, char *Error, size_t maxlength);
private:
BaseStringTable m_Strings;
KTrie<int> m_KeyValues;
}; };
extern bool SM_AreConfigsExecuted(); extern bool SM_AreConfigsExecuted();

View File

@ -749,6 +749,44 @@ bool CGameConfig::Reparse(char *error, size_t maxlength)
} }
} }
/* Parse the contents of the 'custom' directory */
g_SourceMod.BuildPath(Path_SM, path, sizeof(path), "gamedata/%s/custom", m_File);
IDirectory *customDir = g_LibSys.OpenDirectory(path);
if (!customDir)
{
return true;
}
while (customDir->MoreFiles())
{
if (!customDir->IsEntryFile())
{
customDir->NextEntry();
continue;
}
const char *curFile = customDir->GetEntryName();
/* Only allow .txt files */
int len = strlen(curFile);
if (len > 4 && strcmp(&curFile[len-4], ".txt") != 0)
{
customDir->NextEntry();
continue;
}
UTIL_Format(path, sizeof(path), "%s/custom/%s", m_File, curFile);
if (!EnterFile(path, error, maxlength))
{
g_LibSys.CloseDirectory(customDir);
return false;
}
customDir->NextEntry();
}
g_LibSys.CloseDirectory(customDir);
return true; return true;
} }
@ -764,15 +802,11 @@ bool CGameConfig::EnterFile(const char *file, char *error, size_t maxlength)
bShouldBeReadingDefault = true; bShouldBeReadingDefault = true;
m_ParseState = PSTATE_NONE; m_ParseState = PSTATE_NONE;
g_GameConfigs.AcquireLock();
if ((err=textparsers->ParseSMCFile(m_CurFile, this, &state, error, maxlength)) if ((err=textparsers->ParseSMCFile(m_CurFile, this, &state, error, maxlength))
!= SMCError_Okay) != SMCError_Okay)
{ {
const char *msg; const char *msg;
g_GameConfigs.ReleaseLock();
msg = textparsers->GetSMCErrorString(err); msg = textparsers->GetSMCErrorString(err);
g_Logger.LogError("[SM] Error parsing gameconfig file \"%s\":", m_CurFile); g_Logger.LogError("[SM] Error parsing gameconfig file \"%s\":", m_CurFile);
@ -793,8 +827,6 @@ bool CGameConfig::EnterFile(const char *file, char *error, size_t maxlength)
return false; return false;
} }
g_GameConfigs.ReleaseLock();
return true; return true;
} }
@ -862,8 +894,6 @@ GameConfigManager::~GameConfigManager()
void GameConfigManager::OnSourceModStartup(bool late) void GameConfigManager::OnSourceModStartup(bool late)
{ {
m_FileLock = g_pThreader->MakeMutex();
LoadGameConfigFile("core.games", &g_pGameConf, NULL, 0); LoadGameConfigFile("core.games", &g_pGameConf, NULL, 0);
strncopy(g_Game, g_SourceMod.GetGameFolderName(), sizeof(g_Game)); strncopy(g_Game, g_SourceMod.GetGameFolderName(), sizeof(g_Game));
@ -898,7 +928,6 @@ void GameConfigManager::OnSourceModAllInitialized()
void GameConfigManager::OnSourceModAllShutdown() void GameConfigManager::OnSourceModAllShutdown()
{ {
CloseGameConfigFile(g_pGameConf); CloseGameConfigFile(g_pGameConf);
m_FileLock->DestroyThis();
} }
bool GameConfigManager::LoadGameConfigFile(const char *file, IGameConfig **_pConfig, char *error, size_t maxlength) bool GameConfigManager::LoadGameConfigFile(const char *file, IGameConfig **_pConfig, char *error, size_t maxlength)
@ -993,10 +1022,8 @@ void GameConfigManager::RemoveUserConfigHook(const char *sectionname, ITextListe
void GameConfigManager::AcquireLock() void GameConfigManager::AcquireLock()
{ {
m_FileLock->Lock();
} }
void GameConfigManager::ReleaseLock() void GameConfigManager::ReleaseLock()
{ {
m_FileLock->Unlock();
} }

View File

@ -120,7 +120,6 @@ public: //SMGlobalClass
private: private:
List<CGameConfig *> m_cfgs; List<CGameConfig *> m_cfgs;
Trie *m_pLookup; Trie *m_pLookup;
IMutex *m_FileLock;
public: public:
KTrie<ITextListener_SMC *> m_customHandlers; KTrie<ITextListener_SMC *> m_customHandlers;
}; };

View File

@ -348,6 +348,8 @@ void UserMessages::OnMessageEnd_Post()
MsgIter iter; MsgIter iter;
ListenerInfo *pInfo; ListenerInfo *pInfo;
m_InHook = false;
pList = &m_msgIntercepts[m_CurId]; pList = &m_msgIntercepts[m_CurId];
for (iter=pList->begin(); iter!=pList->end(); ) for (iter=pList->begin(); iter!=pList->end(); )
{ {
@ -367,8 +369,6 @@ void UserMessages::OnMessageEnd_Post()
iter++; iter++;
} }
m_InHook = false;
pList = &m_msgHooks[m_CurId]; pList = &m_msgHooks[m_CurId];
for (iter=pList->begin(); iter!=pList->end(); ) for (iter=pList->begin(); iter!=pList->end(); )
{ {

View File

@ -70,6 +70,12 @@ typedef ISourcePawnEngine *(*GET_SP_V1)();
typedef ISourcePawnEngine2 *(*GET_SP_V2)(); typedef ISourcePawnEngine2 *(*GET_SP_V2)();
typedef void (*NOTIFYSHUTDOWN)(); typedef void (*NOTIFYSHUTDOWN)();
#ifdef PLATFORM_WINDOWS
ConVar sm_basepath("sm_basepath", "addons\\sourcemod", 0, "SourceMod base path (set via command line)");
#elif defined PLATFORM_LINUX || defined PLATFORM_APPLE
ConVar sm_basepath("sm_basepath", "addons/sourcemod", 0, "SourceMod base path (set via command line)");
#endif
void ShutdownJIT() void ShutdownJIT()
{ {
NOTIFYSHUTDOWN notify = (NOTIFYSHUTDOWN)g_pJIT->GetSymbolAddress("NotifyShutdown"); NOTIFYSHUTDOWN notify = (NOTIFYSHUTDOWN)g_pJIT->GetSymbolAddress("NotifyShutdown");
@ -145,16 +151,26 @@ bool SourceModBase::InitializeSourceMod(char *error, size_t maxlength, bool late
} }
} }
/* Initialize CoreConfig so we can get SourceMod base path properly - this basically parses core.cfg */ const char *basepath = icvar->GetCommandLineValue("sm_basepath");
g_CoreConfig.Initialize(); /* Set a custom base path if there is one. */
if (basepath != NULL && basepath[0] != '\0')
/* This shouldn't happen, but can't hurt to be safe */
if (!g_LibSys.PathExists(m_SMBaseDir) || !m_GotBasePath)
{ {
g_LibSys.PathFormat(m_SMBaseDir, sizeof(m_SMBaseDir), "%s/addons/sourcemod", g_BaseDir.c_str());
g_LibSys.PathFormat(m_SMRelDir, sizeof(m_SMRelDir), "addons/sourcemod");
m_GotBasePath = true; m_GotBasePath = true;
} }
/* Otherwise, use a default and keep the m_GotBasePath unlocked. */
else
{
basepath = sm_basepath.GetDefault();
}
g_LibSys.PathFormat(m_SMBaseDir, sizeof(m_SMBaseDir), "%s/%s", g_BaseDir.c_str(), basepath);
g_LibSys.PathFormat(m_SMRelDir, sizeof(m_SMRelDir), "%s", basepath);
/* Initialize CoreConfig to get the SourceMod base path properly - this parses core.cfg */
g_CoreConfig.Initialize();
/* There will always be a path by this point, since it was force-set above. */
m_GotBasePath = true;
/* Attempt to load the JIT! */ /* Attempt to load the JIT! */
char file[PLATFORM_MAX_PATH]; char file[PLATFORM_MAX_PATH];
@ -696,6 +712,11 @@ void SourceModBase::AddFrameAction(FRAMEACTION fn, void *data)
::AddFrameAction(FrameAction(fn, data)); ::AddFrameAction(FrameAction(fn, data));
} }
const char *SourceModBase::GetCoreConfigValue(const char *key)
{
return g_CoreConfig.GetCoreConfigValue(key);
}
SMGlobalClass *SMGlobalClass::head = NULL; SMGlobalClass *SMGlobalClass::head = NULL;
SMGlobalClass::SMGlobalClass() SMGlobalClass::SMGlobalClass()

View File

@ -132,6 +132,7 @@ public: // ISourceMod
size_t Format(char *buffer, size_t maxlength, const char *fmt, ...); size_t Format(char *buffer, size_t maxlength, const char *fmt, ...);
size_t FormatArgs(char *buffer, size_t maxlength, const char *fmt, va_list ap); size_t FormatArgs(char *buffer, size_t maxlength, const char *fmt, va_list ap);
void AddFrameAction(FRAMEACTION fn, void *data); void AddFrameAction(FRAMEACTION fn, void *data);
const char *GetCoreConfigValue(const char *key);
private: private:
CStack<CDataPack *> m_freepacks; CStack<CDataPack *> m_freepacks;
char m_SMBaseDir[PLATFORM_MAX_PATH]; char m_SMBaseDir[PLATFORM_MAX_PATH];

View File

@ -34,8 +34,6 @@
#include "Updater.h" #include "Updater.h"
#include "md5.h" #include "md5.h"
#define UPDATE_URL "http://www.sourcemod.net/update/"
#define USTATE_NONE 0 #define USTATE_NONE 0
#define USTATE_FOLDERS 1 #define USTATE_FOLDERS 1
#define USTATE_CHANGED 2 #define USTATE_CHANGED 2
@ -43,7 +41,7 @@
using namespace SourceMod; using namespace SourceMod;
UpdateReader::UpdateReader() UpdateReader::UpdateReader() : partFirst(NULL), partLast(NULL)
{ {
} }
@ -125,7 +123,7 @@ SMCResult UpdateReader::ReadSMC_KeyValue(const SMCStates *states,
} }
else if (strcmp(key, "location") == 0) else if (strcmp(key, "location") == 0)
{ {
url.assign(UPDATE_URL); url.assign(update_url);
url.append(value); url.append(value);
} }
break; break;
@ -174,6 +172,21 @@ SMCResult UpdateReader::ReadSMC_LeavingSection(const SMCStates *states)
return SMCResult_Continue; return SMCResult_Continue;
} }
void UpdateReader::LinkPart(UpdatePart *part)
{
part->next = NULL;
if (partFirst == NULL)
{
partFirst = part;
partLast = part;
}
else
{
partLast->next = part;
partLast = part;
}
}
void UpdateReader::HandleFile() void UpdateReader::HandleFile()
{ {
MD5 md5; MD5 md5;
@ -192,6 +205,12 @@ void UpdateReader::HandleFile()
md5.finalize(); md5.finalize();
md5.hex_digest(real_checksum); md5.hex_digest(real_checksum);
if (mdl.GetSize() == 0)
{
AddUpdateError("Zero-length file returned for \"%s\"", curfile.c_str());
return;
}
if (strcasecmp(checksum, real_checksum) != 0) if (strcasecmp(checksum, real_checksum) != 0)
{ {
AddUpdateError("Checksums for file \"%s\" do not match:", curfile.c_str()); AddUpdateError("Checksums for file \"%s\" do not match:", curfile.c_str());
@ -199,45 +218,20 @@ void UpdateReader::HandleFile()
return; return;
} }
char path[PLATFORM_MAX_PATH]; UpdatePart *part = new UpdatePart;
smutils->BuildPath(Path_SM, path, sizeof(path), "gamedata/%s", curfile.c_str()); part->data = (char*)malloc(mdl.GetSize());
part->file = strdup(curfile.c_str());
gameconfs->AcquireLock(); part->length = mdl.GetSize();
LinkPart(part);
FILE *fp = fopen(path, "wt");
if (fp == NULL)
{
gameconfs->ReleaseLock();
AddUpdateError("Could not open %s for writing", path);
return;
}
fwrite(mdl.GetBuffer(), 1, mdl.GetSize(), fp);
fclose(fp);
gameconfs->ReleaseLock();
AddUpdateMessage("Successfully updated gamedata file \"%s\"", curfile.c_str());
} }
void UpdateReader::HandleFolder(const char *folder) void UpdateReader::HandleFolder(const char *folder)
{ {
char path[PLATFORM_MAX_PATH]; UpdatePart *part = new UpdatePart;
part->data = NULL;
smutils->BuildPath(Path_SM, path, sizeof(path), "gamedata/%s", folder); part->length = 0;
if (libsys->IsPathDirectory(path)) part->file = strdup(folder);
{ LinkPart(part);
return;
}
if (!libsys->CreateFolder(path))
{
AddUpdateError("Could not create folder: %s", path);
}
else
{
AddUpdateMessage("Created folder \"%s\" from updater", folder);
}
} }
static bool md5_file(const char *file, char checksum[33]) static bool md5_file(const char *file, char checksum[33])
@ -334,18 +328,18 @@ static void add_folders(IWebForm *form, const char *root, unsigned int &num_file
libsys->CloseDirectory(dir); libsys->CloseDirectory(dir);
} }
void UpdateReader::PerformUpdate() void UpdateReader::PerformUpdate(const char *url)
{ {
IWebForm *form; IWebForm *form;
MemoryDownloader master; MemoryDownloader master;
SMCStates states = {0, 0}; SMCStates states = {0, 0};
update_url = url;
form = webternet->CreateForm(); form = webternet->CreateForm();
xfer = webternet->CreateSession(); xfer = webternet->CreateSession();
xfer->SetFailOnHTTPError(true); xfer->SetFailOnHTTPError(true);
const char *root_url = UPDATE_URL "gamedata.php";
form->AddString("version", SVN_FULL_VERSION); form->AddString("version", SVN_FULL_VERSION);
form->AddString("build", SM_BUILD_UNIQUEID); form->AddString("build", SM_BUILD_UNIQUEID);
@ -356,9 +350,9 @@ void UpdateReader::PerformUpdate()
smutils->Format(temp, sizeof(temp), "%d", num_files); smutils->Format(temp, sizeof(temp), "%d", num_files);
form->AddString("files", temp); form->AddString("files", temp);
if (!xfer->PostAndDownload(root_url, form, &master, NULL)) if (!xfer->PostAndDownload(url, form, &master, NULL))
{ {
AddUpdateError("Could not download \"%s\"", root_url); AddUpdateError("Could not download \"%s\"", url);
AddUpdateError("Error: %s", xfer->LastErrorMessage()); AddUpdateError("Error: %s", xfer->LastErrorMessage());
goto cleanup; goto cleanup;
} }
@ -381,3 +375,14 @@ cleanup:
delete xfer; delete xfer;
delete form; delete form;
} }
UpdatePart *UpdateReader::DetachParts()
{
UpdatePart *first;
first = partFirst;
partFirst = NULL;
partLast = NULL;
return first;
}

View File

@ -37,6 +37,14 @@
#include <sh_string.h> #include <sh_string.h>
#include "MemoryDownloader.h" #include "MemoryDownloader.h"
struct UpdatePart
{
UpdatePart* next;
char *file;
char *data;
size_t length;
};
namespace SourceMod namespace SourceMod
{ {
class UpdateReader : class UpdateReader :
@ -51,10 +59,12 @@ namespace SourceMod
SMCResult ReadSMC_KeyValue(const SMCStates *states, const char *key, const char *value); SMCResult ReadSMC_KeyValue(const SMCStates *states, const char *key, const char *value);
SMCResult ReadSMC_LeavingSection(const SMCStates *states); SMCResult ReadSMC_LeavingSection(const SMCStates *states);
public: public:
void PerformUpdate(); void PerformUpdate(const char *url);
UpdatePart *DetachParts();
private: private:
void HandleFile(); void HandleFile();
void HandleFolder(const char *folder); void HandleFolder(const char *folder);
void LinkPart(UpdatePart *part);
private: private:
IWebTransfer *xfer; IWebTransfer *xfer;
MemoryDownloader mdl; MemoryDownloader mdl;
@ -63,6 +73,9 @@ namespace SourceMod
SourceHook::String curfile; SourceHook::String curfile;
SourceHook::String url; SourceHook::String url;
char checksum[33]; char checksum[33];
UpdatePart *partFirst;
UpdatePart *partLast;
const char *update_url;
}; };
} }

View File

@ -38,6 +38,8 @@
#include <sh_list.h> #include <sh_list.h>
#include <sh_string.h> #include <sh_string.h>
#define DEFAULT_UPDATE_URL "http://www.sourcemod.net/update/"
using namespace SourceHook; using namespace SourceHook;
SmUpdater g_Updater; /**< Global singleton for extension's main interface */ SmUpdater g_Updater; /**< Global singleton for extension's main interface */
@ -45,8 +47,8 @@ SMEXT_LINK(&g_Updater);
IWebternet *webternet; IWebternet *webternet;
static List<String *> update_errors; static List<String *> update_errors;
static List<String *> update_messages;
static IThreadHandle *update_thread; static IThreadHandle *update_thread;
static String update_url;
bool SmUpdater::SDK_OnLoad(char *error, size_t maxlength, bool late) bool SmUpdater::SDK_OnLoad(char *error, size_t maxlength, bool late)
{ {
@ -65,6 +67,13 @@ bool SmUpdater::SDK_OnLoad(char *error, size_t maxlength, bool late)
return false; return false;
} }
const char *url = smutils->GetCoreConfigValue("AutoUpdateURL");
if (url == NULL)
{
url = DEFAULT_UPDATE_URL;
}
update_url.assign(url);
return true; return true;
} }
@ -85,10 +94,6 @@ void SmUpdater::SDK_OnUnload()
{ {
iter = update_errors.erase(iter); iter = update_errors.erase(iter);
} }
while (iter != update_messages.end())
{
iter = update_messages.erase(iter);
}
} }
bool SmUpdater::QueryInterfaceDrop(SourceMod::SMInterface *pInterface) bool SmUpdater::QueryInterfaceDrop(SourceMod::SMInterface *pInterface)
@ -112,11 +117,61 @@ void SmUpdater::NotifyInterfaceDrop(SMInterface *pInterface)
} }
} }
static void LogAllMessages(void *data) static void PumpUpdate(void *data)
{ {
String *str; String *str;
List<String *>::iterator iter; List<String *>::iterator iter;
char path[PLATFORM_MAX_PATH];
UpdatePart *temp;
UpdatePart *part = (UpdatePart*)data;
while (part != NULL)
{
if (strstr(part->file, "..") != NULL)
{
/* Naughty naughty */
AddUpdateError("Detected invalid path escape (..): %s", part->file);
goto skip_create;
}
if (part->data == NULL)
{
smutils->BuildPath(Path_SM, path, sizeof(path), "gamedata/%s", part->file);
if (libsys->IsPathDirectory(path))
{
continue;
}
if (!libsys->CreateFolder(path))
{
AddUpdateError("Could not create folder: %s", path);
}
else
{
smutils->LogMessage(myself, "Created folder \"%s\" from updater", path);
}
}
else
{
smutils->BuildPath(Path_SM, path, sizeof(path), "gamedata/%s", part->file);
FILE *fp = fopen(path, "wt");
if (fp == NULL)
{
AddUpdateError("Could not open %s for writing", path);
return;
}
fwrite(part->data, 1, part->length, fp);
fclose(fp);
smutils->LogMessage(myself,
"Successfully updated gamedata file \"%s\"",
part->file);
}
skip_create:
temp = part->next;
free(part->data);
free(part->file);
delete part;
part = temp;
}
if (update_errors.size()) if (update_errors.size())
{ {
smutils->LogError(myself, "--- BEGIN ERRORS FROM AUTOMATIC UPDATER ---"); smutils->LogError(myself, "--- BEGIN ERRORS FROM AUTOMATIC UPDATER ---");
@ -131,44 +186,21 @@ static void LogAllMessages(void *data)
smutils->LogError(myself, "--- END ERRORS FROM AUTOMATIC UPDATER ---"); smutils->LogError(myself, "--- END ERRORS FROM AUTOMATIC UPDATER ---");
} }
for (iter = update_messages.begin();
iter != update_messages.end();
iter++)
{
str = (*iter);
smutils->LogMessage(myself, "%s", str->c_str());
}
} }
void SmUpdater::RunThread(IThreadHandle *pHandle) void SmUpdater::RunThread(IThreadHandle *pHandle)
{ {
UpdateReader ur; UpdateReader ur;
ur.PerformUpdate(); ur.PerformUpdate(update_url.c_str());
if (update_errors.size() || update_messages.size()) smutils->AddFrameAction(PumpUpdate, ur.DetachParts());
{
smutils->AddFrameAction(LogAllMessages, NULL);
}
} }
void SmUpdater::OnTerminate(IThreadHandle *pHandle, bool cancel) void SmUpdater::OnTerminate(IThreadHandle *pHandle, bool cancel)
{ {
} }
void AddUpdateMessage(const char *fmt, ...)
{
va_list ap;
char buffer[2048];
va_start(ap, fmt);
smutils->FormatArgs(buffer, sizeof(buffer), fmt, ap);
va_end(ap);
update_messages.push_back(new String(buffer));
}
void AddUpdateError(const char *fmt, ...) void AddUpdateError(const char *fmt, ...)
{ {
va_list ap; va_list ap;

View File

@ -38,7 +38,7 @@
{ {
"library" "server" "library" "server"
"linux" "@_ZN8CTFKnife26CalcIsAttackCriticalHelperEv" "linux" "@_ZN8CTFKnife26CalcIsAttackCriticalHelperEv"
"windows" "\x33\xC0\x83\xB9\x08\x13\x00\x00\x01\x0F\x94\xC0\xC3" "windows" "\x33\xC0\x83\xB9\x30\x13\x00\x00\x01\x0F\x94\xC0\xC3"
} }
} }

View File

@ -163,12 +163,12 @@ namespace SourceMod
virtual void RemoveUserConfigHook(const char *sectionname, ITextListener_SMC *listener) =0; virtual void RemoveUserConfigHook(const char *sectionname, ITextListener_SMC *listener) =0;
/** /**
* @brief Acquires a file reading lock on the gamedata system. * @brief Does nothing.
*/ */
virtual void AcquireLock() = 0; virtual void AcquireLock() = 0;
/** /**
* @brief Releases the file reading lock. * @brief Does nothing.
*/ */
virtual void ReleaseLock() = 0; virtual void ReleaseLock() = 0;
}; };

View File

@ -43,7 +43,7 @@
#include <time.h> #include <time.h>
#define SMINTERFACE_SOURCEMOD_NAME "ISourceMod" #define SMINTERFACE_SOURCEMOD_NAME "ISourceMod"
#define SMINTERFACE_SOURCEMOD_VERSION 9 #define SMINTERFACE_SOURCEMOD_VERSION 10
/** /**
* @brief Forward declaration of the KeyValues class. * @brief Forward declaration of the KeyValues class.
@ -287,6 +287,15 @@ namespace SourceMod
* @param data Data to pass to function. * @param data Data to pass to function.
*/ */
virtual void AddFrameAction(FRAMEACTION fn, void *data) = 0; virtual void AddFrameAction(FRAMEACTION fn, void *data) = 0;
/**
* @brief Retrieves a core.cfg configuration value.
*
* @param key Core.cfg key phrase.
* @return Value string, or NULL on failure.
* The string will be destroyed on core.cfg reparses.
*/
virtual const char *GetCoreConfigValue(const char *key) = 0;
}; };
} }