diff --git a/core/AMBuilder b/core/AMBuilder index d9f62d83..b8f466be 100644 --- a/core/AMBuilder +++ b/core/AMBuilder @@ -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'), diff --git a/core/ConCmdManager.cpp b/core/ConCmdManager.cpp index 80d3f703..e93c6cc3 100644 --- a/core/ConCmdManager.cpp +++ b/core/ConCmdManager.cpp @@ -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 cmdgroup = i->value; diff --git a/core/EventManager.cpp b/core/EventManager.cpp index 308dbf9c..89d4da25 100644 --- a/core/EventManager.cpp +++ b/core/EventManager.cpp @@ -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; diff --git a/core/EventManager.h b/core/EventManager.h index 005b938f..12d2e7d4 100644 --- a/core/EventManager.h +++ b/core/EventManager.h @@ -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: diff --git a/core/PlayerManager.cpp b/core/PlayerManager.cpp index 587db7e5..c9600edf 100644 --- a/core/PlayerManager.cpp +++ b/core/PlayerManager.cpp @@ -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() diff --git a/core/PlayerManager.h b/core/PlayerManager.h index 9bb58f0b..cfd57cc0 100644 --- a/core/PlayerManager.h +++ b/core/PlayerManager.h @@ -43,6 +43,8 @@ #include #include "ConVarManager.h" +#include + 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 diff --git a/core/logic/GameConfigs.cpp b/core/logic/GameConfigs.cpp index 12067853..8c122425 100644 --- a/core/logic/GameConfigs.cpp +++ b/core/logic/GameConfigs.cpp @@ -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; diff --git a/core/logic/ShareSys.cpp b/core/logic/ShareSys.cpp index 77769662..ddde22a5 100644 --- a/core/logic/ShareSys.cpp +++ b/core/logic/ShareSys.cpp @@ -375,7 +375,7 @@ PassRef ShareSystem::AddNativeToCache(CNativeOwner *pOwner, const sp_nat if (i.found()) return NULL; - Ref entry = Newborn(new Native(pOwner, ntv)); + Ref entry = new Native(pOwner, ntv); m_NtvCache.insert(ntv->name, entry); return entry; } @@ -415,7 +415,7 @@ PassRef ShareSystem::AddFakeNative(IPluginFunction *pFunc, const char *n CNativeOwner *owner = g_PluginSys.GetPluginByCtx(fake->ctx->GetContext()); - entry = Newborn(new Native(owner, fake.take())); + entry = new Native(owner, fake.take()); m_NtvCache.insert(name, entry); return entry; diff --git a/core/logic/intercom.h b/core/logic/intercom.h index 2fa40410..78dd1eaf 100644 --- a/core/logic/intercom.h +++ b/core/logic/intercom.h @@ -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 diff --git a/core/logic/smn_adt_trie.cpp b/core/logic/smn_adt_trie.cpp index ab70f8cc..989df0f4 100644 --- a/core/logic/smn_adt_trie.cpp +++ b/core/logic/smn_adt_trie.cpp @@ -163,7 +163,7 @@ private: cell_t data_; }; -struct CellTrie : public ke::Refcounted +struct CellTrie { StringHashMap 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; diff --git a/core/logic/smn_filesystem.cpp b/core/logic/smn_filesystem.cpp index 82430e52..16f20e3c 100644 --- a/core/logic/smn_filesystem.cpp +++ b/core/logic/smn_filesystem.cpp @@ -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(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(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(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(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(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(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(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(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(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(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(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) diff --git a/core/logic/smn_float.cpp b/core/logic/smn_float.cpp index 73c95f8e..784de670 100644 --- a/core/logic/smn_float.cpp +++ b/core/logic/smn_float.cpp @@ -36,6 +36,7 @@ #include "MersenneTwister.h" #include #include +#include /**************************************** * * diff --git a/core/logic/smn_players.cpp b/core/logic/smn_players.cpp index 47288f0a..34b24798 100644 --- a/core/logic/smn_players.cpp +++ b/core/logic/smn_players.cpp @@ -37,12 +37,21 @@ #include #include #include +#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(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 }, diff --git a/core/logic_bridge.cpp b/core/logic_bridge.cpp index 13fba9fe..05b2aa8c 100644 --- a/core/logic_bridge.cpp +++ b/core/logic_bridge.cpp @@ -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; diff --git a/core/sm_stringutil.cpp b/core/sm_stringutil.cpp index 86ada852..6babf358 100644 --- a/core/sm_stringutil.cpp +++ b/core/sm_stringutil.cpp @@ -39,6 +39,7 @@ #include "logic_bridge.h" #include "sourcemod.h" #include +#include #define LADJUST 0x00000004 /* left adjustment */ #define ZEROPAD 0x00000080 /* zero (as opposed to blank) pad */ diff --git a/extensions/clientprefs/extension.cpp b/extensions/clientprefs/extension.cpp index 96a3173b..7ff5eee2 100644 --- a/extensions/clientprefs/extension.cpp +++ b/extensions/clientprefs/extension.cpp @@ -219,7 +219,7 @@ void ClientPrefs::DatabaseConnect() char error[256]; int errCode = 0; - Database = Newborn(Driver->Connect(DBInfo, true, error, sizeof(error))); + Database = AdoptRef(Driver->Connect(DBInfo, true, error, sizeof(error))); if (!Database) { diff --git a/extensions/mysql/mysql/MyDatabase.cpp b/extensions/mysql/mysql/MyDatabase.cpp index 74825bfb..84f34537 100644 --- a/extensions/mysql/mysql/MyDatabase.cpp +++ b/extensions/mysql/mysql/MyDatabase.cpp @@ -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() diff --git a/extensions/sdkhooks/extension.cpp b/extensions/sdkhooks/extension.cpp index 646776c7..94d6009f 100644 --- a/extensions/sdkhooks/extension.cpp +++ b/extensions/sdkhooks/extension.cpp @@ -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 &vtablehooklist = g_HookList[SDKHook_OnTakeDamage]; + ke::Vector &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 &vtablehooklist = g_HookList[SDKHook_OnTakeDamagePost]; + ke::Vector &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); diff --git a/extensions/sdkhooks/extension.h b/extensions/sdkhooks/extension.h index 5c88ff9c..50f2116b 100644 --- a/extensions/sdkhooks/extension.h +++ b/extensions/sdkhooks/extension.h @@ -1,349 +1,361 @@ -#ifndef _INCLUDE_SOURCEMOD_EXTENSION_PROPER_H_ -#define _INCLUDE_SOURCEMOD_EXTENSION_PROPER_H_ - -#include "smsdk_ext.h" -#include -#include -#include -#include -#include -#include - -#include -#include - -#if SOURCE_ENGINE >= SE_ORANGEBOX -#include -#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 hooks; -}; - +#ifndef _INCLUDE_SOURCEMOD_EXTENSION_PROPER_H_ +#define _INCLUDE_SOURCEMOD_EXTENSION_PROPER_H_ + +#include "smsdk_ext.h" +#include +#include +#include +#include +#include +#include + +#include +#include + +#if SOURCE_ENGINE >= SE_ORANGEBOX +#include +#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 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 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 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 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 g_HookList[SDKHook_MAXHOOKS]; + +extern ICvar *icvar; + +#if SOURCE_ENGINE >= SE_ORANGEBOX +extern IServerTools *servertools; +#endif + +#endif // _INCLUDE_SOURCEMOD_EXTENSION_PROPER_H_ diff --git a/extensions/sqlite/driver/SqDatabase.cpp b/extensions/sqlite/driver/SqDatabase.cpp index 91811aa5..e0f13e80 100644 --- a/extensions/sqlite/driver/SqDatabase.cpp +++ b/extensions/sqlite/driver/SqDatabase.cpp @@ -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() diff --git a/gamedata/core.games/engine.bgt.txt b/gamedata/core.games/engine.bgt.txt index 674993e8..c4502dbb 100644 --- a/gamedata/core.games/engine.bgt.txt +++ b/gamedata/core.games/engine.bgt.txt @@ -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" + } } } diff --git a/gamedata/core.games/engine.css.txt b/gamedata/core.games/engine.css.txt index cf08b2b0..2ec1cc75 100644 --- a/gamedata/core.games/engine.css.txt +++ b/gamedata/core.games/engine.css.txt @@ -53,5 +53,10 @@ "mac" "@gEntList" } } + + "Keys" + { + "UseInvalidUniverseInSteam2IDs" "1" + } } } diff --git a/gamedata/core.games/engine.darkm.txt b/gamedata/core.games/engine.darkm.txt index d84d54b3..f458d257 100644 --- a/gamedata/core.games/engine.darkm.txt +++ b/gamedata/core.games/engine.darkm.txt @@ -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" + } } } diff --git a/gamedata/core.games/engine.ep1.txt b/gamedata/core.games/engine.ep1.txt index de669556..932f92ca 100644 --- a/gamedata/core.games/engine.ep1.txt +++ b/gamedata/core.games/engine.ep1.txt @@ -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" + } } } diff --git a/gamedata/core.games/engine.ep2.txt b/gamedata/core.games/engine.ep2.txt index ba0a3460..d1a4f5bd 100644 --- a/gamedata/core.games/engine.ep2.txt +++ b/gamedata/core.games/engine.ep2.txt @@ -58,4 +58,12 @@ } } } + + "#default" + { + "Keys" + { + "UseInvalidUniverseInSteam2IDs" "1" + } + } } diff --git a/gamedata/core.games/engine.ep2valve.txt b/gamedata/core.games/engine.ep2valve.txt index 55eef306..0dc63e82 100644 --- a/gamedata/core.games/engine.ep2valve.txt +++ b/gamedata/core.games/engine.ep2valve.txt @@ -52,5 +52,10 @@ "mac" "@gEntList" } } + + "Keys" + { + "UseInvalidUniverseInSteam2IDs" "1" + } } } diff --git a/gamedata/core.games/engine.eye.txt b/gamedata/core.games/engine.eye.txt index f99e691d..045f65aa 100644 --- a/gamedata/core.games/engine.eye.txt +++ b/gamedata/core.games/engine.eye.txt @@ -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" + } } } diff --git a/gamedata/core.games/engine.sdk2013.txt b/gamedata/core.games/engine.sdk2013.txt index 498fb367..4912944c 100644 --- a/gamedata/core.games/engine.sdk2013.txt +++ b/gamedata/core.games/engine.sdk2013.txt @@ -95,4 +95,12 @@ } } } + + "#default" + { + "Keys" + { + "UseInvalidUniverseInSteam2IDs" "1" + } + } } diff --git a/gamedata/sdkhooks.games/engine.blade.txt b/gamedata/sdkhooks.games/engine.blade.txt index 1973cf49..50e1e831 100644 --- a/gamedata/sdkhooks.games/engine.blade.txt +++ b/gamedata/sdkhooks.games/engine.blade.txt @@ -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" diff --git a/gamedata/sdkhooks.games/engine.csgo.txt b/gamedata/sdkhooks.games/engine.csgo.txt index 31ad5852..54f0fca3 100644 --- a/gamedata/sdkhooks.games/engine.csgo.txt +++ b/gamedata/sdkhooks.games/engine.csgo.txt @@ -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" diff --git a/gamedata/sdkhooks.games/engine.ep2v.txt b/gamedata/sdkhooks.games/engine.ep2v.txt index fa71bd24..7c0be283 100644 --- a/gamedata/sdkhooks.games/engine.ep2v.txt +++ b/gamedata/sdkhooks.games/engine.ep2v.txt @@ -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" diff --git a/gamedata/sdkhooks.games/engine.insurgency.txt b/gamedata/sdkhooks.games/engine.insurgency.txt index 1f67f9d3..92008cea 100644 --- a/gamedata/sdkhooks.games/engine.insurgency.txt +++ b/gamedata/sdkhooks.games/engine.insurgency.txt @@ -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" diff --git a/gamedata/sdkhooks.games/engine.l4d.txt b/gamedata/sdkhooks.games/engine.l4d.txt index 97f6da37..abe3ea9d 100644 --- a/gamedata/sdkhooks.games/engine.l4d.txt +++ b/gamedata/sdkhooks.games/engine.l4d.txt @@ -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" diff --git a/gamedata/sdkhooks.games/game.cstrike.txt b/gamedata/sdkhooks.games/game.cstrike.txt index 93f386f0..06707425 100644 --- a/gamedata/sdkhooks.games/game.cstrike.txt +++ b/gamedata/sdkhooks.games/game.cstrike.txt @@ -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" diff --git a/gamedata/sdkhooks.games/game.fof.txt b/gamedata/sdkhooks.games/game.fof.txt index be2cf534..b98682f5 100644 --- a/gamedata/sdkhooks.games/game.fof.txt +++ b/gamedata/sdkhooks.games/game.fof.txt @@ -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" diff --git a/gamedata/sdkhooks.games/game.l4d2.txt b/gamedata/sdkhooks.games/game.l4d2.txt index 46395471..e64604eb 100644 --- a/gamedata/sdkhooks.games/game.l4d2.txt +++ b/gamedata/sdkhooks.games/game.l4d2.txt @@ -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" diff --git a/gamedata/sdkhooks.games/game.nmrih.txt b/gamedata/sdkhooks.games/game.nmrih.txt index 4eedd98b..e2e98198 100644 --- a/gamedata/sdkhooks.games/game.nmrih.txt +++ b/gamedata/sdkhooks.games/game.nmrih.txt @@ -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" diff --git a/gamedata/sdkhooks.games/game.nucleardawn.txt b/gamedata/sdkhooks.games/game.nucleardawn.txt index a5432dd0..b95980b8 100644 --- a/gamedata/sdkhooks.games/game.nucleardawn.txt +++ b/gamedata/sdkhooks.games/game.nucleardawn.txt @@ -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" diff --git a/plugins/admin-flatfile/admin-flatfile.sp b/plugins/admin-flatfile/admin-flatfile.sp index 250ebb24..12f06711 100644 --- a/plugins/admin-flatfile/admin-flatfile.sp +++ b/plugins/admin-flatfile/admin-flatfile.sp @@ -70,7 +70,7 @@ public OnRebuildAdminCache(AdminCachePart:part) } } -ParseError(const String:format[], {Handle,String,Float,_}:...) +ParseError(const String:format[], any:...) { decl String:buffer[512]; diff --git a/plugins/include/clients.inc b/plugins/include/clients.inc index 174ca0ad..b30a3040 100644 --- a/plugins/include/clients.inc +++ b/plugins/include/clients.inc @@ -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. * diff --git a/plugins/include/console.inc b/plugins/include/console.inc index 6323102e..91c03222 100644 --- a/plugins/include/console.inc +++ b/plugins/include/console.inc @@ -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); }; /** diff --git a/plugins/include/events.inc b/plugins/include/events.inc index be3f2d46..771d1578 100644 --- a/plugins/include/events.inc +++ b/plugins/include/events.inc @@ -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); }; /** diff --git a/plugins/include/files.inc b/plugins/include/files.inc index c25ed8ac..ce9cbfbc 100644 --- a/plugins/include/files.inc +++ b/plugins/include/files.inc @@ -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. diff --git a/plugins/include/sdkhooks.inc b/plugins/include/sdkhooks.inc index 2b255044..65756e06 100644 --- a/plugins/include/sdkhooks.inc +++ b/plugins/include/sdkhooks.inc @@ -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); }; diff --git a/plugins/include/sdktools_trace.inc b/plugins/include/sdktools_trace.inc index 27de9201..ce493547 100644 --- a/plugins/include/sdktools_trace.inc +++ b/plugins/include/sdktools_trace.inc @@ -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]); \ No newline at end of file +native TR_PointOutsideWorld(Float:pos[3]); diff --git a/plugins/include/sorting.inc b/plugins/include/sorting.inc index 161aff00..e60bcd6e 100644 --- a/plugins/include/sorting.inc +++ b/plugins/include/sorting.inc @@ -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); }; /** diff --git a/plugins/include/tf2.inc b/plugins/include/tf2.inc index a1e9a9d9..7e079be4 100644 --- a/plugins/include/tf2.inc +++ b/plugins/include/tf2.inc @@ -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; diff --git a/plugins/include/tf2_stocks.inc b/plugins/include/tf2_stocks.inc index e0f250f6..43f69e24 100644 --- a/plugins/include/tf2_stocks.inc +++ b/plugins/include/tf2_stocks.inc @@ -249,6 +249,7 @@ enum { TF_WEAPON_SPELLBOOK, TF_WEAPON_SPELLBOOK_PROJECTILE, TF_WEAPON_SNIPERRIFLE_CLASSIC, + TF_WEAPON_PARACHUTE, }; // TF2 Weapon Loadout Slots diff --git a/plugins/include/timers.inc b/plugins/include/timers.inc index d0a9ed09..8da9696b 100644 --- a/plugins/include/timers.inc +++ b/plugins/include/timers.inc @@ -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); }; /** diff --git a/public/IPlayerHelpers.h b/public/IPlayerHelpers.h index 8b1d9cd2..35a174a7 100644 --- a/public/IPlayerHelpers.h +++ b/public/IPlayerHelpers.h @@ -41,7 +41,7 @@ #include #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; }; /** diff --git a/public/amtl/am-fixedarray.h b/public/amtl/am-fixedarray.h new file mode 100644 index 00000000..4681651d --- /dev/null +++ b/public/amtl/am-fixedarray.h @@ -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 +#include +#include + +namespace ke { + +template +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) { + 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_ diff --git a/public/amtl/am-float.h b/public/amtl/am-float.h new file mode 100644 index 00000000..e53f25a0 --- /dev/null +++ b/public/amtl/am-float.h @@ -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 +#include + +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_ diff --git a/public/amtl/am-hashmap.h b/public/amtl/am-hashmap.h index 9a2d1ee6..7d5c3839 100644 --- a/public/amtl/am-hashmap.h +++ b/public/amtl/am-hashmap.h @@ -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 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 value) { - return table_.add(i, Entry(key, value)); + Entry entry(key, value); + return table_.add(i, ke::Move(entry)); } bool add(Insert &i, Moveable key, Moveable value) { - return table_.add(i, Entry(key, value)); + Entry entry(key, value); + return table_.add(i, ke::Move(entry)); } bool add(Insert &i, Moveable 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 diff --git a/public/amtl/am-refcounting-threadsafe.h b/public/amtl/am-refcounting-threadsafe.h index a37b39d4..785ba62b 100644 --- a/public/amtl/am-refcounting-threadsafe.h +++ b/public/amtl/am-refcounting-threadsafe.h @@ -35,12 +35,15 @@ namespace ke { +// See the comment above Refcounted 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 class RefcountedThreadsafe { public: RefcountedThreadsafe() - : refcount_(1) + : refcount_(0) { } diff --git a/public/amtl/am-refcounting.h b/public/amtl/am-refcounting.h index 71a6f554..ea869464 100644 --- a/public/amtl/am-refcounting.h +++ b/public/amtl/am-refcounting.h @@ -37,18 +37,35 @@ namespace ke { template 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 -class Newborn +class AlreadyRefed { public: - Newborn(T *t) + AlreadyRefed(T *t) : thing_(t) { } + AlreadyRefed(const AlreadyRefed &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 -static inline Newborn -NoAddRef(T *t) +static inline AlreadyRefed +AdoptRef(T *t) { - return Newborn(t); + return AlreadyRefed(t); } // When returning a value, we'd rather not be needlessly changing the refcount, @@ -81,7 +98,14 @@ class PassRef { } - PassRef(const Newborn &other) + PassRef(const AlreadyRefed &other) + : thing_(other.release()) + { + // Don't addref, newborn means already addref'd. + } + + template + PassRef(const AlreadyRefed &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 &other); + PassRef &operator =(AlreadyRefed &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 class Refcounted { public: Refcounted() - : refcount_(1) + : refcount_(0) { } @@ -217,7 +246,12 @@ class Ref : thing_(other.release()) { } - Ref(const Newborn &other) + Ref(const AlreadyRefed &other) + : thing_(other.release()) + { + } + template + Ref(const AlreadyRefed &other) : thing_(other.release()) { } @@ -255,7 +289,7 @@ class Ref } template - Ref &operator =(const Newborn &other) { + Ref &operator =(const AlreadyRefed &other) { Release(); thing_ = other.release(); return *this; diff --git a/public/amtl/am-string.h b/public/amtl/am-string.h index 074339fa..4e62bde2 100644 --- a/public/amtl/am-string.h +++ b/public/amtl/am-string.h @@ -56,7 +56,7 @@ class AString if (other.length_) set(other.chars_, other.length_); else - length_ = 0; + length_ = 0; } AString(Moveable 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; diff --git a/public/amtl/am-threadlocal.h b/public/amtl/am-threadlocal.h new file mode 100644 index 00000000..df4c023c --- /dev/null +++ b/public/amtl/am-threadlocal.h @@ -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 + +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, 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 +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(TlsGetValue(key_)); + } + void internalSet(const T &t) { + TlsSetValue(key_, reinterpret_cast(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(pthread_getspecific(key_)); + } + void internalSet(const T &t) { + pthread_setspecific(key_, reinterpret_cast(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_ diff --git a/public/amtl/am-utility.h b/public/amtl/am-utility.h index 41f69dc7..1e31e067 100644 --- a/public/amtl/am-utility.h +++ b/public/amtl/am-utility.h @@ -34,8 +34,6 @@ #include #include #include -#include -#include #if defined(_MSC_VER) # include #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 +class StackLinked +{ + public: + StackLinked(T **prevp) + : prevp_(prevp), + prev_(*prevp) + { + *prevp_ = static_cast(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 diff --git a/sourcepawn/compiler/libpawnc.cpp b/sourcepawn/compiler/libpawnc.cpp index 76a8cca2..2ca5acea 100644 --- a/sourcepawn/compiler/libpawnc.cpp +++ b/sourcepawn/compiler/libpawnc.cpp @@ -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; diff --git a/sourcepawn/compiler/sc.h b/sourcepawn/compiler/sc.h index 0a6b6fb5..ee0d8544 100644 --- a/sourcepawn/compiler/sc.h +++ b/sourcepawn/compiler/sc.h @@ -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 */ diff --git a/sourcepawn/compiler/sc1.cpp b/sourcepawn/compiler/sc1.cpp index 95114951..43720315 100644 --- a/sourcepawn/compiler/sc1.cpp +++ b/sourcepawn/compiler/sc1.cpp @@ -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 TAB indent size (in character positions, default=%d)\n",sc_tabsize); pc_printf(" -v verbosity level; 0=quiet, 1=normal, 2=verbose (default=%d)\n",verbosity); pc_printf(" -w disable a specific warning by its number\n"); + pc_printf(" -E treat warnings as errors\n"); pc_printf(" -X abstract machine size limit in bytes\n"); pc_printf(" -XD 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 diff --git a/sourcepawn/compiler/sc2.cpp b/sourcepawn/compiler/sc2.cpp index b03d6929..7b5f25cd 100644 --- a/sourcepawn/compiler/sc2.cpp +++ b/sourcepawn/compiler/sc2.cpp @@ -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", diff --git a/sourcepawn/compiler/sc5-in.scp b/sourcepawn/compiler/sc5-in.scp index 0478abb2..f7ec5a24 100644 --- a/sourcepawn/compiler/sc5-in.scp +++ b/sourcepawn/compiler/sc5-in.scp @@ -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", diff --git a/sourcepawn/compiler/sc5.cpp b/sourcepawn/compiler/sc5.cpp index 64d2a649..e161ed1a 100644 --- a/sourcepawn/compiler/sc5.cpp +++ b/sourcepawn/compiler/sc5.cpp @@ -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 */ diff --git a/sourcepawn/compiler/scvars.cpp b/sourcepawn/compiler/scvars.cpp index 0f030923..3f1a5131 100644 --- a/sourcepawn/compiler/scvars.cpp +++ b/sourcepawn/compiler/scvars.cpp @@ -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 */ diff --git a/sourcepawn/compiler/tests/ok-trailing-comma-in-literal.sp b/sourcepawn/compiler/tests/ok-trailing-comma-in-literal.sp new file mode 100644 index 00000000..e1876f6d --- /dev/null +++ b/sourcepawn/compiler/tests/ok-trailing-comma-in-literal.sp @@ -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 ] ); +}