Merge.
This commit is contained in:
commit
75ebac822d
@ -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.
|
||||||
|
@ -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;
|
||||||
|
@ -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();
|
||||||
|
@ -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();
|
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
};
|
};
|
||||||
|
@ -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(); )
|
||||||
{
|
{
|
||||||
|
@ -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()
|
||||||
|
@ -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];
|
||||||
|
@ -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;
|
||||||
|
}
|
||||||
|
@ -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;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
@ -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"
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
};
|
};
|
||||||
|
@ -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;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user