Merge branch 'master' into calli-5

Conflicts:
	public/amtl/am-utility.h
This commit is contained in:
David Anderson 2014-09-07 15:03:28 -07:00
commit 60eb8ca4bd
66 changed files with 2034 additions and 622 deletions

View File

@ -52,17 +52,14 @@ for sdk_name in SM.sdks:
compiler = binary.compiler
if sdk.name == 'csgo':
# Protobuf 2.3 headers have some signed/unsigned compares. I believe that it's fixed in later versions, but Valve.
if compiler.cxx.behavior == 'gcc':
compiler.cflags += ['-Wno-sign-compare']
compiler.cxxincludes += [
os.path.join(sdk.path, 'common', 'protobuf-2.3.0', 'src'),
os.path.join(sdk.path, 'common', 'protobuf-2.5.0', 'src'),
os.path.join(sdk.path, 'public', 'engine', 'protobuf'),
os.path.join(sdk.path, 'public', 'game', 'shared', 'csgo', 'protobuf')
]
elif sdk.name == 'dota':
compiler.cxxincludes += [
os.path.join(sdk.path, 'common', 'protobuf-2.4.1', 'src'),
os.path.join(sdk.path, 'common', 'protobuf-2.5.0', 'src'),
os.path.join(sdk.path, 'public', 'engine', 'protobuf'),
os.path.join(sdk.path, 'public', 'game', 'shared', 'protobuf'),
os.path.join(sdk.path, 'public', 'game', 'shared', 'dota', 'protobuf')
@ -109,6 +106,7 @@ for sdk_name in SM.sdks:
binary.sources += [
os.path.join(sdk.path, 'public', 'engine', 'protobuf', 'networkbasetypes.pb.cc'),
os.path.join(sdk.path, 'public', 'engine', 'protobuf', 'netmessages.pb.cc'),
os.path.join(sdk.path, 'public', 'engine', 'protobuf', 'network_connection.pb.cc'),
os.path.join(sdk.path, 'public', 'game', 'shared', 'protobuf', 'ai_activity.pb.cc'),
os.path.join(sdk.path, 'public', 'game', 'shared', 'protobuf', 'usermessages.pb.cc'),
os.path.join(sdk.path, 'public', 'game', 'shared', 'dota', 'protobuf', 'dota_commonmessages.pb.cc'),

View File

@ -383,7 +383,7 @@ bool ConCmdManager::AddAdminCommand(IPluginFunction *pFunction,
{
if (!m_CmdGrps.add(i, group))
return false;
i->value = NoAddRef(new CommandGroup());
i->value = new CommandGroup();
}
Ref<CommandGroup> cmdgroup = i->value;

View File

@ -155,7 +155,7 @@ void EventManager::FireGameEvent(IGameEvent *pEvent)
Just need to add ourselves as a listener to make our hook on IGameEventManager2::FireEvent work */
}
#if SOURCE_ENGINE >= SE_LEFT4DEAD
#if SOURCE_ENGINE >= SE_LEFT4DEAD && SOURCE_ENGINE != SE_DOTA
int EventManager::GetEventDebugID()
{
return EVENT_DEBUG_ID_INIT;

View File

@ -110,7 +110,7 @@ public: // IPluginsListener
void OnPluginUnloaded(IPlugin *plugin);
public: // IGameEventListener2
void FireGameEvent(IGameEvent *pEvent);
#if SOURCE_ENGINE >= SE_LEFT4DEAD
#if SOURCE_ENGINE >= SE_LEFT4DEAD && SOURCE_ENGINE != SE_DOTA
int GetEventDebugID();
#endif
public:

View File

@ -1914,7 +1914,7 @@ CPlayer::CPlayer()
m_bIsSourceTV = false;
m_bIsReplay = false;
m_Serial.value = -1;
m_SteamAccountID = 0;
m_SteamId = k_steamIDNil;
#if SOURCE_ENGINE == SE_CSGO
m_LanguageCookie = InvalidQueryCvarCookie;
#endif
@ -1997,7 +1997,7 @@ void CPlayer::Disconnect()
m_bIsSourceTV = false;
m_bIsReplay = false;
m_Serial.value = -1;
m_SteamAccountID = 0;
m_SteamId = k_steamIDNil;
#if SOURCE_ENGINE == SE_CSGO
m_LanguageCookie = InvalidQueryCvarCookie;
#endif
@ -2033,16 +2033,17 @@ const char *CPlayer::GetAuthString(bool validated)
return m_AuthID.c_str();
}
unsigned int CPlayer::GetSteamAccountID(bool validated)
const CSteamID &CPlayer::GetSteamId(bool validated)
{
if (IsFakeClient() || (validated && !IsAuthStringValidated()))
{
return 0;
static const CSteamID invalidId = k_steamIDNil;
return invalidId;
}
if (m_SteamAccountID != 0)
if (m_SteamId.IsValid())
{
return m_SteamAccountID;
return m_SteamId;
}
#if SOURCE_ENGINE < SE_ORANGEBOX
@ -2050,22 +2051,35 @@ unsigned int CPlayer::GetSteamAccountID(bool validated)
/* STEAM_0:1:123123 | STEAM_ID_LAN | STEAM_ID_PENDING */
if (pAuth && (strlen(pAuth) > 10) && pAuth[8] != '_')
{
m_SteamAccountID = (atoi(&pAuth[8]) | (atoi(&pAuth[10]) << 1));
m_SteamId = CSteamID(atoi(&pAuth[8]) | (atoi(&pAuth[10]) << 1),
k_unSteamUserDesktopInstance, k_EUniversePublic, k_EAccountTypeIndividual);
}
#else
unsigned long long *steamId;
const CSteamID *steamId;
#if SOURCE_ENGINE == SE_DOTA
steamId = (unsigned long long *)engine->GetClientSteamID(m_iIndex);
steamId = engine->GetClientSteamID(m_iIndex);
#else
steamId = (unsigned long long *)engine->GetClientSteamID(m_pEdict);
steamId = engine->GetClientSteamID(m_pEdict);
#endif
if (steamId)
{
m_SteamAccountID = (*steamId & 0xFFFFFFFF);
m_SteamId = (*steamId);
}
#endif
return m_SteamAccountID;
return m_SteamId;
}
unsigned int CPlayer::GetSteamAccountID(bool validated)
{
if (!IsFakeClient() && (!validated || IsAuthStringValidated()))
{
const CSteamID &id = GetSteamId();
if (id.IsValid())
return id.GetAccountID();
}
return 0;
}
edict_t *CPlayer::GetEdict()

View File

@ -43,6 +43,8 @@
#include <sh_vector.h>
#include "ConVarManager.h"
#include <steam/steamclientpublic.h>
using namespace SourceHook;
#define PLAYER_LIFE_UNKNOWN 0
@ -71,6 +73,8 @@ public:
const char *GetIPAddress();
const char *GetAuthString(bool validated = true);
unsigned int GetSteamAccountID(bool validated = true);
const CSteamID &GetSteamId(bool validated = true);
uint64_t GetSteamId64(bool validated = true) { return GetSteamId(validated).ConvertToUint64(); }
edict_t *GetEdict();
bool IsInGame();
bool WasCountedAsInGame();
@ -130,7 +134,7 @@ private:
bool m_bIsSourceTV;
bool m_bIsReplay;
serial_t m_Serial;
unsigned int m_SteamAccountID;
CSteamID m_SteamId;
#if SOURCE_ENGINE == SE_CSGO
QueryCvarCookie_t m_LanguageCookie;
#endif

View File

@ -1082,6 +1082,7 @@ bool GameConfigManager::LoadGameConfigFile(const char *file, IGameConfig **_pCon
}
pConfig = new CGameConfig(file);
pConfig->AddRef();
/* :HACKHACK: Don't parse the main config file */
bool retval = true;

View File

@ -375,7 +375,7 @@ PassRef<Native> ShareSystem::AddNativeToCache(CNativeOwner *pOwner, const sp_nat
if (i.found())
return NULL;
Ref<Native> entry = Newborn<Native>(new Native(pOwner, ntv));
Ref<Native> entry = new Native(pOwner, ntv);
m_NtvCache.insert(ntv->name, entry);
return entry;
}
@ -415,7 +415,7 @@ PassRef<Native> ShareSystem::AddFakeNative(IPluginFunction *pFunc, const char *n
CNativeOwner *owner = g_PluginSys.GetPluginByCtx(fake->ctx->GetContext());
entry = Newborn<Native>(new Native(owner, fake.take()));
entry = new Native(owner, fake.take());
m_NtvCache.insert(name, entry);
return entry;

View File

@ -83,6 +83,7 @@ class IFileSystem_Logic
public:
virtual const char *FindFirstEx(const char *pWildCard, const char *pPathID, FileFindHandle_t *pHandle) = 0;
virtual const char *FindNext(FileFindHandle_t handle) = 0;
virtual bool FindIsDirectory(FileFindHandle_t handle) = 0;
virtual void FindClose(FileFindHandle_t handle) = 0;
virtual FileHandle_t Open(const char *pFileName, const char *pOptions, const char *pathID = 0) = 0;
virtual void Close(FileHandle_t file) = 0;
@ -90,6 +91,17 @@ public:
virtual bool EndOfFile(FileHandle_t file) = 0;
virtual bool FileExists(const char *pFileName, const char *pPathID = 0) = 0;
virtual unsigned int Size(const char *pFileName, const char *pPathID = 0) = 0;
virtual int Read(void* pOutput, int size, FileHandle_t file) = 0;
virtual int Write(void const* pInput, int size, FileHandle_t file) = 0;
virtual void Seek(FileHandle_t file, int post, int seekType) = 0;
virtual unsigned int Tell(FileHandle_t file) = 0;
virtual int FPrint(FileHandle_t file, const char *pData) = 0;
virtual void Flush(FileHandle_t file) = 0;
virtual bool IsOk(FileHandle_t file) = 0;
virtual void RemoveFile(const char *pRelativePath, const char *pathID = 0) = 0;
virtual void RenameFile(char const *pOldPath, char const *pNewPath, const char *pathID = 0) = 0;
virtual bool IsDirectory(const char *pFileName, const char *pathID = 0) = 0;
virtual void CreateDirHierarchy(const char *path, const char *pathID = 0) = 0;
};
namespace SourceMod

View File

@ -163,7 +163,7 @@ private:
cell_t data_;
};
struct CellTrie : public ke::Refcounted<CellTrie>
struct CellTrie
{
StringHashMap<Entry> map;
};
@ -204,8 +204,7 @@ public: //IHandleTypeDispatch
{
if (type == htCellTrie)
{
CellTrie *pTrie = (CellTrie *)object;
pTrie->Release();
delete (CellTrie *)object;
} else {
TrieSnapshot *snapshot = (TrieSnapshot *)object;
delete snapshot;

View File

@ -55,9 +55,135 @@
#endif
HandleType_t g_FileType;
HandleType_t g_ValveFileType;
HandleType_t g_DirType;
HandleType_t g_ValveDirType;
IChangeableForward *g_pLogHook = NULL;
enum class FSType
{
STDIO,
VALVE,
};
class FSHelper
{
public:
void SetFSType(FSType fstype)
{
_fstype = fstype;
}
public:
inline void *Open(const char *filename, const char *mode, const char *pathID)
{
if (_fstype == FSType::VALVE)
return smcore.filesystem->Open(filename, mode, pathID);
else
return fopen(filename, mode);
}
inline int Read(void *pOut, int size, void *pFile)
{
if (_fstype == FSType::VALVE)
return smcore.filesystem->Read(pOut, size, (FileHandle_t)pFile);
else
return fread(pOut, 1, size, (FILE *)pFile) * size;
}
inline char *ReadLine(char *pOut, int size, void *pFile)
{
if (_fstype == FSType::VALVE)
return smcore.filesystem->ReadLine(pOut, size, (FileHandle_t)pFile);
else
return fgets(pOut, size, (FILE *)pFile);
}
inline size_t Write(const void *pData, int size, void *pFile)
{
if (_fstype == FSType::VALVE)
return (size_t)smcore.filesystem->Write(pData, size, (FileHandle_t)pFile);
else
return fwrite(pData, 1, size, (FILE *)pFile);
}
inline void Seek(void *pFile, int pos, int seekType)
{
if (_fstype == FSType::VALVE)
smcore.filesystem->Seek((FileHandle_t)pFile, pos, seekType);
else
fseek((FILE *)pFile, pos, seekType);
}
inline int Tell(void *pFile)
{
if (_fstype == FSType::VALVE)
return smcore.filesystem->Tell((FileHandle_t)pFile);
else
return ftell((FILE *)pFile);
}
inline bool HasError(void *pFile)
{
if (_fstype == FSType::VALVE)
return !smcore.filesystem->IsOk((FileHandle_t)pFile);
else
return ferror((FILE *)pFile) != 0;
}
inline void Close(void *pFile)
{
if (_fstype == FSType::VALVE)
smcore.filesystem->Close((FileHandle_t)pFile);
else
fclose((FILE *)pFile);
}
inline bool Remove(const char *pFilePath, const char *pathID)
{
if (_fstype == FSType::VALVE)
{
if (!smcore.filesystem->FileExists(pFilePath, pathID))
return false;
smcore.filesystem->RemoveFile(pFilePath, pathID);
if (smcore.filesystem->FileExists(pFilePath, pathID))
return false;
return true;
}
else
{
return unlink(pFilePath) == 0;
}
}
inline bool EndOfFile(void *pFile)
{
if (_fstype == FSType::VALVE)
return smcore.filesystem->EndOfFile((FileHandle_t)pFile);
else
return feof((FILE *)pFile) != 0;
}
inline bool Flush(void *pFile)
{
if (_fstype == FSType::VALVE)
return smcore.filesystem->Flush((FileHandle_t)pFile), true;
else
return fflush((FILE *)pFile) == 0;
}
private:
FSType _fstype;
};
struct ValveDirectory
{
FileFindHandle_t hndl;
char szFirstPath[PLATFORM_MAX_PATH];
bool bHandledFirstPath;
};
class FileNatives :
public SMGlobalClass,
public IHandleTypeDispatch,
@ -70,7 +196,9 @@ public:
virtual void OnSourceModAllInitialized()
{
g_FileType = handlesys->CreateType("File", this, 0, NULL, NULL, g_pCoreIdent, NULL);
g_ValveFileType = handlesys->CreateType("ValveFile", this, 0, NULL, NULL, g_pCoreIdent, NULL);
g_DirType = handlesys->CreateType("Directory", this, 0, NULL, NULL, g_pCoreIdent, NULL);
g_ValveDirType = handlesys->CreateType("ValveDirectory", this, 0, NULL, NULL, g_pCoreIdent, NULL);
g_pLogHook = forwardsys->CreateForwardEx(NULL, ET_Hook, 1, NULL, Param_String);
pluginsys->AddPluginsListener(this);
}
@ -80,8 +208,12 @@ public:
forwardsys->ReleaseForward(g_pLogHook);
handlesys->RemoveType(g_DirType, g_pCoreIdent);
handlesys->RemoveType(g_FileType, g_pCoreIdent);
handlesys->RemoveType(g_ValveFileType, g_pCoreIdent);
handlesys->RemoveType(g_ValveDirType, g_pCoreIdent);
g_DirType = 0;
g_FileType = 0;
g_ValveFileType = 0;
g_ValveDirType = 0;
}
virtual void OnHandleDestroy(HandleType_t type, void *object)
{
@ -95,6 +227,17 @@ public:
IDirectory *pDir = (IDirectory *)object;
libsys->CloseDirectory(pDir);
}
else if (type == g_ValveFileType)
{
FileHandle_t fp = (FileHandle_t) object;
smcore.filesystem->Close(fp);
}
else if (type == g_ValveDirType)
{
ValveDirectory *valveDir = (ValveDirectory *)object;
smcore.filesystem->FindClose(valveDir->hndl);
delete valveDir;
}
}
virtual void AddLogHook(IPluginFunction *pFunc)
{
@ -127,23 +270,56 @@ static cell_t sm_OpenDirectory(IPluginContext *pContext, const cell_t *params)
pContext->ThrowNativeErrorEx(err, NULL);
return 0;
}
char realpath[PLATFORM_MAX_PATH];
g_pSM->BuildPath(Path_Game, realpath, sizeof(realpath), "%s", path);
IDirectory *pDir = libsys->OpenDirectory(realpath);
if (!pDir)
Handle_t handle = 0;
if (params[0] >= 2 && params[2])
{
return 0;
char wildcardedPath[PLATFORM_MAX_PATH];
snprintf(wildcardedPath, sizeof(wildcardedPath), "%s*", path);
ValveDirectory *valveDir = new ValveDirectory;
char *pathID;
if ((err=pContext->LocalToStringNULL(params[3], &pathID)) != SP_ERROR_NONE)
{
pContext->ThrowNativeErrorEx(err, NULL);
return 0;
}
const char *pFirst = smcore.filesystem->FindFirstEx(wildcardedPath, pathID, &valveDir->hndl);
if (pFirst)
{
valveDir->bHandledFirstPath = false;
strncpy(valveDir->szFirstPath, pFirst, sizeof(valveDir->szFirstPath));
}
else
{
valveDir->bHandledFirstPath = true;
}
handle = handlesys->CreateHandle(g_ValveDirType, valveDir, pContext->GetIdentity(), g_pCoreIdent, NULL);
}
else
{
char realpath[PLATFORM_MAX_PATH];
g_pSM->BuildPath(Path_Game, realpath, sizeof(realpath), "%s", path);
return handlesys->CreateHandle(g_DirType, pDir, pContext->GetIdentity(), g_pCoreIdent, NULL);
IDirectory *pDir = libsys->OpenDirectory(realpath);
if (!pDir)
{
return 0;
}
handle = handlesys->CreateHandle(g_DirType, pDir, pContext->GetIdentity(), g_pCoreIdent, NULL);
}
return handle;
}
static cell_t sm_ReadDirEntry(IPluginContext *pContext, const cell_t *params)
{
Handle_t hndl = static_cast<Handle_t>(params[1]);
IDirectory *pDir;
void *pTempDir;
HandleError herr;
HandleSecurity sec;
int err;
@ -151,44 +327,90 @@ static cell_t sm_ReadDirEntry(IPluginContext *pContext, const cell_t *params)
sec.pOwner = NULL;
sec.pIdentity = g_pCoreIdent;
if ((herr=handlesys->ReadHandle(hndl, g_DirType, &sec, (void **)&pDir))
!= HandleError_None)
if ((herr=handlesys->ReadHandle(hndl, g_DirType, &sec, &pTempDir)) == HandleError_None)
{
IDirectory *pDir = (IDirectory *)pTempDir;
if (!pDir->MoreFiles())
{
return 0;
}
cell_t *filetype;
if ((err=pContext->LocalToPhysAddr(params[4], &filetype)) != SP_ERROR_NONE)
{
pContext->ThrowNativeErrorEx(err, NULL);
return 0;
}
if (pDir->IsEntryDirectory())
{
*filetype = 1;
} else if (pDir->IsEntryFile()) {
*filetype = 2;
} else {
*filetype = 0;
}
const char *path = pDir->GetEntryName();
if ((err=pContext->StringToLocalUTF8(params[2], params[3], path, NULL))
!= SP_ERROR_NONE)
{
return pContext->ThrowNativeErrorEx(err, NULL);
}
pDir->NextEntry();
}
else if ((herr=handlesys->ReadHandle(hndl, g_ValveDirType, &sec, &pTempDir)) == HandleError_None)
{
ValveDirectory *valveDir = (ValveDirectory *)pTempDir;
const char *pEntry = NULL;
if (!valveDir->bHandledFirstPath)
{
if (valveDir->szFirstPath[0])
{
pEntry = valveDir->szFirstPath;
}
}
else
{
pEntry = smcore.filesystem->FindNext(valveDir->hndl);
}
valveDir->bHandledFirstPath = true;
// No more entries
if (!pEntry)
{
return 0;
}
if ((err=pContext->StringToLocalUTF8(params[2], params[3], pEntry, NULL))
!= SP_ERROR_NONE)
{
return pContext->ThrowNativeErrorEx(err, NULL);
}
cell_t *filetype;
if ((err=pContext->LocalToPhysAddr(params[4], &filetype)) != SP_ERROR_NONE)
{
pContext->ThrowNativeErrorEx(err, NULL);
return 0;
}
if (smcore.filesystem->FindIsDirectory(valveDir->hndl))
{
*filetype = 1;
} else {
*filetype = 2;
}
}
else
{
return pContext->ThrowNativeError("Invalid file handle %x (error %d)", hndl, herr);
}
if (!pDir->MoreFiles())
{
return false;
}
cell_t *filetype;
if ((err=pContext->LocalToPhysAddr(params[4], &filetype)) != SP_ERROR_NONE)
{
pContext->ThrowNativeErrorEx(err, NULL);
return 0;
}
if (pDir->IsEntryDirectory())
{
*filetype = 1;
} else if (pDir->IsEntryFile()) {
*filetype = 2;
} else {
*filetype = 0;
}
const char *path = pDir->GetEntryName();
if ((err=pContext->StringToLocalUTF8(params[2], params[3], path, NULL))
!= SP_ERROR_NONE)
{
pContext->ThrowNativeErrorEx(err, NULL);
return 0;
}
pDir->NextEntry();
return true;
return 1;
}
static cell_t sm_OpenFile(IPluginContext *pContext, const cell_t *params)
@ -206,16 +428,40 @@ static cell_t sm_OpenFile(IPluginContext *pContext, const cell_t *params)
return 0;
}
char realpath[PLATFORM_MAX_PATH];
g_pSM->BuildPath(Path_Game, realpath, sizeof(realpath), "%s", name);
FILE *pFile = fopen(realpath, mode);
if (!pFile)
Handle_t handle = 0;
HandleType_t handleType;
FSHelper fshelper;
const char *openpath;
char *pathID;
if (params[0] <= 2 || !params[3])
{
return 0;
handleType = g_FileType;
fshelper.SetFSType(FSType::STDIO);
char realpath[PLATFORM_MAX_PATH];
g_pSM->BuildPath(Path_Game, realpath, sizeof(realpath), "%s", name);
openpath = realpath;
}
else
{
if ((err=pContext->LocalToStringNULL(params[4], &pathID)) != SP_ERROR_NONE)
{
pContext->ThrowNativeErrorEx(err, NULL);
return 0;
}
handleType = g_ValveFileType;
fshelper.SetFSType(FSType::VALVE);
openpath = name;
}
return handlesys->CreateHandle(g_FileType, pFile, pContext->GetIdentity(), g_pCoreIdent, NULL);
void *pFile = fshelper.Open(openpath, mode, pathID);
if (pFile)
{
handle = handlesys->CreateHandle(handleType, pFile, pContext->GetIdentity(), g_pCoreIdent, NULL);
}
return handle;
}
static cell_t sm_DeleteFile(IPluginContext *pContext, const cell_t *params)
@ -228,10 +474,29 @@ static cell_t sm_DeleteFile(IPluginContext *pContext, const cell_t *params)
return 0;
}
char realpath[PLATFORM_MAX_PATH];
g_pSM->BuildPath(Path_Game, realpath, sizeof(realpath), "%s", name);
FSHelper fshelper;
const char *filepath;
char *pathID;
if (params[0] < 2 || !params[2])
{
fshelper.SetFSType(FSType::STDIO);
char realpath[PLATFORM_MAX_PATH];
g_pSM->BuildPath(Path_Game, realpath, sizeof(realpath), "%s", name);
filepath = realpath;
}
else
{
if ((err=pContext->LocalToStringNULL(params[3], &pathID)) != SP_ERROR_NONE)
{
pContext->ThrowNativeErrorEx(err, NULL);
return 0;
}
fshelper.SetFSType(FSType::VALVE);
filepath = name;
}
return (unlink(realpath)) ? 0 : 1;
return fshelper.Remove(filepath, pathID) ? 1 : 0;
}
static cell_t sm_ReadFileLine(IPluginContext *pContext, const cell_t *params)
@ -239,18 +504,12 @@ static cell_t sm_ReadFileLine(IPluginContext *pContext, const cell_t *params)
Handle_t hndl = static_cast<Handle_t>(params[1]);
HandleError herr;
HandleSecurity sec;
FILE *pFile;
int err;
void *pFile;
sec.pOwner = NULL;
sec.pIdentity = g_pCoreIdent;
if ((herr=handlesys->ReadHandle(hndl, g_FileType, &sec, (void **)&pFile))
!= HandleError_None)
{
return pContext->ThrowNativeError("Invalid file handle %x (error %d)", hndl, herr);
}
char *buf;
if ((err=pContext->LocalToString(params[2], &buf)) != SP_ERROR_NONE)
{
@ -258,12 +517,22 @@ static cell_t sm_ReadFileLine(IPluginContext *pContext, const cell_t *params)
return 0;
}
if (fgets(buf, params[3], pFile) == NULL)
FSHelper fshelper;
if ((herr = handlesys->ReadHandle(hndl, g_FileType, &sec, &pFile)) == HandleError_None)
{
return 0;
fshelper.SetFSType(FSType::STDIO);
}
else if ((herr = handlesys->ReadHandle(hndl, g_ValveFileType, &sec, &pFile)) == HandleError_None)
{
fshelper.SetFSType(FSType::VALVE);
}
else
{
return pContext->ThrowNativeError("Invalid file handle %x (error %d)", hndl, herr);
}
return 1;
return fshelper.ReadLine(buf, params[3], pFile) == NULL ? 0 : 1;
}
static cell_t sm_IsEndOfFile(IPluginContext *pContext, const cell_t *params)
@ -271,18 +540,26 @@ static cell_t sm_IsEndOfFile(IPluginContext *pContext, const cell_t *params)
Handle_t hndl = static_cast<Handle_t>(params[1]);
HandleError herr;
HandleSecurity sec;
FILE *pFile;
void *pFile;
sec.pOwner = NULL;
sec.pIdentity = g_pCoreIdent;
if ((herr=handlesys->ReadHandle(hndl, g_FileType, &sec, (void **)&pFile))
!= HandleError_None)
FSHelper fshelper;
if ((herr = handlesys->ReadHandle(hndl, g_FileType, &sec, &pFile)) == HandleError_None)
{
fshelper.SetFSType(FSType::STDIO);
}
else if ((herr = handlesys->ReadHandle(hndl, g_ValveFileType, &sec, &pFile)) == HandleError_None)
{
fshelper.SetFSType(FSType::VALVE);
}
else
{
return pContext->ThrowNativeError("Invalid file handle %x (error %d)", hndl, herr);
}
return (feof(pFile)) ? 1 : 0;
return fshelper.EndOfFile(pFile) ? 1 : 0;
}
static cell_t sm_FileSeek(IPluginContext *pContext, const cell_t *params)
@ -290,18 +567,26 @@ static cell_t sm_FileSeek(IPluginContext *pContext, const cell_t *params)
Handle_t hndl = static_cast<Handle_t>(params[1]);
HandleError herr;
HandleSecurity sec;
FILE *pFile;
void *pFile;
sec.pOwner = NULL;
sec.pIdentity = g_pCoreIdent;
if ((herr=handlesys->ReadHandle(hndl, g_FileType, &sec, (void **)&pFile))
!= HandleError_None)
FSHelper fshelper;
if ((herr = handlesys->ReadHandle(hndl, g_FileType, &sec, &pFile)) == HandleError_None)
{
fshelper.SetFSType(FSType::STDIO);
}
else if ((herr = handlesys->ReadHandle(hndl, g_ValveFileType, &sec, &pFile)) == HandleError_None)
{
fshelper.SetFSType(FSType::VALVE);
}
else
{
return pContext->ThrowNativeError("Invalid file handle %x (error %d)", hndl, herr);
}
fseek(pFile, params[2], params[3]);
fshelper.Seek(pFile, params[2], params[3]);
return 1;
}
@ -311,18 +596,27 @@ static cell_t sm_FilePosition(IPluginContext *pContext, const cell_t *params)
Handle_t hndl = static_cast<Handle_t>(params[1]);
HandleError herr;
HandleSecurity sec;
FILE *pFile;
void *pFile;
sec.pOwner = NULL;
sec.pIdentity = g_pCoreIdent;
if ((herr=handlesys->ReadHandle(hndl, g_FileType, &sec, (void **)&pFile))
!= HandleError_None)
FSHelper fshelper;
if ((herr = handlesys->ReadHandle(hndl, g_FileType, &sec, &pFile)) == HandleError_None)
{
fshelper.SetFSType(FSType::STDIO);
}
else if ((herr = handlesys->ReadHandle(hndl, g_ValveFileType, &sec, &pFile)) == HandleError_None)
{
fshelper.SetFSType(FSType::VALVE);
}
else
{
return pContext->ThrowNativeError("Invalid file handle %x (error %d)", hndl, herr);
}
return ftell(pFile);
return (cell_t)fshelper.Tell(pFile);
}
static cell_t sm_FileExists(IPluginContext *pContext, const cell_t *params)
@ -337,7 +631,17 @@ static cell_t sm_FileExists(IPluginContext *pContext, const cell_t *params)
if (params[0] >= 2 && params[2] == 1)
{
return smcore.filesystem->FileExists(name) ? 1 : 0;
char *pathID = NULL;
if (params[0] >= 3)
{
if ((err=pContext->LocalToStringNULL(params[3], &pathID)) != SP_ERROR_NONE)
{
pContext->ThrowNativeErrorEx(err, NULL);
return 0;
}
}
return smcore.filesystem->FileExists(name, pathID) ? 1 : 0;
}
char realpath[PLATFORM_MAX_PATH];
@ -381,6 +685,19 @@ static cell_t sm_RenameFile(IPluginContext *pContext, const cell_t *params)
pContext->ThrowNativeErrorEx(err, NULL);
return 0;
}
if (params[0] >= 3 && params[3] == 1)
{
char *pathID;
if ((err=pContext->LocalToStringNULL(params[4], &pathID)) != SP_ERROR_NONE)
{
pContext->ThrowNativeErrorEx(err, NULL);
return 0;
}
smcore.filesystem->RenameFile(oldpath, newpath, pathID);
return 1;
}
char new_realpath[PLATFORM_MAX_PATH];
g_pSM->BuildPath(Path_Game, new_realpath, sizeof(new_realpath), "%s", newpath);
@ -403,6 +720,18 @@ static cell_t sm_DirExists(IPluginContext *pContext, const cell_t *params)
pContext->ThrowNativeErrorEx(err, NULL);
return 0;
}
if (params[0] >= 2 && params[2] == 1)
{
char *pathID;
if ((err=pContext->LocalToStringNULL(params[3], &pathID)) != SP_ERROR_NONE)
{
pContext->ThrowNativeErrorEx(err, NULL);
return 0;
}
return smcore.filesystem->IsDirectory(name, pathID) ? 1 : 0;
}
char realpath[PLATFORM_MAX_PATH];
g_pSM->BuildPath(Path_Game, realpath, sizeof(realpath), "%s", name);
@ -443,9 +772,19 @@ static cell_t sm_FileSize(IPluginContext *pContext, const cell_t *params)
if (params[0] >= 2 && params[2] == 1)
{
if (smcore.filesystem->FileExists(name))
char *pathID = NULL;
if (params[0] >= 3)
{
return smcore.filesystem->Size(name);
if ((err=pContext->LocalToStringNULL(params[3], &pathID)) != SP_ERROR_NONE)
{
pContext->ThrowNativeErrorEx(err, NULL);
return -1;
}
}
if (smcore.filesystem->FileExists(name, pathID))
{
return smcore.filesystem->Size(name, pathID);
}
else
{
@ -508,9 +847,29 @@ static cell_t sm_SetFilePermissions(IPluginContext *pContext, const cell_t *para
static cell_t sm_CreateDirectory(IPluginContext *pContext, const cell_t *params)
{
char *name;
char realpath[PLATFORM_MAX_PATH];
pContext->LocalToString(params[1], &name);
if (params[0] >= 3 && params[3] == 1)
{
int err;
char *pathID;
if ((err=pContext->LocalToStringNULL(params[4], &pathID)) != SP_ERROR_NONE)
{
return pContext->ThrowNativeErrorEx(err, NULL);
}
if (smcore.filesystem->IsDirectory(name, pathID))
return 0;
smcore.filesystem->CreateDirHierarchy(name, pathID);
if (smcore.filesystem->IsDirectory(name, pathID))
return 1;
return 0;
}
char realpath[PLATFORM_MAX_PATH];
g_pSM->BuildPath(Path_Game, realpath, sizeof(realpath), "%s", name);
#if defined PLATFORM_WINDOWS
@ -541,19 +900,14 @@ static cell_t sm_WriteFileLine(IPluginContext *pContext, const cell_t *params)
Handle_t hndl = static_cast<Handle_t>(params[1]);
HandleError herr;
HandleSecurity sec;
FILE *pFile;
void *pTempFile;
sec.pOwner = NULL;
sec.pIdentity = g_pCoreIdent;
if ((herr=handlesys->ReadHandle(hndl, g_FileType, &sec, (void **)&pFile))
!= HandleError_None)
{
return pContext->ThrowNativeError("Invalid file handle %x (error %d)", hndl, herr);
}
char *fmt;
int err;
if ((err=pContext->LocalToString(params[2], &fmt)) != SP_ERROR_NONE)
{
pContext->ThrowNativeErrorEx(err, NULL);
@ -562,8 +916,23 @@ static cell_t sm_WriteFileLine(IPluginContext *pContext, const cell_t *params)
char buffer[2048];
int arg = 3;
smcore.atcprintf(buffer, sizeof(buffer), fmt, pContext, params, &arg);
fprintf(pFile, "%s\n", buffer);
if ((herr = handlesys->ReadHandle(hndl, g_FileType, &sec, &pTempFile)) == HandleError_None)
{
FILE *pFile = (FILE *) pTempFile;
smcore.atcprintf(buffer, sizeof(buffer), fmt, pContext, params, &arg);
fprintf(pFile, "%s\n", buffer);
}
else if ((herr = handlesys->ReadHandle(hndl, g_ValveFileType, &sec, &pTempFile)) == HandleError_None)
{
FileHandle_t pFile = (FileHandle_t) pTempFile;
smcore.atcprintf(buffer, sizeof(buffer), fmt, pContext, params, &arg);
sprintf(buffer, "%s\n", buffer);
smcore.filesystem->FPrint(pFile, buffer);
}
else
{
return pContext->ThrowNativeError("Invalid file handle %x (error %d)", hndl, herr);
}
return 1;
}
@ -573,18 +942,26 @@ static cell_t sm_FlushFile(IPluginContext *pContext, const cell_t *params)
Handle_t hndl = static_cast<Handle_t>(params[1]);
HandleError herr;
HandleSecurity sec;
FILE *pFile;
void *pFile;
sec.pOwner = NULL;
sec.pIdentity = g_pCoreIdent;
if ((herr=handlesys->ReadHandle(hndl, g_FileType, &sec, (void **)&pFile))
!= HandleError_None)
FSHelper fshelper;
if ((herr = handlesys->ReadHandle(hndl, g_FileType, &sec, &pFile)) == HandleError_None)
{
fshelper.SetFSType(FSType::STDIO);
}
else if ((herr = handlesys->ReadHandle(hndl, g_ValveFileType, &sec, &pFile)) == HandleError_None)
{
fshelper.SetFSType(FSType::VALVE);
}
else
{
return pContext->ThrowNativeError("Invalid file handle %x (error %d)", hndl, herr);
}
return (fflush(pFile) == 0) ? 1 : 0;
return fshelper.Flush(pFile) ? 1 : 0;
}
static cell_t sm_BuildPath(IPluginContext *pContext, const cell_t *params)
@ -749,11 +1126,20 @@ static cell_t sm_ReadFile(IPluginContext *pContext, const cell_t *params)
Handle_t hndl = static_cast<Handle_t>(params[1]);
HandleError herr;
HandleSecurity sec(pContext->GetIdentity(), g_pCoreIdent);
FILE *pFile;
size_t read = 0;
if ((herr=handlesys->ReadHandle(hndl, g_FileType, &sec, (void **)&pFile))
!= HandleError_None)
void *pFile = NULL;
FSHelper fshelper;
if ((herr = handlesys->ReadHandle(hndl, g_FileType, &sec, &pFile)) == HandleError_None)
{
fshelper.SetFSType(FSType::STDIO);
}
else if ((herr = handlesys->ReadHandle(hndl, g_ValveFileType, &sec, &pFile)) == HandleError_None)
{
fshelper.SetFSType(FSType::VALVE);
}
else
{
return pContext->ThrowNativeError("Invalid file handle %x (error %d)", hndl, herr);
}
@ -765,21 +1151,21 @@ static cell_t sm_ReadFile(IPluginContext *pContext, const cell_t *params)
cell_t *data;
pContext->LocalToPhysAddr(params[2], &data);
if (params[4] == 4)
{
read = fread(data, sizeof(cell_t), params[3], pFile);
read = fshelper.Read(data, sizeof(cell_t) * params[3], pFile);
}
else if (params[4] == 2)
{
uint16_t val;
for (cell_t i = 0; i < params[3]; i++)
{
if (fread(&val, sizeof(uint16_t), 1, pFile) != 1)
if (fshelper.Read(&val, sizeof(uint16_t), pFile) != 1)
{
break;
}
data[read++] = val;
data[read += sizeof(uint16_t)] = val;
}
}
else if (params[4] == 1)
@ -787,20 +1173,20 @@ static cell_t sm_ReadFile(IPluginContext *pContext, const cell_t *params)
uint8_t val;
for (cell_t i = 0; i < params[3]; i++)
{
if (fread(&val, sizeof(uint8_t), 1, pFile) != 1)
if (fshelper.Read(&val, sizeof(uint8_t), pFile) != 1)
{
break;
}
data[read++] = val;
data[read += sizeof(uint8_t)] = val;
}
}
if (read != (size_t)params[3] && ferror(pFile) != 0)
if (read != ((size_t)params[3] * params[4]) && fshelper.HasError(pFile))
{
return -1;
}
return read;
return read / params[4];
}
static cell_t sm_ReadFileString(IPluginContext *pContext, const cell_t *params)
@ -808,18 +1194,27 @@ static cell_t sm_ReadFileString(IPluginContext *pContext, const cell_t *params)
Handle_t hndl = static_cast<Handle_t>(params[1]);
HandleError herr;
HandleSecurity sec(pContext->GetIdentity(), g_pCoreIdent);
FILE *pFile;
void *pFile;
cell_t num_read = 0;
if ((herr=handlesys->ReadHandle(hndl, g_FileType, &sec, (void **)&pFile))
!= HandleError_None)
{
return pContext->ThrowNativeError("Invalid file handle %x (error %d)", hndl, herr);
}
char *buffer;
pContext->LocalToString(params[2], &buffer);
FSHelper fshelper;
if ((herr=handlesys->ReadHandle(hndl, g_FileType, &sec, &pFile)) == HandleError_None)
{
fshelper.SetFSType(FSType::STDIO);
}
else if ((herr=handlesys->ReadHandle(hndl, g_ValveFileType, &sec, &pFile)) == HandleError_None)
{
fshelper.SetFSType(FSType::VALVE);
}
else
{
return pContext->ThrowNativeError("Invalid file handle %x (error %d)", hndl, herr);
}
if (params[4] != -1)
{
if (size_t(params[4]) > size_t(params[3]))
@ -829,9 +1224,9 @@ static cell_t sm_ReadFileString(IPluginContext *pContext, const cell_t *params)
params[3]);
}
num_read = (cell_t)fread(buffer, 1, params[4], pFile);
num_read = (cell_t)fshelper.Read(buffer, params[4], pFile);
if (num_read != params[4] && ferror(pFile))
if (num_read != params[4] && fshelper.HasError(pFile))
{
return -1;
}
@ -846,9 +1241,9 @@ static cell_t sm_ReadFileString(IPluginContext *pContext, const cell_t *params)
{
break;
}
if (fread(&val, sizeof(val), 1, pFile) != 1)
if (fshelper.Read(&val, sizeof(val), pFile) != 1)
{
if (ferror(pFile))
if (fshelper.HasError(pFile))
{
return -1;
}
@ -877,10 +1272,18 @@ static cell_t sm_WriteFile(IPluginContext *pContext, const cell_t *params)
Handle_t hndl = static_cast<Handle_t>(params[1]);
HandleError herr;
HandleSecurity sec(pContext->GetIdentity(), g_pCoreIdent);
FILE *pFile;
void *pFile;
FSHelper fshelper;
if ((herr=handlesys->ReadHandle(hndl, g_FileType, &sec, (void **)&pFile))
!= HandleError_None)
if ((herr=handlesys->ReadHandle(hndl, g_FileType, &sec, &pFile)) == HandleError_None)
{
fshelper.SetFSType(FSType::STDIO);
}
else if ((herr=handlesys->ReadHandle(hndl, g_ValveFileType, &sec, &pFile)) == HandleError_None)
{
fshelper.SetFSType(FSType::VALVE);
}
else
{
return pContext->ThrowNativeError("Invalid file handle %x (error %d)", hndl, herr);
}
@ -897,7 +1300,7 @@ static cell_t sm_WriteFile(IPluginContext *pContext, const cell_t *params)
if (params[4] == 4)
{
if (fwrite(data, sizeof(cell_t), params[3], pFile) != (size_t)params[3])
if (fshelper.Write(data, sizeof(cell_t) * params[3], pFile) != (sizeof(cell_t) * (size_t)params[3]))
{
return 0;
}
@ -906,7 +1309,7 @@ static cell_t sm_WriteFile(IPluginContext *pContext, const cell_t *params)
{
for (cell_t i = 0; i < params[3]; i++)
{
if (fwrite(&data[i], sizeof(int16_t), 1, pFile) != 1)
if (fshelper.Write(&data[i], sizeof(int16_t), pFile) != sizeof(int16_t))
{
return 0;
}
@ -916,7 +1319,7 @@ static cell_t sm_WriteFile(IPluginContext *pContext, const cell_t *params)
{
for (cell_t i = 0; i < params[3]; i++)
{
if (fwrite(&data[i], sizeof(int8_t), 1, pFile) != 1)
if (fshelper.Write(&data[i], sizeof(int8_t), pFile) != sizeof(int8_t))
{
return 0;
}
@ -931,10 +1334,18 @@ static cell_t sm_WriteFileString(IPluginContext *pContext, const cell_t *params)
Handle_t hndl = static_cast<Handle_t>(params[1]);
HandleError herr;
HandleSecurity sec(pContext->GetIdentity(), g_pCoreIdent);
FILE *pFile;
void *pFile;
FSHelper fshelper;
if ((herr=handlesys->ReadHandle(hndl, g_FileType, &sec, (void **)&pFile))
!= HandleError_None)
if ((herr=handlesys->ReadHandle(hndl, g_FileType, &sec, &pFile)) == HandleError_None)
{
fshelper.SetFSType(FSType::STDIO);
}
else if ((herr=handlesys->ReadHandle(hndl, g_ValveFileType, &sec, &pFile)) == HandleError_None)
{
fshelper.SetFSType(FSType::VALVE);
}
else
{
return pContext->ThrowNativeError("Invalid file handle %x (error %d)", hndl, herr);
}
@ -949,7 +1360,7 @@ static cell_t sm_WriteFileString(IPluginContext *pContext, const cell_t *params)
len++;
}
return (fwrite(buffer, sizeof(char), len, pFile) == len) ? 1 : 0;
return (fshelper.Write(buffer, len, pFile) == len) ? 1 : 0;
}
static cell_t sm_AddGameLogHook(IPluginContext *pContext, const cell_t *params)

View File

@ -36,6 +36,7 @@
#include "MersenneTwister.h"
#include <IPluginSys.h>
#include <am-utility.h>
#include <am-float.h>
/****************************************
* *

View File

@ -37,12 +37,21 @@
#include <ITranslator.h>
#include <sh_string.h>
#include <sh_list.h>
#include "GameConfigs.h"
#include "CellArray.h"
#include "AutoHandleRooter.h"
using namespace SourceHook;
using namespace SourceMod;
#ifndef PRIu64
#ifdef _WIN32
#define PRIu64 "I64u"
#else
#define PRIu64 "llu"
#endif
#endif
static const int kActivityNone = 0;
static const int kActivityNonAdmins = 1; // Show admin activity to non-admins anonymously.
static const int kActivityNonAdminsNames = 2; // If 1 is specified, admin names will be shown.
@ -322,9 +331,17 @@ static cell_t sm_GetClientIP(IPluginContext *pCtx, const cell_t *params)
return 1;
}
static cell_t sm_GetClientAuthStr(IPluginContext *pCtx, const cell_t *params)
// Must match clients.inc
enum class AuthIdType
{
Engine = 0,
Steam2,
Steam3,
SteamId64,
};
static cell_t SteamIdToLocal(IPluginContext *pCtx, int index, AuthIdType authType, cell_t local_addr, size_t bytes, bool validate)
{
int index = params[1];
if ((index < 1) || (index > playerhelpers->GetMaxClients()))
{
return pCtx->ThrowNativeError("Client index %d is invalid", index);
@ -336,24 +353,113 @@ static cell_t sm_GetClientAuthStr(IPluginContext *pCtx, const cell_t *params)
return pCtx->ThrowNativeError("Client %d is not connected", index);
}
bool validate = true;
if (params[0] > 3)
{
validate = !!params[4];
}
const char *authstr = pPlayer->GetAuthString(validate);
if (!authstr || authstr[0] == '\0')
switch (authType)
{
return 0;
}
case AuthIdType::Engine:
{
const char *authstr = pPlayer->GetAuthString(validate);
if (!authstr || authstr[0] == '\0')
{
return 0;
}
pCtx->StringToLocal(params[2], static_cast<size_t>(params[3]), authstr);
pCtx->StringToLocal(local_addr, bytes, authstr);
}
break;
case AuthIdType::Steam2:
case AuthIdType::Steam3:
{
if (pPlayer->IsFakeClient())
{
pCtx->StringToLocal(local_addr, bytes, "BOT");
return 1;
}
uint64_t steamId = pPlayer->GetSteamId64(validate);
if (steamId == 0)
{
if (gamehelpers->IsLANServer())
{
pCtx->StringToLocal(local_addr, bytes, "STEAM_ID_LAN");
return 1;
}
else if (!validate)
{
pCtx->StringToLocal(local_addr, bytes, "STEAM_ID_PENDING");
return 1;
}
else
{
return 0;
}
}
char szAuth[64];
unsigned int universe = steamId >> 56;
unsigned int accountId = steamId & 0xFFFFFFFF;
unsigned int instance = (steamId >> 32) & 0x000FFFFF;
if (authType == AuthIdType::Steam2)
{
if (atoi(g_pGameConf->GetKeyValue("UseInvalidUniverseInSteam2IDs")) == 1)
{
universe = 0;
}
snprintf(szAuth, sizeof(szAuth), "STEAM_%u:%u:%u", universe, accountId & 1, accountId >> 1);
}
else if (instance != 1)
{
snprintf(szAuth, sizeof(szAuth), "[U:%u:%u:%u]", universe, accountId, instance);
}
else
{
snprintf(szAuth, sizeof(szAuth), "[U:%u:%u]", universe, accountId);
}
pCtx->StringToLocal(local_addr, bytes, szAuth);
}
break;
case AuthIdType::SteamId64:
{
if (pPlayer->IsFakeClient() || gamehelpers->IsLANServer())
{
return 0;
}
uint64_t steamId = pPlayer->GetSteamId64(validate);
if (steamId == 0)
{
return 0;
}
char szAuth[64];
snprintf(szAuth, sizeof(szAuth), "%" PRIu64, steamId);
pCtx->StringToLocal(local_addr, bytes, szAuth);
}
break;
}
return 1;
}
static cell_t sm_GetClientAuthStr(IPluginContext *pCtx, const cell_t *params)
{
bool validate = true;
if (params[0] >= 4)
{
validate = !!params[4];
}
return SteamIdToLocal(pCtx, params[1], AuthIdType::Steam2, params[2], (size_t)params[3], validate);
}
static cell_t sm_GetClientAuthId(IPluginContext *pCtx, const cell_t *params)
{
return SteamIdToLocal(pCtx, params[1], (AuthIdType)params[2], params[3], (size_t)params[4], params[5] != 0);
}
static cell_t sm_GetSteamAccountID(IPluginContext *pCtx, const cell_t *params)
{
int index = params[1];
@ -1540,6 +1646,7 @@ REGISTER_NATIVES(playernatives)
{ "CanUserTarget", CanUserTarget },
{ "ChangeClientTeam", ChangeClientTeam },
{ "GetClientAuthString", sm_GetClientAuthStr },
{ "GetClientAuthId", sm_GetClientAuthId },
{ "GetSteamAccountID", sm_GetSteamAccountID },
{ "GetClientCount", sm_GetClientCount },
{ "GetClientInfo", sm_GetClientInfo },

View File

@ -147,6 +147,10 @@ public:
{
return filesystem->FindNext(handle);
}
bool FindIsDirectory(FileFindHandle_t handle)
{
return filesystem->FindIsDirectory(handle);
}
void FindClose(FileFindHandle_t handle)
{
filesystem->FindClose(handle);
@ -175,6 +179,50 @@ public:
{
return filesystem->Size(pFileName, pPathID);
}
int Read(void* pOutput, int size, FileHandle_t file)
{
return filesystem->Read(pOutput, size, file);
}
int Write(void const* pInput, int size, FileHandle_t file)
{
return filesystem->Write(pInput, size, file);
}
void Seek(FileHandle_t file, int pos, int seekType)
{
filesystem->Seek(file, pos, (FileSystemSeek_t) seekType);
}
unsigned int Tell(FileHandle_t file)
{
return filesystem->Tell(file);
}
int FPrint(FileHandle_t file, const char *pData)
{
return filesystem->FPrintf(file, "%s", pData);
}
void Flush(FileHandle_t file)
{
filesystem->Flush(file);
}
bool IsOk(FileHandle_t file)
{
return filesystem->IsOk(file);
}
void RemoveFile(const char *pRelativePath, const char *pathID)
{
filesystem->RemoveFile(pRelativePath, pathID);
}
void RenameFile(char const *pOldPath, char const *pNewPath, const char *pathID)
{
filesystem->RenameFile(pOldPath, pNewPath, pathID);
}
bool IsDirectory(const char *pFileName, const char *pathID)
{
return filesystem->IsDirectory(pFileName, pathID);
}
void CreateDirHierarchy(const char *path, const char *pathID)
{
filesystem->CreateDirHierarchy(path, pathID);
}
};
static VFileSystem_Logic logic_filesystem;

View File

@ -39,6 +39,7 @@
#include "logic_bridge.h"
#include "sourcemod.h"
#include <am-utility.h>
#include <am-float.h>
#define LADJUST 0x00000004 /* left adjustment */
#define ZEROPAD 0x00000080 /* zero (as opposed to blank) pad */

View File

@ -219,7 +219,7 @@ void ClientPrefs::DatabaseConnect()
char error[256];
int errCode = 0;
Database = Newborn<IDatabase>(Driver->Connect(DBInfo, true, error, sizeof(error)));
Database = AdoptRef(Driver->Connect(DBInfo, true, error, sizeof(error)));
if (!Database)
{

View File

@ -101,6 +101,9 @@ MyDatabase::MyDatabase(MYSQL *mysql, const DatabaseInfo *info, bool persistent)
m_Info.driver = NULL;
m_Info.maxTimeout = info->maxTimeout;
m_Info.port = info->port;
// DBI, for historical reasons, guarantees an initial refcount of 1.
AddRef();
}
MyDatabase::~MyDatabase()

View File

@ -88,6 +88,10 @@ HookTypeData g_HookTypes[SDKHook_MAXHOOKS] =
{"Reload", "DT_BaseCombatWeapon", false},
{"ReloadPost", "DT_BaseCombatWeapon", false},
{"GetMaxHealth", "", false},
{"Blocked", "", false},
{"BlockedPost", "", false},
{"OnTakeDamageAlive", "DT_BaseCombatCharacter", false},
{"OnTakeDamageAlivePost", "DT_BaseCombatCharacter", false},
};
SDKHooks g_Interface;
@ -166,6 +170,7 @@ SH_DECL_MANUALHOOK0(GetMaxHealth, 0, 0, 0, int);
#endif
SH_DECL_MANUALHOOK1_void(GroundEntChanged, 0, 0, 0, void *);
SH_DECL_MANUALHOOK1(OnTakeDamage, 0, 0, 0, int, CTakeDamageInfoHack &);
SH_DECL_MANUALHOOK1(OnTakeDamageAlive, 0, 0, 0, int, CTakeDamageInfoHack &);
SH_DECL_MANUALHOOK0_void(PreThink, 0, 0, 0);
SH_DECL_MANUALHOOK0_void(PostThink, 0, 0, 0);
SH_DECL_MANUALHOOK0(Reload, 0, 0, 0, bool);
@ -191,6 +196,7 @@ SH_DECL_MANUALHOOK1(Weapon_CanUse, 0, 0, 0, bool, CBaseCombatWeapon *);
SH_DECL_MANUALHOOK3_void(Weapon_Drop, 0, 0, 0, CBaseCombatWeapon *, const Vector *, const Vector *);
SH_DECL_MANUALHOOK1_void(Weapon_Equip, 0, 0, 0, CBaseCombatWeapon *);
SH_DECL_MANUALHOOK2(Weapon_Switch, 0, 0, 0, bool, CBaseCombatWeapon *, int);
SH_DECL_MANUALHOOK1_void(Blocked, 0, 0, 0, CBaseEntity *);
/**
@ -512,6 +518,7 @@ void SDKHooks::SetupHooks()
CHECKOFFSET(FireBullets, false, true);
CHECKOFFSET(GroundEntChanged, false, true);
CHECKOFFSET(OnTakeDamage, true, true);
CHECKOFFSET(OnTakeDamageAlive,true, true);
CHECKOFFSET(PreThink, true, true);
CHECKOFFSET(PostThink, true, true);
CHECKOFFSET(Reload, true, true);
@ -529,6 +536,7 @@ void SDKHooks::SetupHooks()
CHECKOFFSET_W(Equip, true, true);
CHECKOFFSET_W(Switch, true, true);
CHECKOFFSET(VPhysicsUpdate, true, true);
CHECKOFFSET(Blocked, true, true);
// this one is in a class all its own -_-
offset = 0;
@ -603,6 +611,12 @@ HookReturn SDKHooks::Hook(int entity, SDKHookType type, IPluginFunction *callbac
case SDKHook_OnTakeDamagePost:
hookid = SH_ADD_MANUALVPHOOK(OnTakeDamage, pEnt, SH_MEMBER(&g_Interface, &SDKHooks::Hook_OnTakeDamagePost), true);
break;
case SDKHook_OnTakeDamageAlive:
hookid = SH_ADD_MANUALVPHOOK(OnTakeDamageAlive, pEnt, SH_MEMBER(&g_Interface, &SDKHooks::Hook_OnTakeDamageAlive), false);
break;
case SDKHook_OnTakeDamageAlivePost:
hookid = SH_ADD_MANUALVPHOOK(OnTakeDamageAlive, pEnt, SH_MEMBER(&g_Interface, &SDKHooks::Hook_OnTakeDamageAlivePost), true);
break;
case SDKHook_PreThink:
hookid = SH_ADD_MANUALVPHOOK(PreThink, pEnt, SH_MEMBER(&g_Interface, &SDKHooks::Hook_PreThink), false);
break;
@ -699,6 +713,12 @@ HookReturn SDKHooks::Hook(int entity, SDKHookType type, IPluginFunction *callbac
case SDKHook_ShouldCollide:
hookid = SH_ADD_MANUALVPHOOK(ShouldCollide, pEnt, SH_MEMBER(&g_Interface, &SDKHooks::Hook_ShouldCollide), false);
break;
case SDKHook_Blocked:
hookid = SH_ADD_MANUALVPHOOK(Blocked, pEnt, SH_MEMBER(&g_Interface, &SDKHooks::Hook_Blocked), false);
break;
case SDKHook_BlockedPost:
hookid = SH_ADD_MANUALVPHOOK(Blocked, pEnt, SH_MEMBER(&g_Interface, &SDKHooks::Hook_BlockedPost), true);
break;
}
vhook.SetHookID(hookid);
@ -989,12 +1009,12 @@ void SDKHooks::Hook_GroundEntChangedPost(void *pVar)
Call(META_IFACEPTR(CBaseEntity), SDKHook_GroundEntChangedPost);
}
int SDKHooks::Hook_OnTakeDamage(CTakeDamageInfoHack &info)
int SDKHooks::HandleOnTakeDamageHook(CTakeDamageInfoHack &info, SDKHookType hookType)
{
CBaseEntity *pEntity = META_IFACEPTR(CBaseEntity);
CVTableHook vhook(pEntity);
ke::Vector<CVTableList *> &vtablehooklist = g_HookList[SDKHook_OnTakeDamage];
ke::Vector<CVTableList *> &vtablehooklist = g_HookList[hookType];
for (size_t entry = 0; entry < vtablehooklist.length(); ++entry)
{
if (vhook != vtablehooklist[entry]->vtablehook)
@ -1010,10 +1030,10 @@ int SDKHooks::Hook_OnTakeDamage(CTakeDamageInfoHack &info)
int weapon = info.GetWeapon();
Vector force = info.GetDamageForce();
cell_t damageForce[3] = {sp_ftoc(force.x), sp_ftoc(force.y), sp_ftoc(force.z)};
cell_t damageForce[3] = { sp_ftoc(force.x), sp_ftoc(force.y), sp_ftoc(force.z) };
Vector pos = info.GetDamagePosition();
cell_t damagePosition[3] = {sp_ftoc(pos.x), sp_ftoc(pos.y), sp_ftoc(pos.z)};
cell_t damagePosition[3] = { sp_ftoc(pos.x), sp_ftoc(pos.y), sp_ftoc(pos.z) };
cell_t res, ret = Pl_Continue;
@ -1029,23 +1049,23 @@ int SDKHooks::Hook_OnTakeDamage(CTakeDamageInfoHack &info)
callback->PushCellByRef(&damagetype);
callback->PushCellByRef(&weapon);
callback->PushArray(damageForce, 3, SM_PARAM_COPYBACK);
callback->PushArray(damagePosition, 3, SM_PARAM_COPYBACK);
callback->PushArray(damagePosition, 3, SM_PARAM_COPYBACK);
callback->PushCell(info.GetDamageCustom());
callback->Execute(&res);
if(res >= ret)
if (res >= ret)
{
ret = res;
if(ret == Pl_Changed)
if (ret == Pl_Changed)
{
CBaseEntity *pEntAttacker = gamehelpers->ReferenceToEntity(attacker);
if(!pEntAttacker)
if (!pEntAttacker)
{
callback->GetParentRuntime()->GetDefaultContext()->ThrowNativeError("Entity %d for attacker is invalid", attacker);
RETURN_META_VALUE(MRES_IGNORED, 0);
}
CBaseEntity *pEntInflictor = gamehelpers->ReferenceToEntity(inflictor);
if(!pEntInflictor)
if (!pEntInflictor)
{
callback->GetParentRuntime()->GetDefaultContext()->ThrowNativeError("Entity %d for inflictor is invalid", inflictor);
RETURN_META_VALUE(MRES_IGNORED, 0);
@ -1067,12 +1087,12 @@ int SDKHooks::Hook_OnTakeDamage(CTakeDamageInfoHack &info)
}
}
}
if(ret >= Pl_Handled)
if (ret >= Pl_Handled)
RETURN_META_VALUE(MRES_SUPERCEDE, 1);
if(ret == Pl_Changed)
RETURN_META_VALUE(MRES_HANDLED, 1);
if (ret == Pl_Changed)
RETURN_META_VALUE(MRES_HANDLED, 1);
break;
}
@ -1080,12 +1100,12 @@ int SDKHooks::Hook_OnTakeDamage(CTakeDamageInfoHack &info)
RETURN_META_VALUE(MRES_IGNORED, 0);
}
int SDKHooks::Hook_OnTakeDamagePost(CTakeDamageInfoHack &info)
int SDKHooks::HandleOnTakeDamageHookPost(CTakeDamageInfoHack &info, SDKHookType hookType)
{
CBaseEntity *pEntity = META_IFACEPTR(CBaseEntity);
CVTableHook vhook(pEntity);
ke::Vector<CVTableList *> &vtablehooklist = g_HookList[SDKHook_OnTakeDamagePost];
ke::Vector<CVTableList *> &vtablehooklist = g_HookList[hookType];
for (size_t entry = 0; entry < vtablehooklist.length(); ++entry)
{
if (vhook != vtablehooklist[entry]->vtablehook)
@ -1108,11 +1128,11 @@ int SDKHooks::Hook_OnTakeDamagePost(CTakeDamageInfoHack &info)
callback->PushCell(info.GetWeapon());
Vector force = info.GetDamageForce();
cell_t damageForce[3] = {sp_ftoc(force.x), sp_ftoc(force.y), sp_ftoc(force.z)};
cell_t damageForce[3] = { sp_ftoc(force.x), sp_ftoc(force.y), sp_ftoc(force.z) };
callback->PushArray(damageForce, 3);
Vector pos = info.GetDamagePosition();
cell_t damagePosition[3] = {sp_ftoc(pos.x), sp_ftoc(pos.y), sp_ftoc(pos.z)};
cell_t damagePosition[3] = { sp_ftoc(pos.x), sp_ftoc(pos.y), sp_ftoc(pos.z) };
callback->PushArray(damagePosition, 3);
callback->PushCell(info.GetDamageCustom());
@ -1126,6 +1146,26 @@ int SDKHooks::Hook_OnTakeDamagePost(CTakeDamageInfoHack &info)
RETURN_META_VALUE(MRES_IGNORED, 0);
}
int SDKHooks::Hook_OnTakeDamage(CTakeDamageInfoHack &info)
{
return HandleOnTakeDamageHook(info, SDKHook_OnTakeDamage);
}
int SDKHooks::Hook_OnTakeDamagePost(CTakeDamageInfoHack &info)
{
return HandleOnTakeDamageHookPost(info, SDKHook_OnTakeDamagePost);
}
int SDKHooks::Hook_OnTakeDamageAlive(CTakeDamageInfoHack &info)
{
return HandleOnTakeDamageHook(info, SDKHook_OnTakeDamageAlive);
}
int SDKHooks::Hook_OnTakeDamageAlivePost(CTakeDamageInfoHack &info)
{
return HandleOnTakeDamageHookPost(info, SDKHook_OnTakeDamageAlivePost);
}
void SDKHooks::Hook_PreThink()
{
Call(META_IFACEPTR(CBaseEntity), SDKHook_PreThink);
@ -1576,6 +1616,22 @@ void SDKHooks::Hook_VPhysicsUpdatePost(IPhysicsObject *pPhysics)
Call(META_IFACEPTR(CBaseEntity), SDKHook_VPhysicsUpdatePost);
}
void SDKHooks::Hook_Blocked(CBaseEntity *pOther)
{
cell_t result = Call(META_IFACEPTR(CBaseEntity), SDKHook_Blocked, pOther);
if(result >= Pl_Handled)
RETURN_META(MRES_SUPERCEDE);
RETURN_META(MRES_IGNORED);
}
void SDKHooks::Hook_BlockedPost(CBaseEntity *pOther)
{
Call(META_IFACEPTR(CBaseEntity), SDKHook_BlockedPost, pOther);
RETURN_META(MRES_IGNORED);
}
bool SDKHooks::Hook_WeaponCanSwitchTo(CBaseCombatWeapon *pWeapon)
{
cell_t result = Call(META_IFACEPTR(CBaseEntity), SDKHook_WeaponCanSwitchTo, pWeapon);

View File

@ -1,349 +1,361 @@
#ifndef _INCLUDE_SOURCEMOD_EXTENSION_PROPER_H_
#define _INCLUDE_SOURCEMOD_EXTENSION_PROPER_H_
#include "smsdk_ext.h"
#include <ISDKHooks.h>
#include <IBinTools.h>
#include <convar.h>
#include <sh_list.h>
#include <amtl/am-vector.h>
#include <vtable_hook_helper.h>
#include <iplayerinfo.h>
#include <shareddefs.h>
#if SOURCE_ENGINE >= SE_ORANGEBOX
#include <itoolentity.h>
#endif
#include "takedamageinfohack.h"
#ifndef METAMOD_PLAPI_VERSION
#define GetCGlobals pGlobals
#define GetEngineFactory engineFactory
#define GetServerFactory serverFactory
#endif
#if SOURCE_ENGINE >= SE_CSS && SOURCE_ENGINE != SE_LEFT4DEAD
#define GETMAXHEALTH_IS_VIRTUAL
#endif
#if SOURCE_ENGINE != SE_HL2DM && SOURCE_ENGINE != SE_DODS && SOURCE_ENGINE != SE_CSS && SOURCE_ENGINE != SE_TF2 && SOURCE_ENGINE != SE_LEFT4DEAD2 && SOURCE_ENGINE != SE_CSGO && SOURCE_ENGINE != SE_NUCLEARDAWN
#define GAMEDESC_CAN_CHANGE
#endif
#if SOURCE_ENGINE == SE_DOTA
class CEntityKeyValues;
#endif
/**
* Globals
*/
struct HookTypeData
{
const char *name;
const char *dtReq;
bool supported;
};
enum SDKHookType
{
SDKHook_EndTouch,
SDKHook_FireBulletsPost,
SDKHook_OnTakeDamage,
SDKHook_OnTakeDamagePost,
SDKHook_PreThink,
SDKHook_PostThink,
SDKHook_SetTransmit,
SDKHook_Spawn,
SDKHook_StartTouch,
SDKHook_Think,
SDKHook_Touch,
SDKHook_TraceAttack,
SDKHook_TraceAttackPost,
SDKHook_WeaponCanSwitchTo,
SDKHook_WeaponCanUse,
SDKHook_WeaponDrop,
SDKHook_WeaponEquip,
SDKHook_WeaponSwitch,
SDKHook_ShouldCollide,
SDKHook_PreThinkPost,
SDKHook_PostThinkPost,
SDKHook_ThinkPost,
SDKHook_EndTouchPost,
SDKHook_GroundEntChangedPost,
SDKHook_SpawnPost,
SDKHook_StartTouchPost,
SDKHook_TouchPost,
SDKHook_VPhysicsUpdate,
SDKHook_VPhysicsUpdatePost,
SDKHook_WeaponCanSwitchToPost,
SDKHook_WeaponCanUsePost,
SDKHook_WeaponDropPost,
SDKHook_WeaponEquipPost,
SDKHook_WeaponSwitchPost,
SDKHook_Use,
SDKHook_UsePost,
SDKHook_Reload,
SDKHook_ReloadPost,
SDKHook_GetMaxHealth,
SDKHook_MAXHOOKS
};
enum HookReturn
{
HookRet_Successful,
HookRet_InvalidEntity,
HookRet_InvalidHookType,
HookRet_NotSupported,
HookRet_BadEntForHookType,
};
#if SOURCE_ENGINE >= SE_CSS
typedef void *(*ReticulateSplines)();
#endif
/**
* Classes
*/
class IPhysicsObject;
class CDmgAccumulator;
typedef CBaseEntity CBaseCombatWeapon;
struct HookList
{
public:
int entity;
IPluginFunction *callback;
};
class CVTableList
{
public:
CVTableList() : vtablehook(NULL)
{
};
~CVTableList()
{
delete vtablehook;
};
public:
CVTableHook *vtablehook;
ke::Vector<HookList> hooks;
};
#ifndef _INCLUDE_SOURCEMOD_EXTENSION_PROPER_H_
#define _INCLUDE_SOURCEMOD_EXTENSION_PROPER_H_
#include "smsdk_ext.h"
#include <ISDKHooks.h>
#include <IBinTools.h>
#include <convar.h>
#include <sh_list.h>
#include <amtl/am-vector.h>
#include <vtable_hook_helper.h>
#include <iplayerinfo.h>
#include <shareddefs.h>
#if SOURCE_ENGINE >= SE_ORANGEBOX
#include <itoolentity.h>
#endif
#include "takedamageinfohack.h"
#ifndef METAMOD_PLAPI_VERSION
#define GetCGlobals pGlobals
#define GetEngineFactory engineFactory
#define GetServerFactory serverFactory
#endif
#if SOURCE_ENGINE >= SE_CSS && SOURCE_ENGINE != SE_LEFT4DEAD
#define GETMAXHEALTH_IS_VIRTUAL
#endif
#if SOURCE_ENGINE != SE_HL2DM && SOURCE_ENGINE != SE_DODS && SOURCE_ENGINE != SE_CSS && SOURCE_ENGINE != SE_TF2 && SOURCE_ENGINE != SE_LEFT4DEAD2 && SOURCE_ENGINE != SE_CSGO && SOURCE_ENGINE != SE_NUCLEARDAWN
#define GAMEDESC_CAN_CHANGE
#endif
#if SOURCE_ENGINE == SE_DOTA
class CEntityKeyValues;
#endif
/**
* Globals
*/
struct HookTypeData
{
const char *name;
const char *dtReq;
bool supported;
};
enum SDKHookType
{
SDKHook_EndTouch,
SDKHook_FireBulletsPost,
SDKHook_OnTakeDamage,
SDKHook_OnTakeDamagePost,
SDKHook_PreThink,
SDKHook_PostThink,
SDKHook_SetTransmit,
SDKHook_Spawn,
SDKHook_StartTouch,
SDKHook_Think,
SDKHook_Touch,
SDKHook_TraceAttack,
SDKHook_TraceAttackPost,
SDKHook_WeaponCanSwitchTo,
SDKHook_WeaponCanUse,
SDKHook_WeaponDrop,
SDKHook_WeaponEquip,
SDKHook_WeaponSwitch,
SDKHook_ShouldCollide,
SDKHook_PreThinkPost,
SDKHook_PostThinkPost,
SDKHook_ThinkPost,
SDKHook_EndTouchPost,
SDKHook_GroundEntChangedPost,
SDKHook_SpawnPost,
SDKHook_StartTouchPost,
SDKHook_TouchPost,
SDKHook_VPhysicsUpdate,
SDKHook_VPhysicsUpdatePost,
SDKHook_WeaponCanSwitchToPost,
SDKHook_WeaponCanUsePost,
SDKHook_WeaponDropPost,
SDKHook_WeaponEquipPost,
SDKHook_WeaponSwitchPost,
SDKHook_Use,
SDKHook_UsePost,
SDKHook_Reload,
SDKHook_ReloadPost,
SDKHook_GetMaxHealth,
SDKHook_Blocked,
SDKHook_BlockedPost,
SDKHook_OnTakeDamageAlive,
SDKHook_OnTakeDamageAlivePost,
SDKHook_MAXHOOKS
};
enum HookReturn
{
HookRet_Successful,
HookRet_InvalidEntity,
HookRet_InvalidHookType,
HookRet_NotSupported,
HookRet_BadEntForHookType,
};
#if SOURCE_ENGINE >= SE_CSS
typedef void *(*ReticulateSplines)();
#endif
/**
* Classes
*/
class IPhysicsObject;
class CDmgAccumulator;
typedef CBaseEntity CBaseCombatWeapon;
struct HookList
{
public:
int entity;
IPluginFunction *callback;
};
class CVTableList
{
public:
CVTableList() : vtablehook(NULL)
{
};
~CVTableList()
{
delete vtablehook;
};
public:
CVTableHook *vtablehook;
ke::Vector<HookList> hooks;
};
class IEntityListener
{
public:
virtual void OnEntityCreated( CBaseEntity *pEntity ) {};
virtual void OnEntitySpawned( CBaseEntity *pEntity ) {};
virtual void OnEntityDeleted( CBaseEntity *pEntity ) {};
};
class SDKHooks :
public SDKExtension,
public IConCommandBaseAccessor,
public IPluginsListener,
public IFeatureProvider,
public IEntityListener,
public IClientListener,
public ISDKHooks
{
public:
/**
* @brief This is called after the initial loading sequence has been processed.
*
* @param error Error message buffer.
* @param maxlength Size of error message buffer.
* @param late Whether or not the module was loaded after map load.
* @return True to succeed loading, false to fail.
*/
virtual bool SDK_OnLoad(char *error, size_t maxlength, bool late);
/**
* @brief This is called right before the extension is unloaded.
*/
virtual void SDK_OnUnload();
/**
* @brief This is called once all known extensions have been loaded.
* Note: It is is a good idea to add natives here, if any are provided.
*/
virtual void SDK_OnAllLoaded();
/**
* @brief Called when the pause state is changed.
*/
//virtual void SDK_OnPauseChange(bool paused);
/**
* @brief this is called when Core wants to know if your extension is working.
*
* @param error Error message buffer.
* @param maxlength Size of error message buffer.
* @return True if working, false otherwise.
*/
//virtual bool QueryRunning(char *error, size_t maxlength);
/** Returns version string */
virtual const char *GetExtensionVerString();
/** Returns date string */
virtual const char *GetExtensionDateString();
public:
#if defined SMEXT_CONF_METAMOD
/**
* @brief Called when Metamod is attached, before the extension version is called.
*
* @param error Error buffer.
* @param maxlength Maximum size of error buffer.
* @param late Whether or not Metamod considers this a late load.
* @return True to succeed, false to fail.
*/
virtual bool SDK_OnMetamodLoad(ISmmAPI *ismm, char *error, size_t maxlength, bool late);
/**
* @brief Called when Metamod is detaching, after the extension version is called.
* NOTE: By default this is blocked unless sent from SourceMod.
*
* @param error Error buffer.
* @param maxlength Maximum size of error buffer.
* @return True to succeed, false to fail.
*/
//virtual bool SDK_OnMetamodUnload(char *error, size_t maxlength);
/**
* @brief Called when Metamod's pause state is changing.
* NOTE: By default this is blocked unless sent from SourceMod.
*
* @param paused Pause state being set.
* @param error Error buffer.
* @param maxlength Maximum size of error buffer.
* @return True to succeed, false to fail.
*/
//virtual bool SDK_OnMetamodPauseChange(bool paused, char *error, size_t maxlength);
#endif
public: // IPluginsListener
virtual void OnPluginLoaded(IPlugin *plugin);
virtual void OnPluginUnloaded(IPlugin *plugin);
public: // IConCommandBaseAccessor
virtual bool RegisterConCommandBase(ConCommandBase *pVar);
public: // IFeatureProvider
virtual FeatureStatus GetFeatureStatus(FeatureType type, const char *name);
public: // IEntityListener
virtual void OnEntityCreated(CBaseEntity *pEntity);
virtual void OnEntityDeleted(CBaseEntity *pEntity);
public: // IClientListener
virtual void OnClientPutInServer(int client);
virtual void OnClientDisconnecting(int client);
public: // ISDKHooks
virtual void AddEntityListener(ISMEntityListener *listener);
virtual void RemoveEntityListener(ISMEntityListener *listener);
private:
SourceHook::List<ISMEntityListener *> m_EntListeners;
public:
/**
* Functions
*/
};
class SDKHooks :
public SDKExtension,
public IConCommandBaseAccessor,
public IPluginsListener,
public IFeatureProvider,
public IEntityListener,
public IClientListener,
public ISDKHooks
{
public:
/**
* @brief This is called after the initial loading sequence has been processed.
*
* @param error Error message buffer.
* @param maxlength Size of error message buffer.
* @param late Whether or not the module was loaded after map load.
* @return True to succeed loading, false to fail.
*/
virtual bool SDK_OnLoad(char *error, size_t maxlength, bool late);
/**
* @brief This is called right before the extension is unloaded.
*/
virtual void SDK_OnUnload();
/**
* @brief This is called once all known extensions have been loaded.
* Note: It is is a good idea to add natives here, if any are provided.
*/
virtual void SDK_OnAllLoaded();
/**
* @brief Called when the pause state is changed.
*/
//virtual void SDK_OnPauseChange(bool paused);
/**
* @brief this is called when Core wants to know if your extension is working.
*
* @param error Error message buffer.
* @param maxlength Size of error message buffer.
* @return True if working, false otherwise.
*/
//virtual bool QueryRunning(char *error, size_t maxlength);
/** Returns version string */
virtual const char *GetExtensionVerString();
/** Returns date string */
virtual const char *GetExtensionDateString();
public:
#if defined SMEXT_CONF_METAMOD
/**
* @brief Called when Metamod is attached, before the extension version is called.
*
* @param error Error buffer.
* @param maxlength Maximum size of error buffer.
* @param late Whether or not Metamod considers this a late load.
* @return True to succeed, false to fail.
*/
virtual bool SDK_OnMetamodLoad(ISmmAPI *ismm, char *error, size_t maxlength, bool late);
/**
* @brief Called when Metamod is detaching, after the extension version is called.
* NOTE: By default this is blocked unless sent from SourceMod.
*
* @param error Error buffer.
* @param maxlength Maximum size of error buffer.
* @return True to succeed, false to fail.
*/
//virtual bool SDK_OnMetamodUnload(char *error, size_t maxlength);
/**
* @brief Called when Metamod's pause state is changing.
* NOTE: By default this is blocked unless sent from SourceMod.
*
* @param paused Pause state being set.
* @param error Error buffer.
* @param maxlength Maximum size of error buffer.
* @return True to succeed, false to fail.
*/
//virtual bool SDK_OnMetamodPauseChange(bool paused, char *error, size_t maxlength);
#endif
public: // IPluginsListener
virtual void OnPluginLoaded(IPlugin *plugin);
virtual void OnPluginUnloaded(IPlugin *plugin);
public: // IConCommandBaseAccessor
virtual bool RegisterConCommandBase(ConCommandBase *pVar);
public: // IFeatureProvider
virtual FeatureStatus GetFeatureStatus(FeatureType type, const char *name);
public: // IEntityListener
virtual void OnEntityCreated(CBaseEntity *pEntity);
virtual void OnEntityDeleted(CBaseEntity *pEntity);
public: // IClientListener
virtual void OnClientPutInServer(int client);
virtual void OnClientDisconnecting(int client);
public: // ISDKHooks
virtual void AddEntityListener(ISMEntityListener *listener);
virtual void RemoveEntityListener(ISMEntityListener *listener);
private:
SourceHook::List<ISMEntityListener *> m_EntListeners;
public:
/**
* Functions
*/
cell_t Call(int entity, SDKHookType type, int other=INVALID_EHANDLE_INDEX);
cell_t Call(CBaseEntity *pEnt, SDKHookType type, int other=INVALID_EHANDLE_INDEX);
cell_t Call(CBaseEntity *pEnt, SDKHookType type, CBaseEntity *pOther);
void SetupHooks();
HookReturn Hook(int entity, SDKHookType type, IPluginFunction *pCallback);
void Unhook(int entity, SDKHookType type, IPluginFunction *pCallback);
/**
* IServerGameDLL & IVEngineServer Hook Handlers
*/
#ifdef GAMEDESC_CAN_CHANGE
const char *Hook_GetGameDescription();
#endif
const char *Hook_GetMapEntitiesString();
bool Hook_LevelInit(char const *pMapName, char const *pMapEntities, char const *pOldLevel, char const *pLandmarkName, bool loadGame, bool background);
/**
* CBaseEntity Hook Handlers
*/
void Hook_EndTouch(CBaseEntity *pOther);
void Hook_EndTouchPost(CBaseEntity *pOther);
void Hook_FireBulletsPost(const FireBulletsInfo_t &info);
#ifdef GETMAXHEALTH_IS_VIRTUAL
int Hook_GetMaxHealth();
#endif
void Hook_GroundEntChangedPost(void *pVar);
int Hook_OnTakeDamage(CTakeDamageInfoHack &info);
int Hook_OnTakeDamagePost(CTakeDamageInfoHack &info);
void Hook_PreThink();
void Hook_PreThinkPost();
void Hook_PostThink();
void Hook_PostThinkPost();
bool Hook_Reload();
bool Hook_ReloadPost();
void Hook_SetTransmit(CCheckTransmitInfo *pInfo, bool bAlways);
bool Hook_ShouldCollide(int collisonGroup, int contentsMask);
#if SOURCE_ENGINE == SE_DOTA
void Hook_Spawn(CEntityKeyValues *kv);
void Hook_SpawnPost(CEntityKeyValues *kv);
#else
void Hook_Spawn();
void Hook_SpawnPost();
#endif
void Hook_StartTouch(CBaseEntity *pOther);
void Hook_StartTouchPost(CBaseEntity *pOther);
void Hook_Think();
void Hook_ThinkPost();
void Hook_Touch(CBaseEntity *pOther);
void Hook_TouchPost(CBaseEntity *pOther);
#if SOURCE_ENGINE == SE_HL2DM || SOURCE_ENGINE == SE_DODS || SOURCE_ENGINE == SE_CSS || SOURCE_ENGINE == SE_TF2 || SOURCE_ENGINE == SE_SDK2013
void Hook_TraceAttack(CTakeDamageInfoHack &info, const Vector &vecDir, trace_t *ptr, CDmgAccumulator *pAccumulator);
void Hook_TraceAttackPost(CTakeDamageInfoHack &info, const Vector &vecDir, trace_t *ptr, CDmgAccumulator *pAccumulator);
#else
void Hook_TraceAttack(CTakeDamageInfoHack &info, const Vector &vecDir, trace_t *ptr);
void Hook_TraceAttackPost(CTakeDamageInfoHack &info, const Vector &vecDir, trace_t *ptr);
#endif
void Hook_UpdateOnRemove();
void Hook_Use(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value);
void Hook_UsePost(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value);
void Hook_VPhysicsUpdate(IPhysicsObject *pPhysics);
void Hook_VPhysicsUpdatePost(IPhysicsObject *pPhysics);
bool Hook_WeaponCanSwitchTo(CBaseCombatWeapon *pWeapon);
bool Hook_WeaponCanSwitchToPost(CBaseCombatWeapon *pWeapon);
bool Hook_WeaponCanUse(CBaseCombatWeapon *pWeapon);
bool Hook_WeaponCanUsePost(CBaseCombatWeapon *pWeapon);
void Hook_WeaponDrop(CBaseCombatWeapon *pWeapon, const Vector *pvecTarget, const Vector *pVelocity);
void Hook_WeaponDropPost(CBaseCombatWeapon *pWeapon, const Vector *pvecTarget, const Vector *pVelocity);
void Hook_WeaponEquip(CBaseCombatWeapon *pWeapon);
void Hook_WeaponEquipPost(CBaseCombatWeapon *pWeapon);
bool Hook_WeaponSwitch(CBaseCombatWeapon *pWeapon, int viewmodelindex);
bool Hook_WeaponSwitchPost(CBaseCombatWeapon *pWeapon, int viewmodelindex);
private:
void HandleEntityCreated(CBaseEntity *pEntity, int ref);
void HandleEntityDeleted(CBaseEntity *pEntity, int ref);
void Unhook(CBaseEntity *pEntity);
void Unhook(IPluginContext *pContext);
};
extern CGlobalVars *gpGlobals;
extern ke::Vector<CVTableList *> g_HookList[SDKHook_MAXHOOKS];
extern ICvar *icvar;
#if SOURCE_ENGINE >= SE_ORANGEBOX
extern IServerTools *servertools;
#endif
#endif // _INCLUDE_SOURCEMOD_EXTENSION_PROPER_H_
cell_t Call(CBaseEntity *pEnt, SDKHookType type, int other=INVALID_EHANDLE_INDEX);
cell_t Call(CBaseEntity *pEnt, SDKHookType type, CBaseEntity *pOther);
void SetupHooks();
HookReturn Hook(int entity, SDKHookType type, IPluginFunction *pCallback);
void Unhook(int entity, SDKHookType type, IPluginFunction *pCallback);
/**
* IServerGameDLL & IVEngineServer Hook Handlers
*/
#ifdef GAMEDESC_CAN_CHANGE
const char *Hook_GetGameDescription();
#endif
const char *Hook_GetMapEntitiesString();
bool Hook_LevelInit(char const *pMapName, char const *pMapEntities, char const *pOldLevel, char const *pLandmarkName, bool loadGame, bool background);
/**
* CBaseEntity Hook Handlers
*/
void Hook_EndTouch(CBaseEntity *pOther);
void Hook_EndTouchPost(CBaseEntity *pOther);
void Hook_FireBulletsPost(const FireBulletsInfo_t &info);
#ifdef GETMAXHEALTH_IS_VIRTUAL
int Hook_GetMaxHealth();
#endif
void Hook_GroundEntChangedPost(void *pVar);
int Hook_OnTakeDamage(CTakeDamageInfoHack &info);
int Hook_OnTakeDamagePost(CTakeDamageInfoHack &info);
int Hook_OnTakeDamageAlive(CTakeDamageInfoHack &info);
int Hook_OnTakeDamageAlivePost(CTakeDamageInfoHack &info);
void Hook_PreThink();
void Hook_PreThinkPost();
void Hook_PostThink();
void Hook_PostThinkPost();
bool Hook_Reload();
bool Hook_ReloadPost();
void Hook_SetTransmit(CCheckTransmitInfo *pInfo, bool bAlways);
bool Hook_ShouldCollide(int collisonGroup, int contentsMask);
#if SOURCE_ENGINE == SE_DOTA
void Hook_Spawn(CEntityKeyValues *kv);
void Hook_SpawnPost(CEntityKeyValues *kv);
#else
void Hook_Spawn();
void Hook_SpawnPost();
#endif
void Hook_StartTouch(CBaseEntity *pOther);
void Hook_StartTouchPost(CBaseEntity *pOther);
void Hook_Think();
void Hook_ThinkPost();
void Hook_Touch(CBaseEntity *pOther);
void Hook_TouchPost(CBaseEntity *pOther);
#if SOURCE_ENGINE == SE_HL2DM || SOURCE_ENGINE == SE_DODS || SOURCE_ENGINE == SE_CSS || SOURCE_ENGINE == SE_TF2 || SOURCE_ENGINE == SE_SDK2013
void Hook_TraceAttack(CTakeDamageInfoHack &info, const Vector &vecDir, trace_t *ptr, CDmgAccumulator *pAccumulator);
void Hook_TraceAttackPost(CTakeDamageInfoHack &info, const Vector &vecDir, trace_t *ptr, CDmgAccumulator *pAccumulator);
#else
void Hook_TraceAttack(CTakeDamageInfoHack &info, const Vector &vecDir, trace_t *ptr);
void Hook_TraceAttackPost(CTakeDamageInfoHack &info, const Vector &vecDir, trace_t *ptr);
#endif
void Hook_UpdateOnRemove();
void Hook_Use(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value);
void Hook_UsePost(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value);
void Hook_VPhysicsUpdate(IPhysicsObject *pPhysics);
void Hook_VPhysicsUpdatePost(IPhysicsObject *pPhysics);
void Hook_Blocked(CBaseEntity *pOther);
void Hook_BlockedPost(CBaseEntity *pOther);
bool Hook_WeaponCanSwitchTo(CBaseCombatWeapon *pWeapon);
bool Hook_WeaponCanSwitchToPost(CBaseCombatWeapon *pWeapon);
bool Hook_WeaponCanUse(CBaseCombatWeapon *pWeapon);
bool Hook_WeaponCanUsePost(CBaseCombatWeapon *pWeapon);
void Hook_WeaponDrop(CBaseCombatWeapon *pWeapon, const Vector *pvecTarget, const Vector *pVelocity);
void Hook_WeaponDropPost(CBaseCombatWeapon *pWeapon, const Vector *pvecTarget, const Vector *pVelocity);
void Hook_WeaponEquip(CBaseCombatWeapon *pWeapon);
void Hook_WeaponEquipPost(CBaseCombatWeapon *pWeapon);
bool Hook_WeaponSwitch(CBaseCombatWeapon *pWeapon, int viewmodelindex);
bool Hook_WeaponSwitchPost(CBaseCombatWeapon *pWeapon, int viewmodelindex);
private:
void HandleEntityCreated(CBaseEntity *pEntity, int ref);
void HandleEntityDeleted(CBaseEntity *pEntity, int ref);
void Unhook(CBaseEntity *pEntity);
void Unhook(IPluginContext *pContext);
private:
int HandleOnTakeDamageHook(CTakeDamageInfoHack &info, SDKHookType hookType);
int HandleOnTakeDamageHookPost(CTakeDamageInfoHack &info, SDKHookType hookType);
};
extern CGlobalVars *gpGlobals;
extern ke::Vector<CVTableList *> g_HookList[SDKHook_MAXHOOKS];
extern ICvar *icvar;
#if SOURCE_ENGINE >= SE_ORANGEBOX
extern IServerTools *servertools;
#endif
#endif // _INCLUDE_SOURCEMOD_EXTENSION_PROPER_H_

View File

@ -36,6 +36,8 @@
SqDatabase::SqDatabase(sqlite3 *sq3, bool persistent) :
m_sq3(sq3), m_Persistent(persistent)
{
// DBI, for historical reasons, guarantees an initial refcount of 1.
AddRef();
}
SqDatabase::~SqDatabase()

View File

@ -36,5 +36,10 @@
"windows" "\xE8\x2A\x2A\x2A\x2A\xE8\x2A\x2A\x2A\x2A\xB9\x2A\x2A\x2A\x2A\xE8\x2A\x2A\x2A\x2A\xE8\x2A\x2A\x2A\x2A\x6A"
}
}
"Keys"
{
"UseInvalidUniverseInSteam2IDs" "1"
}
}
}

View File

@ -53,5 +53,10 @@
"mac" "@gEntList"
}
}
"Keys"
{
"UseInvalidUniverseInSteam2IDs" "1"
}
}
}

View File

@ -42,5 +42,10 @@
"windows" "\xE8\x2A\x2A\x2A\x2A\xE8\x2A\x2A\x2A\x2A\xB9\x2A\x2A\x2A\x2A\xE8\x2A\x2A\x2A\x2A\xE8"
}
}
"Keys"
{
"UseInvalidUniverseInSteam2IDs" "1"
}
}
}

View File

@ -106,6 +106,11 @@
"windows" "\x56\x8B\x74\x24\x08\x57\x56\x8B\xF9\xE8\x2A\x2A\x2A\x2A\x84\xC0\x0F\x85\xC4\x00\x00\x00\x56\x8D"
}
}
"Keys"
{
"UseInvalidUniverseInSteam2IDs" "1"
}
}
}

View File

@ -58,4 +58,12 @@
}
}
}
"#default"
{
"Keys"
{
"UseInvalidUniverseInSteam2IDs" "1"
}
}
}

View File

@ -52,5 +52,10 @@
"mac" "@gEntList"
}
}
"Keys"
{
"UseInvalidUniverseInSteam2IDs" "1"
}
}
}

View File

@ -41,5 +41,10 @@
"windows" "\xE8\x2A\x2A\x2A\x2A\xE8\x2A\x2A\x2A\x2A\xB9\x2A\x2A\x2A\x2A\xE8\x2A\x2A\x2A\x2A\xE8"
}
}
"Keys"
{
"UseInvalidUniverseInSteam2IDs" "1"
}
}
}

View File

@ -95,4 +95,12 @@
}
}
}
"#default"
{
"Keys"
{
"UseInvalidUniverseInSteam2IDs" "1"
}
}
}

View File

@ -4,6 +4,12 @@
{
"Offsets"
{
"Blocked"
{
"windows" "106"
"linux" "107"
"mac" "107"
}
"EndTouch"
{
"windows" "104"
@ -34,6 +40,12 @@
"linux" "69"
"mac" "69"
}
"OnTakeDamage_Alive"
{
"windows" "291"
"linux" "292"
"mac" "292"
}
"PreThink"
{
"windows" "351"

View File

@ -4,6 +4,12 @@
{
"Offsets"
{
"Blocked"
{
"windows" "105"
"linux" "106"
"mac" "106"
}
"EndTouch"
{
"windows" "103"
@ -34,6 +40,12 @@
"linux" "68"
"mac" "68"
}
"OnTakeDamage_Alive"
{
"windows" "292"
"linux" "293"
"mac" "293"
}
"PreThink"
{
"windows" "364"

View File

@ -35,6 +35,12 @@
"linux" "63"
"mac" "63"
}
"OnTakeDamage_Alive"
{
"windows" "271"
"linux" "272"
"mac" "272"
}
"PreThink"
{
"windows" "331"
@ -107,6 +113,12 @@
"linux" "158"
"mac" "158"
}
"Blocked"
{
"windows" "102"
"linux" "103"
"mac" "103"
}
"Weapon_CanSwitchTo"
{
"windows" "265"
@ -174,6 +186,12 @@
"linux" "63"
"mac" "63"
}
"OnTakeDamage_Alive"
{
"windows" "271"
"linux" "272"
"mac" "272"
}
"PreThink"
{
"windows" "331"
@ -246,6 +264,12 @@
"linux" "158"
"mac" "158"
}
"Blocked"
{
"windows" "102"
"linux" "103"
"mac" "103"
}
"Weapon_CanSwitchTo"
{
"windows" "265"
@ -313,6 +337,12 @@
"linux" "63"
"mac" "63"
}
"OnTakeDamage_Alive"
{
"windows" "271"
"linux" "272"
"mac" "272"
}
"PreThink"
{
"windows" "331"
@ -385,6 +415,12 @@
"linux" "158"
"mac" "158"
}
"Blocked"
{
"windows" "102"
"linux" "103"
"mac" "103"
}
"Weapon_CanSwitchTo"
{
"windows" "265"

View File

@ -4,6 +4,12 @@
{
"Offsets"
{
"Blocked"
{
"windows" "106"
"linux" "107"
"mac" "107"
}
"EndTouch"
{
"windows" "104"
@ -34,6 +40,12 @@
"linux" "66"
"mac" "66"
}
"OnTakeDamage_Alive"
{
"windows" "288"
"linux" "289"
"mac" "289"
}
"PreThink"
{
"windows" "357"

View File

@ -4,6 +4,12 @@
{
"Offsets"
{
"Blocked"
{
"windows" "99"
"linux" "100"
"mac" "100"
}
"EndTouch"
{
"windows" "97"
@ -22,6 +28,12 @@
"linux" "63"
"mac" "63"
}
"OnTakeDamage_Alive"
{
"windows" "271"
"linux" "272"
"mac" "272"
}
"PreThink"
{
"windows" "333"

View File

@ -4,6 +4,12 @@
{
"Offsets"
{
"Blocked"
{
"windows" "102"
"linux" "103"
"mac" "103"
}
"EndTouch"
{
"windows" "100"
@ -34,6 +40,12 @@
"linux" "63"
"mac" "63"
}
"OnTakeDamage_Alive"
{
"windows" "271"
"linux" "272"
"mac" "272"
}
"PreThink"
{
"windows" "331"

View File

@ -4,6 +4,12 @@
{
"Offsets"
{
"Blocked"
{
"windows" "102"
"linux" "103"
"mac" "103"
}
"EndTouch"
{
"windows" "100"
@ -22,6 +28,12 @@
"linux" "63"
"mac" "63"
}
"OnTakeDamage_Alive"
{
"windows" "273"
"linux" "274"
"mac" "274"
}
"PreThink"
{
"windows" "333"

View File

@ -16,6 +16,12 @@
{
"Offsets"
{
"Blocked"
{
"windows" "110"
"linux" "111"
"mac" "111"
}
"EndTouch"
{
"windows" "108"
@ -40,6 +46,12 @@
"linux" "72"
"mac" "72"
}
"OnTakeDamage_Alive"
{
"windows" "291"
"linux" "292"
"mac" "292"
}
"PreThink"
{
"windows" "355"

View File

@ -4,6 +4,12 @@
{
"Offsets"
{
"Blocked"
{
"windows" "103"
"linux" "104"
"mac" "104"
}
"EndTouch"
{
"windows" "101"
@ -28,6 +34,12 @@
"linux" "63"
"mac" "63"
}
"OnTakeDamage_Alive"
{
"windows" "273"
"linux" "274"
"mac" "274"
}
"PreThink"
{
"windows" "345"

View File

@ -4,6 +4,12 @@
{
"Offsets"
{
"Blocked"
{
"windows" "121"
"linux" "122"
"mac" "122"
}
"EndTouch"
{
"windows" "119"
@ -34,6 +40,12 @@
"linux" "73"
"mac" "73"
}
"OnTakeDamage_Alive"
{
"windows" "303"
"linux" "304"
"mac" "304"
}
"PreThink"
{
"windows" "368"

View File

@ -70,7 +70,7 @@ public OnRebuildAdminCache(AdminCachePart:part)
}
}
ParseError(const String:format[], {Handle,String,Float,_}:...)
ParseError(const String:format[], any:...)
{
decl String:buffer[512];

View File

@ -45,6 +45,25 @@ enum NetFlow
NetFlow_Both, /**< Both values added together */
};
/**
* Auth string types.
*
* Note that for the Steam2 and Steam3 types, the following ids are
* also valid values:
* "STEAM_ID_PENDING" - Authentication is pending.
* "STEAM_ID_LAN" - Authentication is disabled because of being on a LAN server.
* "BOT" - The client is a bot.
*/
enum AuthIdType
{
AuthId_Engine = 0, /**< The game-specific auth string as returned from the engine */
// The following are only available on games that support Steam authentication.
AuthId_Steam2, /**< Steam2 rendered format, ex "STEAM_1:1:4153990" */
AuthId_Steam3, /**< Steam3 rendered format, ex "[U:1:8307981]" */
AuthId_SteamID64, /**< A SteamID64 (uint64) as a String, ex "76561197968573709" */
};
/**
* MAXPLAYERS is not the same as MaxClients.
* MAXPLAYERS is a hardcoded value as an upper limit. MaxClients changes based on the server.
@ -267,8 +286,24 @@ native bool:GetClientIP(client, String:ip[], maxlen, bool:remport=true);
* @return True on success, false otherwise.
* @error If the client is not connected or the index is invalid.
*/
#pragma deprecated Use GetClientAuthId
native bool:GetClientAuthString(client, String:auth[], maxlen, bool:validate=true);
/**
* Retrieves a client's authentication string (SteamID).
*
* @param client Player index.
* @param authType Auth id type and format to use.
* @param auth Buffer to store the client's auth id.
* @param maxlen Maximum length of string buffer (includes NULL terminator).
* @param validate Check backend validation status.
* DO NOT PASS FALSE UNLESS YOU UNDERSTAND THE CONSEQUENCES,
* You WILL KNOW if you need to use this, MOST WILL NOT.
* @return True on success, false otherwise.
* @error If the client is not connected or the index is invalid.
*/
native bool:GetClientAuthId(client, AuthIdType:authType, String:auth[], maxlen, bool:validate=true);
/**
* Returns the client's Steam account ID.
*

View File

@ -669,7 +669,7 @@ native SetConVarBounds(Handle:convar, ConVarBounds:type, bool:set, Float:value=0
*/
native GetConVarName(Handle:convar, String:name[], maxlength);
funcenum ConVarQueryFinished
union ConVarQueryFinished
{
/**
* Called when a query to retrieve a client's console variable has finished.
@ -683,7 +683,7 @@ funcenum ConVarQueryFinished
* @param value Value that was passed when query was started.
* @noreturn
*/
public(QueryCookie:cookie, client, ConVarQueryResult:result, const String:cvarName[], const String:cvarValue[], any:value),
function void (QueryCookie cookie, int client, ConVarQueryResult result, const char[] cvarName, const char[] cvarValue, any value);
/**
* Called when a query to retrieve a client's console variable has finished.
@ -696,7 +696,7 @@ funcenum ConVarQueryFinished
* @param convarValue Value of client convar that was queried if successful. This will be "" if it was not.
* @noreturn
*/
public(QueryCookie:cookie, client, ConVarQueryResult:result, const String:cvarName[], const String:cvarValue[])
function void (QueryCookie cookie, int client, ConVarQueryResult result, const char[] cvarName, const char[] cvarValue);
};
/**

View File

@ -48,7 +48,7 @@ enum EventHookMode
/**
* Hook function types for events.
*/
funcenum EventHook
union EventHook
{
/**
* Called when a game event is fired.
@ -59,7 +59,7 @@ funcenum EventHook
* @param dontBroadcast True if event was not broadcast to clients, false otherwise.
* @return Ignored for post hooks. Plugin_Handled will block event if hooked as pre.
*/
Action:public(Handle:event, const String:name[], bool:dontBroadcast),
function Action (Handle event, const char[] name, bool dontBroadcast);
/**
* Called when a game event is fired.
*
@ -69,7 +69,7 @@ funcenum EventHook
* @param dontBroadcast True if event was not broadcast to clients, false otherwise.
* @noreturn
*/
public(Handle:event, const String:name[], bool:dontBroadcast),
function void (Handle event, const char[] name, bool dontBroadcast);
};
/**

View File

@ -108,9 +108,14 @@ native BuildPath(PathType:type, String:buffer[], maxlength, const String:fmt[],
* @note OpenDirectory() supports the "file://" notation.
*
* @param path Path to open.
* @param use_valve_fs If true, the Valve file system will be used instead.
* This can be used to find files existing in any of
* the Valve search paths, rather than solely files
* existing directly in the gamedir.
* @param valve_path_id If use_valve_fs, a search path from gameinfo or NULL_STRING for all search paths.
* @return A Handle to the directory, INVALID_HANDLE on open error.
*/
native Handle:OpenDirectory(const String:path[]);
native Handle:OpenDirectory(const String:path[], bool:use_valve_fs=false, const String:valve_path_id[]="GAME");
/**
* Reads the current directory entry as a local filename, then moves to the next file.
@ -136,17 +141,27 @@ native bool:ReadDirEntry(Handle:dir, String:buffer[], maxlength, &FileType:type=
*
* @param file File to open.
* @param mode Open mode.
* @param use_valve_fs If true, the Valve file system will be used instead.
* This can be used to find files existing in valve
* search paths, rather than solely files existing directly
* in the gamedir.
* @param valve_path_id If use_valve_fs, a search path from gameinfo or NULL_STRING for all search paths.
* @return A Handle to the file, INVALID_HANDLE on open error.
*/
native Handle:OpenFile(const String:file[], const String:mode[]);
native Handle:OpenFile(const String:file[], const String:mode[], bool:use_valve_fs=false, const String:valve_path_id[]="GAME");
/**
* Deletes a file.
*
* @param path Path of the file to delete.
* @return True on success, false otherwise.
* @param use_valve_fs If true, the Valve file system will be used instead.
* This can be used to delete files existing in the Valve
* search path, rather than solely files existing directly
* in the gamedir.
* @param valve_path_id If use_valve_fs, a search path from gameinfo or NULL_STRING for all search paths.
* @return True on success, false on failure or if file not immediately removed.
*/
native bool:DeleteFile(const String:path[]);
native bool:DeleteFile(const String:path[], bool:use_valve_fs=false, const String:valve_path_id[]="DEFAULT_WRITE_PATH");
/**
* Reads a line from a text file.
@ -304,28 +319,38 @@ native FilePosition(Handle:file);
* @param path Path to the file.
* @param use_valve_fs If true, the Valve file system will be used instead.
* This can be used to find files existing in any of
* the GAME search paths, rather than solely files
* the Valve search paths, rather than solely files
* existing directly in the gamedir.
* @param valve_path_id If use_valve_fs, a search path from gameinfo or NULL_STRING for all search paths.
* @return True if the file exists, false otherwise.
*/
native bool:FileExists(const String:path[], bool:use_valve_fs=false);
native bool:FileExists(const String:path[], bool:use_valve_fs=false, const String:valve_path_id[]="GAME");
/**
* Renames a file.
*
* @param newpath New path to the file.
* @param oldpath Path to the existing file.
* @return True on success, false otherwise.
* @param use_valve_fs If true, the Valve file system will be used instead.
* This can be used to rename files in the game's
* Valve search paths, rather than directly in the gamedir.
* @param valve_path_id If use_valve_fs, a search path from gameinfo or NULL_STRING for all search paths.
* @return True on success or use_valve_fs specified, false otherwise.
*/
native bool:RenameFile(const String:newpath[], const String:oldpath[]);
native bool:RenameFile(const String:newpath[], const String:oldpath[], bool:use_valve_fs=false, const String:valve_path_id[]="DEFAULT_WRITE_PATH");
/**
* Checks if a directory exists.
*
* @param path Path to the directory.
* @param use_valve_fs If true, the Valve file system will be used instead.
* This can be used to find files existing in any of
* the Valve search paths, rather than solely files
* existing directly in the gamedir.
* @param valve_path_id If use_valve_fs, a search path from gameinfo or NULL_STRING for all search paths.
* @return True if the directory exists, false otherwise.
*/
native bool:DirExists(const String:path[]);
native bool:DirExists(const String:path[], bool:use_valve_fs=false, const String:valve_path_id[]="GAME");
/**
* Get the file size in bytes.
@ -333,18 +358,20 @@ native bool:DirExists(const String:path[]);
* @param path Path to the file.
* @param use_valve_fs If true, the Valve file system will be used instead.
* This can be used to find files existing in any of
* the GAME search paths, rather than solely files
* the Valve search paths, rather than solely files
* existing directly in the gamedir.
* @param valve_path_id If use_valve_fs, a search path from gameinfo or NULL_STRING for all search paths.
* @return File size in bytes, -1 if file not found.
*/
native FileSize(const String:path[], bool:use_valve_fs=false);
native FileSize(const String:path[], bool:use_valve_fs=false, const String:valve_path_id[]="GAME");
/**
* Flushes a file's buffered output; any buffered output
* is immediately written to the file.
*
* @param file Handle to the file.
* @return True on success, false on failure.
* @return True on success or use_valve_fs specified with OpenFile,
* otherwise false on failure.
*/
native FlushFile(Handle:file);
@ -373,8 +400,13 @@ native bool:RemoveDir(const String:path[]);
* @param path Path to create.
* @param mode Permissions (default is o=rx,g=rx,u=rwx). Note that folders must have
* the execute bit set on Linux. On Windows, the mode is ignored.
* @param use_valve_fs If true, the Valve file system will be used instead.
* This can be used to create folders in the game's
* Valve search paths, rather than directly in the gamedir.
* @param valve_path_id If use_valve_fs, a search path from gameinfo or NULL_STRING for default.
* In this case, mode is ignored.
*/
native bool:CreateDirectory(const String:path[], mode);
native bool:CreateDirectory(const String:path[], mode, bool:use_valve_fs=false, const String:valve_path_id[]="DEFAULT_WRITE_PATH");
/**
* Changes a file or directories permissions.

View File

@ -117,10 +117,17 @@ enum SDKHookType
SDKHook_Reload,
SDKHook_ReloadPost,
SDKHook_GetMaxHealth, /**< ep2v and later */
SDKHook_Blocked,
SDKHook_BlockedPost,
SDKHook_OnTakeDamageAlive,
SDKHook_OnTakeDamageAlivePost,
};
/*
Alphabetized for easy readability
SDKHook_Blocked,
SDKHook_BlockedPost,
SDKHook_EndTouch,
SDKHook_EndTouchPost,
@ -134,6 +141,9 @@ enum SDKHookType
SDKHook_OnTakeDamage,
SDKHook_OnTakeDamagePost,
SDKHook_OnTakeDamageAlive,
SDKHook_OnTakeDamageAlivePost,
SDKHook_PreThink,
SDKHook_PreThinkPost,
@ -192,90 +202,93 @@ enum UseType
Use_Toggle
};
funcenum SDKHookCB
union SDKHookCB
{
// PreThink/Post
// PostThink/Post
public(client),
function void (int client);
// Spawn
Action:public(entity),
function Action (int entity);
// GroundEntChanged
// SpawnPost
// Think/Post
// VPhysicsUpdate/Post
public(entity),
function void (int entity);
// EndTouch
// StartTouch
// Touch
Action:public(entity, other),
// Blocked
function Action (int entity, int other);
// EndTouchPost
// StartTouchPost
// TouchPost
public(entity, other),
function void (int entity, int other);
// SetTransmit
Action:public(entity, client),
function Action (int entity, int client);
// WeaponCanSwitchTo
// WeaponCanUse
// WeaponDrop
// WeaponEquip
// WeaponSwitch
Action:public(client, weapon),
function Action (int client, int weapon);
// WeaponCanSwitchToPost
// WeaponCanUsePost
// WeaponDropPost
// WeaponEquipPost
// WeaponSwitchPost
public(client, weapon),
function void (int client, int weapon);
// GetMaxHealth (ep2v and later)
Action:public(entity, &maxhealth),
function Action (int entity, int &maxhealth);
// OnTakeDamage
// OnTakeDamagAlive
// Note: The weapon parameter is not used by all games and damage sources.
// Note: Force application is dependent on game and damage type(s)
// SDKHooks 1.0+
Action:public(victim, &attacker, &inflictor, &Float:damage, &damagetype),
function Action (int victim, int &attacker, int &inflictor, float &damage, int &damagetype);
// SDKHooks 2.0+
Action:public(victim, &attacker, &inflictor, &Float:damage, &damagetype, &weapon, Float:damageForce[3], Float:damagePosition[3]),
function Action (int victim, int &attacker, int &inflictor, float &damage, int &damagetype, int &weapon, float damageForce[3], float damagePosition[3]);
// SDKHooks 2.1+ (can check for support at runtime using GetFeatureStatus on SDKHook_DmgCustomInOTD capability.
// DON'T attempt to access 'damagecustom' var if feature status != available
Action:public(victim, &attacker, &inflictor, &Float:damage, &damagetype, &weapon,
Float:damageForce[3], Float:damagePosition[3], damagecustom),
function Action (int victim, int &attacker, int &inflictor, float &damage, int &damagetype, int &weapon,
float damageForce[3], float damagePosition[3], int damagecustom);
// OnTakeDamagePost
public(victim, attacker, inflictor, Float:damage, damagetype),
public(victim, attacker, inflictor, Float:damage, damagetype, weapon, const Float:damageForce[3], const Float:damagePosition[3]),
// OnTakeDamageAlivePost
function void (int victim, int attacker, int inflictor, float damage, int damagetype);
function void (int victim, int attacker, int inflictor, float damage, int damagetype, const float damageForce[3], const float damagePosition[3]);
// FireBulletsPost
public(client, shots, const String:weaponname[]),
function void (int client, int shots, const char[] weaponname);
// TraceAttack
Action:public(victim, &attacker, &inflictor, &Float:damage, &damagetype, &ammotype, hitbox, hitgroup),
function Action (int victim, int &attacker, int &inflictor, float &damage, int &damagetype, int &ammotype, int hitbox, int hitgroup);
// TraceAttackPost
public(victim, attacker, inflictor, Float:damage, damagetype, ammotype, hitbox, hitgroup),
function void (int victim, int attacker, int inflictor, float damage, int damagetype, int ammotype, int hitbox, int hitgroup);
// ShouldCollide
bool:public(entity, collisiongroup, contentsmask, bool:originalResult),
function bool (int entity, int collisiongroup, int contentsmask, bool originalResult);
// Use
Action:public(entity, activator, caller, UseType:type, Float:value),
function Action (int entity, int activator, int caller, UseType type, float value);
// UsePost
public(entity, activator, caller, UseType:type, Float:value),
function void (int entity, int activator, int caller, UseType type, float value);
// Reload
Action:public(weapon),
function Action (int weapon);
// Reload post
public(weapon, bool:bSuccessful)
function void (int weapon, bool bSuccessful);
};

View File

@ -110,7 +110,7 @@ enum RayType
RayType_Infinite /**< The trace ray will go from the start position to infinity using a direction vector. */
};
funcenum TraceEntityFilter
union TraceEntityFilter
{
/**
* Called on entity filtering.
@ -119,7 +119,7 @@ funcenum TraceEntityFilter
* @param contentsMask Contents Mask.
* @return True to allow the current entity to be hit, otherwise false.
*/
bool:public(entity, contentsMask),
function bool (int entity, int contentsMask);
/**
* Called on entity filtering.
@ -129,7 +129,7 @@ funcenum TraceEntityFilter
* @param data Data value, if used.
* @return True to allow the current entity to be hit, otherwise false.
*/
bool:public(entity, contentsMask, any:data),
function bool (int entity, int contentsMask, any data);
};
/**
@ -371,4 +371,4 @@ native TR_GetPlaneNormal(Handle:hndl, Float:normal[3]);
* @param pos Vector buffer to store data in.
* @return True if outside world, otherwise false.
*/
native TR_PointOutsideWorld(Float:pos[3]);
native TR_PointOutsideWorld(Float:pos[3]);

View File

@ -123,10 +123,10 @@ native SortCustom1D(array[], array_size, SortFunc1D:sortfunc, Handle:hndl=INVALI
* 0 if first is equal to second
* 1 if first should go after second
*/
funcenum SortFunc2D
union SortFunc2D
{
public(elem1[], elem2[], const array[][], Handle:hndl),
public(String:elem1[], String:elem2[], const String:array[][], Handle:hndl),
function int (int[] elem1, int[] elem2, const int[][] array, Handle hndl);
function int (char[] elem1, char[] elem2, const char[][] array, Handle hndl);
};
/**

View File

@ -153,6 +153,10 @@ enum TFCond
TFCond_HalloweenTiny,
TFCond_HalloweenInHell,
TFCond_HalloweenGhostMode,
TFCond_DodgeChance = 79,
TFCond_Parachute,
TFCond_BlastJumping,
};
const Float:TFCondDuration_Infinite = -1.0;

View File

@ -249,6 +249,7 @@ enum {
TF_WEAPON_SPELLBOOK,
TF_WEAPON_SPELLBOOK_PROJECTILE,
TF_WEAPON_SNIPERRIFLE_CLASSIC,
TF_WEAPON_PARACHUTE,
};
// TF2 Weapon Loadout Slots

View File

@ -45,7 +45,7 @@
/**
* Any of the following prototypes will work for a timed function.
*/
funcenum Timer
union Timer
{
/**
* Called when the timer interval has elapsed.
@ -55,7 +55,7 @@ funcenum Timer
* @return Plugin_Stop to stop a repeating timer, any other value for
* default behavior.
*/
Action:public(Handle:timer, Handle:hndl),
function Action(Handle timer, Handle hndl);
/**
* Called when the timer interval has elapsed.
@ -65,7 +65,7 @@ funcenum Timer
* @return Plugin_Stop to stop a repeating timer, any other value for
* default behavior.
*/
Action:public(Handle:timer, any:data),
function Action(Handle timer, any data);
/**
* Called when the timer interval has elapsed.
@ -74,7 +74,7 @@ funcenum Timer
* @return Plugin_Stop to stop a repeating timer, any other value for
* default behavior.
*/
Action:public(Handle:timer),
function Action(Handle timer);
};
/**

View File

@ -41,7 +41,7 @@
#include <IAdminSystem.h>
#define SMINTERFACE_PLAYERMANAGER_NAME "IPlayerManager"
#define SMINTERFACE_PLAYERMANAGER_VERSION 20
#define SMINTERFACE_PLAYERMANAGER_VERSION 21
struct edict_t;
class IPlayerInfo;
@ -267,6 +267,15 @@ namespace SourceMod
* @brief Removes admin access from the client.
*/
virtual void ClearAdmin() =0;
/**
* @brief Returns the client's Steam ID as a uint64.
*
* @param validated Check backend validation status.
*
* @return Steam Id or 0 if not available.
*/
virtual uint64_t GetSteamId64(bool validated = true) =0;
};
/**

View File

@ -0,0 +1,99 @@
// vim: set sts=8 ts=2 sw=2 tw=99 et:
//
// Copyright (C) 2013-2014, David Anderson and AlliedModders LLC
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
// * Neither the name of AlliedModders LLC nor the names of its contributors
// may be used to endorse or promote products derived from this software
// without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
#ifndef _include_amtl_fixedarray_h_
#define _include_amtl_fixedarray_h_
#include <am-utility.h>
#include <am-allocator-policies.h>
#include <am-moveable.h>
namespace ke {
template <typename T, typename AllocPolicy = SystemAllocatorPolicy>
class FixedArray : public AllocPolicy
{
public:
FixedArray(size_t length, AllocPolicy = AllocPolicy()) {
length_ = length;
data_ = (T *)this->malloc(sizeof(T) * length_);
if (!data_)
return;
for (size_t i = 0; i < length_; i++)
new (&data_[i]) T();
}
~FixedArray() {
for (size_t i = 0; i < length_; i++)
data_[i].~T();
this->free(data_);
}
// This call may be skipped if the allocator policy is infallible.
bool initialize() {
return length_ == 0 || !!data_;
}
size_t length() const {
return length_;
}
T &operator [](size_t index) {
return at(index);
}
const T &operator [](size_t index) const {
return at(index);
}
T &at(size_t index) {
assert(index < length());
return data_[index];
}
const T &at(size_t index) const {
assert(index < length());
return data_[index];
}
void set(size_t index, const T &t) {
assert(index < length());
data_[index] = t;
}
void set(size_t index, ke::Moveable<T> t) {
assert(index < length());
data_[index] = t;
}
private:
FixedArray(const FixedArray &other) KE_DELETE;
FixedArray &operator =(const FixedArray &other) KE_DELETE;
private:
size_t length_;
T *data_;
};
} // namespace ke
#endif // _include_amtl_fixedarray_h_

50
public/amtl/am-float.h Normal file
View File

@ -0,0 +1,50 @@
// vim: set sts=8 ts=2 sw=2 tw=99 et:
//
// Copyright (C) 2013, David Anderson and AlliedModders LLC
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
// * Neither the name of AlliedModders LLC nor the names of its contributors
// may be used to endorse or promote products derived from this software
// without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
#ifndef _include_amtl_float_h_
#define _include_amtl_float_h_
#include <math.h>
#include <float.h>
namespace ke {
static inline bool
IsNaN(double v)
{
#ifdef _MSC_VER
return !!_isnan(v);
#else
return isnan(v);
#endif
}
} // namespace ke
#endif // _include_amtl_float_h_

View File

@ -138,19 +138,24 @@ class HashMap : public AllocPolicy
// The map must not have been mutated in between findForAdd() and add().
// The Insert object is still valid after add() returns, however.
bool add(Insert &i, const K &key, const V &value) {
return table_.add(i, Entry(key, value));
Entry entry(key, value);
return table_.add(i, ke::Move(entry));
}
bool add(Insert &i, Moveable<K> key, const V &value) {
return table_.add(i, Entry(key, value));
Entry entry(key, value);
return table_.add(i, ke::Move(entry));
}
bool add(Insert &i, const K &key, Moveable<V> value) {
return table_.add(i, Entry(key, value));
Entry entry(key, value);
return table_.add(i, ke::Move(entry));
}
bool add(Insert &i, Moveable<K> key, Moveable<V> value) {
return table_.add(i, Entry(key, value));
Entry entry(key, value);
return table_.add(i, ke::Move(entry));
}
bool add(Insert &i, Moveable<K> key) {
return table_.add(i, Entry(key, V()));
Entry entry(key, V());
return table_.add(i, ke::Move(entry));
}
// This can be used to avoid compiler constructed temporaries, since AMTL

View File

@ -35,12 +35,15 @@
namespace ke {
// See the comment above Refcounted<T> for more information. This class is
// identical, except changing the reference count is guaranteed to be atomic
// with respect to other threads changing the reference count.
template <typename T>
class RefcountedThreadsafe
{
public:
RefcountedThreadsafe()
: refcount_(1)
: refcount_(0)
{
}

View File

@ -37,18 +37,35 @@ namespace ke {
template <typename T> class Ref;
// Holds a refcounted T without addrefing it. This is similar to PassRef<>
// below, but is intended only for freshly allocated objects which start
// with reference count 1, and we don't want to add an extra ref just by
// assigning to PassRef<> or Ref<>.
// Objects in AMTL inheriting from Refcounted will have an initial refcount
// of 0. However, in some systems (such as COM), the initial refcount is 1,
// or functions may return raw pointers that have been AddRef'd. In these
// cases it would be a mistake to use Ref<> or PassRef<>, since the object
// would leak an extra reference.
//
// This container holds a refcounted object without addrefing it. This is
// intended only for interacting with functions which return an object that
// has been manually AddRef'd. Note that this will perform a Release(), so
// so it is necessary to assign it to retain the object.
template <typename T>
class Newborn
class AlreadyRefed
{
public:
Newborn(T *t)
AlreadyRefed(T *t)
: thing_(t)
{
}
AlreadyRefed(const AlreadyRefed<T> &other)
: thing_(other.thing_)
{
// If copy elision for some reason doesn't happen (for example, when
// returning from AdoptRef), just null out the source ref.
other.thing_ = NULL;
}
~AlreadyRefed() {
if (thing_)
thing_->Release();
}
T *release() const {
return ReturnAndVoid(thing_);
@ -59,10 +76,10 @@ class Newborn
};
template <typename T>
static inline Newborn<T>
NoAddRef(T *t)
static inline AlreadyRefed<T>
AdoptRef(T *t)
{
return Newborn<T>(t);
return AlreadyRefed<T>(t);
}
// When returning a value, we'd rather not be needlessly changing the refcount,
@ -81,7 +98,14 @@ class PassRef
{
}
PassRef(const Newborn<T *> &other)
PassRef(const AlreadyRefed<T *> &other)
: thing_(other.release())
{
// Don't addref, newborn means already addref'd.
}
template <typename S>
PassRef(const AlreadyRefed<S *> &other)
: thing_(other.release())
{
// Don't addref, newborn means already addref'd.
@ -134,7 +158,7 @@ class PassRef
private:
// Disallowed operators.
PassRef &operator =(T *other);
PassRef &operator =(Newborn<T> &other);
PassRef &operator =(AlreadyRefed<T> &other);
void AddRef() {
if (thing_)
@ -149,13 +173,18 @@ class PassRef
mutable T *thing_;
};
// Classes which are refcounted should inherit from this.
// Classes which are refcounted should inherit from this. Note that reference
// counts start at 0 in AMTL, rather than 1. This avoids the complexity of
// having to adopt the initial ref upon allocation. However, this also means
// invoking Release() on a newly allocated object is illegal. Newborn objects
// must either be assigned to a Ref or PassRef (NOT an AdoptRef/AlreadyRefed),
// or must be deleted using |delete|.
template <typename T>
class Refcounted
{
public:
Refcounted()
: refcount_(1)
: refcount_(0)
{
}
@ -217,7 +246,12 @@ class Ref
: thing_(other.release())
{
}
Ref(const Newborn<T> &other)
Ref(const AlreadyRefed<T> &other)
: thing_(other.release())
{
}
template <typename S>
Ref(const AlreadyRefed<S> &other)
: thing_(other.release())
{
}
@ -255,7 +289,7 @@ class Ref
}
template <typename S>
Ref &operator =(const Newborn<S> &other) {
Ref &operator =(const AlreadyRefed<S> &other) {
Release();
thing_ = other.release();
return *this;

View File

@ -56,7 +56,7 @@ class AString
if (other.length_)
set(other.chars_, other.length_);
else
length_ = 0;
length_ = 0;
}
AString(Moveable<AString> other)
: chars_(other->chars_.take()),
@ -117,6 +117,8 @@ class AString
}
private:
static const size_t kInvalidLength = (size_t)-1;
void set(const char *str, size_t length) {
chars_ = new char[length + 1];
length_ = length;

View File

@ -0,0 +1,175 @@
// vim: set sts=2 ts=8 sw=2 tw=99 et:
//
// Copyright (C) 2013, David Anderson and AlliedModders LLC
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
// * Neither the name of AlliedModders LLC nor the names of its contributors
// may be used to endorse or promote products derived from this software
// without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
#ifndef _include_amtl_thread_local_h_
#define _include_amtl_thread_local_h_
#include <am-thread-utils.h>
namespace ke {
// Stores a per-thread value. In single-threaded mode (KE_SINGLE_THREADED),
// this is a no-op container wrapper.
//
// T must be castable to uintptr_t.
//
// When assigning to a ThreadLocal<T>, the assigment will automatically attempt
// to allocate thread-local storage from the operating system. If it fails, it
// will abort the program. If this is undesirable, you may call allocate()
// up-front and handle the error case manually.
//
// The number of thread local slots available to processes is limited (on
// Linux, it is generally 1024). It is best to use ThreadLocal sparingly to
// play nicely with other libraries.
//
// ThreadLocal will free the underlying thread-local storage slot in its
// destructor, but it is not an AutoPtr. It does not delete pointers. Since
// one thread's value is only observable from that thread, make sure to free
// the contained resource (if necessary) before the thread exits.
template <typename T>
class ThreadLocal
{
public:
void operator =(const T &other) {
set(other);
}
T operator *() const {
return get();
}
T operator ->() const {
return get();
}
bool operator !() const {
return !get();
}
bool operator ==(const T &other) const {
return get() == other;
}
bool operator !=(const T &other) const {
return get() != other;
}
private:
ThreadLocal(const ThreadLocal &other) KE_DELETE;
ThreadLocal &operator =(const ThreadLocal &other) KE_DELETE;
#if !defined(KE_SINGLE_THREADED)
private:
int allocated_;
public:
ThreadLocal() {
allocated_ = 0;
}
T get() const {
if (!allocated_)
return T();
return internalGet();
}
void set(const T &t) {
if (!allocated_ && !allocate()) {
fprintf(stderr, "could not allocate thread-local storage\n");
abort();
}
internalSet(t);
}
# if defined(_MSC_VER)
~ThreadLocal() {
if (allocated_)
TlsFree(key_);
}
private:
T internalGet() const {
return reinterpret_cast<T>(TlsGetValue(key_));
}
void internalSet(const T &t) {
TlsSetValue(key_, reinterpret_cast<LPVOID>(t));
}
bool allocate() {
if (InterlockedCompareExchange(&allocated_, 1, 0) == 1)
return true;
key_ = TlsAlloc();
return key_ != TLS_OUT_OF_INDEXES;
}
DWORD key_;
# else
public:
~ThreadLocal() {
if (allocated_)
pthread_key_delete(key_);
}
bool allocate() {
if (!__sync_bool_compare_and_swap(&allocated_, 0, 1))
return true;
return pthread_key_create(&key_, NULL) == 0;
}
private:
T internalGet() const {
return (T)reinterpret_cast<uintptr_t>(pthread_getspecific(key_));
}
void internalSet(const T &t) {
pthread_setspecific(key_, reinterpret_cast<void *>(t));
}
pthread_key_t key_;
# endif // !_MSC_VER
#else // KE_SINGLE_THREADED
public:
ThreadLocal() {
t_ = T();
}
bool allocate() {
return true;
}
T get() const {
return t_;
}
void set(const T &t) {
t_ = t;
}
private:
T t_;
#endif
};
} // namespace ke
#endif // _include_amtl_thread_local_h_

View File

@ -34,8 +34,6 @@
#include <stddef.h>
#include <stdlib.h>
#include <stdint.h>
#include <math.h>
#include <float.h>
#if defined(_MSC_VER)
# include <intrin.h>
#endif
@ -89,7 +87,7 @@ class AutoPtr
: t_(NULL)
{
}
AutoPtr(T *t)
explicit AutoPtr(T *t)
: t_(t)
{
}
@ -220,16 +218,6 @@ FindRightmostBit(size_t number)
#endif
}
static inline bool
IsNaN(double v)
{
#ifdef _MSC_VER
return !!_isnan(v);
#else
return isnan(v);
#endif
}
static inline bool
IsPowerOfTwo(size_t value)
{
@ -358,10 +346,46 @@ class SaveAndSet
T old_;
};
template <typename T>
class StackLinked
{
public:
StackLinked<T>(T **prevp)
: prevp_(prevp),
prev_(*prevp)
{
*prevp_ = static_cast<T *>(this);
}
virtual ~StackLinked() {
assert(*prevp_ == this);
*prevp_ = prev_;
}
private:
T **prevp_;
T *prev_;
};
#if __cplusplus >= 201103L
# define KE_CXX11
#endif
#if defined(KE_CXX11)
# define KE_DELETE = delete
# define KE_OVERRIDE override
#else
# define KE_DELETE
# define KE_OVERRIDE
#endif
#if defined(_MSC_VER)
# define KE_SIZET_FMT "%Iu"
# define KE_I64_FMT "%I64d"
# define KE_U64_FMT "%I64u"
#elif defined(__GNUC__)
# define KE_SIZET_FMT "%zu"
# define KE_I64_FMT "%lld"
# define KE_U64_FMT "%llu"
#else
# error "Implement format specifier string"
#endif

View File

@ -74,7 +74,7 @@ static const char *prefix[3]={ "error", "fatal error", "warning" };
if (number!=0) {
int idx;
if (number < 160)
if (number < 160 || (number >= 200 && sc_warnings_are_errors))
idx = 0;
else if (number < 200)
idx = 1;

View File

@ -432,6 +432,7 @@ enum TokenKind {
tTAGOF,
tTHEN,
tTYPEDEF,
tUNION,
tVOID,
tWHILE,
/* compiler directives */
@ -904,6 +905,7 @@ extern int pc_tag_nullfunc_t; /* the null function type */
extern int pc_anytag; /* global any tag */
extern int glbstringread; /* last global string read */
extern int sc_require_newdecls; /* only newdecls are allowed */
extern bool sc_warnings_are_errors;
extern constvalue sc_automaton_tab; /* automaton table */
extern constvalue sc_state_tab; /* state table */

View File

@ -144,6 +144,7 @@ static void dolabel(void);
static void doreturn(void);
static void dofuncenum(int listmode);
static void dotypedef();
static void dounion();
static void domethodmap(LayoutSpec spec);
static void dobreak(void);
static void docont(void);
@ -914,6 +915,9 @@ static void parseoptions(int argc,char **argv,char *oname,char *ename,char *pnam
case 'e':
strlcpy(ename,option_value(ptr),_MAX_PATH); /* set name of error file */
break;
case 'E':
sc_warnings_are_errors = true;
break;
#if defined __WIN32__ || defined _WIN32 || defined _Windows
case 'H':
hwndFinish=(HWND)atoi(option_value(ptr));
@ -1282,6 +1286,7 @@ static void about(void)
pc_printf(" -t<num> TAB indent size (in character positions, default=%d)\n",sc_tabsize);
pc_printf(" -v<num> verbosity level; 0=quiet, 1=normal, 2=verbose (default=%d)\n",verbosity);
pc_printf(" -w<num> disable a specific warning by its number\n");
pc_printf(" -E treat warnings as errors\n");
pc_printf(" -X<num> abstract machine size limit in bytes\n");
pc_printf(" -XD<num> abstract machine data/stack size limit in bytes\n");
pc_printf(" -\\ use '\\' for escape characters\n");
@ -1506,6 +1511,9 @@ static void parse(void)
case tTYPEDEF:
dotypedef();
break;
case tUNION:
dounion();
break;
case tSTRUCT:
declstruct();
break;
@ -2689,8 +2697,11 @@ static cell initvector(int ident,int tag,cell size,int fillzero,
} while (matchtoken(',')); /* do */
needtoken('}');
} else {
init(ident,&ctag,errorfound);
matchtag(tag,ctag,TRUE);
if (!lexpeek('}'))
{
init(ident,&ctag,errorfound);
matchtag(tag,ctag,TRUE);
}
} /* if */
/* fill up the literal queue with a series */
if (ellips) {
@ -3192,6 +3203,8 @@ static int parse_old_decl(declinfo_t *decl, int flags)
}
needtoken(':');
}
if (type->numtags > 1)
error(158);
}
if (type->numtags == 0) {
@ -4214,6 +4227,27 @@ static void dotypedef()
functags_add(def, &type);
}
// Unsafe union - only supports function types. This is a transition hack for SP2.
static void dounion()
{
token_ident_t ident;
if (!needsymbol(&ident))
return;
int prev_tag = pc_findtag(ident.name);
if (prev_tag != -1 && !(prev_tag & FUNCTAG))
error(94);
funcenum_t *def = funcenums_add(ident.name);
needtoken('{');
while (!matchtoken('}')) {
functag_t type;
parse_function_type(&type);
functags_add(def, &type);
}
require_newline(TRUE);
}
/**
* dofuncenum - declare function enumerations

View File

@ -1963,6 +1963,7 @@ const char *sc_tokens[] = {
"return",
"sizeof", "sleep", "static", "stock", "struct", "switch",
"tagof", "*then", "typedef",
"union",
"void",
"while",
"#assert", "#define", "#else", "#elseif", "#emit", "#endif", "#endinput",

View File

@ -201,6 +201,7 @@ static const char *errmsg[] = {
/*155*/ "expected newline, but found '%s'\n",
/*156*/ "the 'any' type is not allowed in new-style natives\n",
/*157*/ "'%s' is a reserved keyword\n",
/*158*/ "multi-tags are no longer supported\n",
#else
"\315e\306\227\266k\217:\235\277bu\201fo\220\204\223\012",
"\202l\224\250s\205g\346\356e\233\201(\243\315\214\267\202) \253 f\255low ea\305 \042c\353e\042\012",

View File

@ -1,3 +1,4 @@
// vim: set ts=8 sts=2 sw=2 tw=99 et:
/* Pawn compiler - Error message system
* In fact a very simple system, using only 'panic mode'.
*
@ -81,6 +82,8 @@ static short lastfile;
int errline = sErrLine;
sErrLine = -1;
bool is_warning = (number >= 200 && !sc_warnings_are_errors);
/* errflag is reset on each semicolon.
* In a two-pass compiler, an error should not be reported twice. Therefore
* the error reporting is enabled only in the second pass (and only when
@ -113,8 +116,13 @@ static short lastfile;
errnum++; /* a fatal error also counts as an error */
} else {
msg=warnmsg[number-200];
pre=prefix[2];
warnnum++;
if (sc_warnings_are_errors) {
pre=prefix[0];
errnum++;
} else {
pre=prefix[2];
warnnum++;
}
} /* if */
assert(errstart<=fline);
@ -164,7 +172,7 @@ static short lastfile;
errorcount=0;
lastline=fline;
lastfile=fcurrent;
if (number<200)
if (!is_warning)
errorcount++;
if (errorcount>=3)
error(167); /* too many error/warning messages on one line */

View File

@ -94,6 +94,7 @@ int pc_optimize=sOPTIMIZE_NOMACRO; /* (peephole) optimization level */
int pc_memflags=0; /* special flags for the stack/heap usage */
int sc_showincludes=0; /* show include files */
int sc_require_newdecls=0; /* Require new-style declarations */
bool sc_warnings_are_errors=false;
constvalue sc_automaton_tab = { NULL, "", 0, 0}; /* automaton table */
constvalue sc_state_tab = { NULL, "", 0, 0}; /* state table */

View File

@ -0,0 +1,20 @@
new String:oldArray[][] =
{
"string",
"string2",
};
char newArray[][] =
{
"another string",
"more strings",
};
native Print( const String:string[] );
public OnPluginStart()
{
Print( oldArray[ 0 ] );
Print( newArray[ 0 ] );
}