diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 88d4b7a..b87a500 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -11,15 +11,21 @@ jobs: build: strategy: matrix: - os: [ubuntu-18.04, ubuntu-latest, windows-2019] + os: [ubuntu-20.04, ubuntu-latest, windows-2019, windows-latest] include: - - os: ubuntu-18.04 + - os: ubuntu-20.04 + release: true cc: clang-8 cxx: clang++-8 - os: ubuntu-latest + release: false cc: clang cxx: clang++ - os: windows-2019 + release: true + cc: msvc + - os: windows-latest + release: false cc: msvc fail-fast: false @@ -121,7 +127,7 @@ jobs: ambuild - name: Upload artifact - if: github.event_name == 'push' && (startsWith(matrix.os, 'ubuntu-18.04') || startsWith(matrix.os, 'windows-2019')) + if: github.event_name == 'push' && matrix.release uses: actions/upload-artifact@v1 with: name: cbasenpc_${{ runner.os }} diff --git a/AMBuildScript b/AMBuildScript index 7ff2d1d..78638ed 100644 --- a/AMBuildScript +++ b/AMBuildScript @@ -169,11 +169,7 @@ class ExtensionConfig(object): if builder.options.sm_path: self.sm_root = builder.options.sm_path else: - self.sm_root = ResolveEnvPath('SOURCEMOD18', 'sourcemod-1.8') - if not self.sm_root: - self.sm_root = ResolveEnvPath('SOURCEMOD', 'sourcemod') - if not self.sm_root: - self.sm_root = ResolveEnvPath('SOURCEMOD_DEV', 'sourcemod-central') + self.sm_root = ResolveEnvPath('SOURCEMOD', 'sourcemod') if not self.sm_root or not os.path.isdir(self.sm_root): raise Exception('Could not find a source copy of SourceMod') @@ -182,11 +178,7 @@ class ExtensionConfig(object): if builder.options.mms_path: self.mms_root = builder.options.mms_path else: - self.mms_root = ResolveEnvPath('MMSOURCE110', 'mmsource-1.10') - if not self.mms_root: - self.mms_root = ResolveEnvPath('MMSOURCE', 'metamod-source') - if not self.mms_root: - self.mms_root = ResolveEnvPath('MMSOURCE_DEV', 'mmsource-central') + self.mms_root = ResolveEnvPath('MMSOURCE', 'metamod-source') if not self.mms_root or not os.path.isdir(self.mms_root): raise Exception('Could not find a source copy of Metamod:Source') @@ -256,6 +248,7 @@ class ExtensionConfig(object): cxx.cflags += [ '-pipe', '-fno-strict-aliasing', + #'-Werror', '-Wall', '-Wno-unused', '-Wno-switch', diff --git a/extension/AMBuilder b/extension/AMBuilder index 3c3d0b8..6249384 100644 --- a/extension/AMBuilder +++ b/extension/AMBuilder @@ -42,7 +42,7 @@ project.sources = [ 'sourcesdk/basedoor.cpp', 'sourcesdk/basetoggle.cpp', 'sourcesdk/funcbrush.cpp', - os.path.join(Extension.sm_root, 'public', 'smsdk_ext.cpp') + 'smsdk_ext.cpp' ] for sdk_name in Extension.sdks: diff --git a/extension/extension.cpp b/extension/extension.cpp index 4961dad..c9ed8b5 100644 --- a/extension/extension.cpp +++ b/extension/extension.cpp @@ -25,6 +25,7 @@ IServerTools* servertools = nullptr; IMDLCache* mdlcache = nullptr; CSharedEdictChangeInfo* g_pSharedChangeInfo = nullptr; IStaticPropMgrServer* staticpropmgr = nullptr; +ConVar* sourcemod_version = nullptr; IBaseNPC_Tools* g_pBaseNPCTools = new BaseNPC_Tools_API; DEFINEHANDLEOBJ(SurroundingAreasCollector, CUtlVector< CNavArea* >); @@ -119,6 +120,8 @@ bool CBaseNPCExt::SDK_OnMetamodLoad(ISmmAPI *ismm, char *error, size_t maxlen, b ConVar_Register(0, this); + sourcemod_version = g_pCVar->FindVar("sourcemod_version"); + g_cvDeveloper = g_pCVar->FindVar("developer"); NextBotSpeedLookAheadRange = g_pCVar->FindVar("nb_speed_look_ahead_range"); diff --git a/extension/helpers.cpp b/extension/helpers.cpp index 4f620bb..fdffbf9 100644 --- a/extension/helpers.cpp +++ b/extension/helpers.cpp @@ -78,7 +78,6 @@ void VectorToPawnVector(cell_t* angAddr, const QAngle* angle) angAddr[2] = sp_ftoc(angle->z); } -#if SOURCEPAWN_API_VERSION >= 0x0211 void MatrixToPawnMatrix(IPluginContext* context, cell_t* matAddr, const matrix3x4_t& mat) { for ( int r = 0; r < 3; r++ ) @@ -120,34 +119,6 @@ void PawnMatrixToMatrix(IPluginContext* context, cell_t* matAddr, matrix3x4_t& m } } } -#else -// https://github.com/alliedmodders/sourcemod/blob/b3672916dee4bc6ad4368e31bc6f9b2779b36d79/core/logic/smn_sorting.cpp#L43 -void MatrixToPawnMatrix(IPluginContext* context, cell_t* matAddr, const matrix3x4_t& mat) -{ - for ( int r = 0; r < 3; r++ ) - { - cell_t* row = (cell_t *)( (uint8_t *)( &matAddr[r] ) + matAddr[r] ); - - for ( int c = 0; c < 4; c++ ) - { - row[c] = sp_ftoc( mat[r][c] ); - } - } -} - -void PawnMatrixToMatrix(IPluginContext* context, cell_t* matAddr, matrix3x4_t& mat) -{ - for ( int r = 0; r < 3; r++ ) - { - cell_t* row = (cell_t *)( (uint8_t *)( &matAddr[r] ) + matAddr[r] ); - - for ( int c = 0; c < 4; c++ ) - { - mat[r][c] = sp_ctof( row[c] ); - } - } -} -#endif const char *HandleErrorToString(HandleError err) { diff --git a/extension/idatamapcontainer.cpp b/extension/idatamapcontainer.cpp index 8c603b9..a277b5a 100644 --- a/extension/idatamapcontainer.cpp +++ b/extension/idatamapcontainer.cpp @@ -9,6 +9,8 @@ #include #include +extern ConVar* sourcemod_version; + IDataMapContainer::IDataMapContainer() { m_pDataMap = nullptr; @@ -796,9 +798,30 @@ void IEntityDataMapContainer::DestroyDataDesc() } // https://github.com/alliedmodders/sourcemod/blob/38eecd5ece26b2469560db1822511a7e2685286e/core/HalfLife2.h#L263 -struct CHalfLife2Hack +struct CHalfLife2 { - struct DataMapCachePolicy + struct DataMapCacheInfo12 + { + static inline bool matches(const char *name, const DataMapCacheInfo12 &info) + { + return strcmp(name, info.name.c_str()) == 0; + } + static inline uint32_t hash(const detail::CharsAndLength &key) + { + return key.hash(); + } + + DataMapCacheInfo12() + : name(), info{nullptr, 0} + { + } + + std::string name; + sm_datatable_info_t info; + }; + typedef NameHashSet DataMapCache12; + + struct DataMapCachePolicy11 { static inline bool matches(const char *name, const sm_datatable_info_t &info) { @@ -809,35 +832,61 @@ struct CHalfLife2Hack return key.hash(); } }; + typedef NameHashSet DataMapCache11; - typedef NameHashSet DataMapCache; - typedef ke::HashMap > DataTableMap; + typedef ke::HashMap > DataTableMap; + typedef ke::HashMap > DataTableMap11; + typedef ke::HashMap > DataTableMap12; void** vptr; NameHashSet m_Classes; DataTableMap m_Maps; - int m_MsgTextMsg; - int m_HinTextMsg; - int m_SayTextMsg; - int m_VGUIMenu; }; void IEntityDataMapContainer::DestroyDataDescMap() { if (!m_pDataMap) + { return; + } // HACK: Force gamehelpers (CHalfLife2 *) to delete the cache of our datamap if it exists. - CHalfLife2Hack* pHL2 = reinterpret_cast(gamehelpers); - auto result = pHL2->m_Maps.find( m_pDataMap ); - if (result.found()) + CHalfLife2* pHL2 = reinterpret_cast(gamehelpers); + + const char* value = sourcemod_version->GetString(); + if (strncmp("1.12.0.", value, 7) == 0) { - CHalfLife2Hack::DataMapCache* cache = result->value; - if (cache) delete cache; + int rev = std::atoi(&value[7]); + if (rev >= 6998) + { + auto maps12 = (CHalfLife2::DataTableMap12*)(&(pHL2->m_Maps)); + auto result = maps12->find( m_pDataMap ); + if (result.found()) + { + auto cache = result->value; + if (cache) + { + delete cache; + } - pHL2->m_Maps.remove( result ); + maps12->remove( result ); + } + IDataMapContainer::DestroyDataDescMap(); + return; + } } + auto maps11 = (CHalfLife2::DataTableMap11*)(&(pHL2->m_Maps)); + auto result = maps11->find( m_pDataMap ); + if (result.found()) + { + auto cache = result->value; + if (cache) + { + delete cache; + } + maps11->remove( result ); + } IDataMapContainer::DestroyDataDescMap(); } diff --git a/extension/smsdk_ext.cpp b/extension/smsdk_ext.cpp new file mode 100644 index 0000000..496ec6a --- /dev/null +++ b/extension/smsdk_ext.cpp @@ -0,0 +1,475 @@ +/** + * vim: set ts=4 sw=4 tw=99 noet: + * ============================================================================= + * SourceMod Base Extension Code + * Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved. + * ============================================================================= + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License, version 3.0, as published by the + * Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + * + * As a special exception, AlliedModders LLC gives you permission to link the + * code of this program (as well as its derivative works) to "Half-Life 2," the + * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software + * by the Valve Corporation. You must obey the GNU General Public License in + * all respects for all other code used. Additionally, AlliedModders LLC grants + * this exception to all derivative works. AlliedModders LLC defines further + * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), + * or . + * + * Version: $Id$ + */ + +#include +#include +#include "smsdk_ext.h" +#include "am-string.h" + +/** + * @file smsdk_ext.cpp + * @brief Contains wrappers for making Extensions easier to write. + */ + +IExtension *myself = NULL; /**< Ourself */ +IShareSys *g_pShareSys = NULL; /**< Share system */ +IShareSys *sharesys = NULL; /**< Share system */ +ISourceMod *g_pSM = NULL; /**< SourceMod helpers */ +ISourceMod *smutils = NULL; /**< SourceMod helpers */ + +#if defined SMEXT_ENABLE_FORWARDSYS +IForwardManager *g_pForwards = NULL; /**< Forward system */ +IForwardManager *forwards = NULL; /**< Forward system */ +#endif +#if defined SMEXT_ENABLE_HANDLESYS +IHandleSys *g_pHandleSys = NULL; /**< Handle system */ +IHandleSys *handlesys = NULL; /**< Handle system */ +#endif +#if defined SMEXT_ENABLE_PLAYERHELPERS +IPlayerManager *playerhelpers = NULL; /**< Player helpers */ +#endif //SMEXT_ENABLE_PLAYERHELPERS +#if defined SMEXT_ENABLE_DBMANAGER +IDBManager *dbi = NULL; /**< DB Manager */ +#endif //SMEXT_ENABLE_DBMANAGER +#if defined SMEXT_ENABLE_GAMECONF +IGameConfigManager *gameconfs = NULL; /**< Game config manager */ +#endif //SMEXT_ENABLE_DBMANAGER +#if defined SMEXT_ENABLE_MEMUTILS +IMemoryUtils *memutils = NULL; +#endif //SMEXT_ENABLE_DBMANAGER +#if defined SMEXT_ENABLE_GAMEHELPERS +IGameHelpers *gamehelpers = NULL; +#endif +#if defined SMEXT_ENABLE_TIMERSYS +ITimerSystem *timersys = NULL; +#endif +#if defined SMEXT_ENABLE_ADTFACTORY +IADTFactory *adtfactory = NULL; +#endif +#if defined SMEXT_ENABLE_THREADER +IThreader *threader = NULL; +#endif +#if defined SMEXT_ENABLE_LIBSYS +ILibrarySys *libsys = NULL; +#endif +#if defined SMEXT_ENABLE_PLUGINSYS +SourceMod::IPluginManager *plsys; +#endif +#if defined SMEXT_ENABLE_MENUS +IMenuManager *menus = NULL; +#endif +#if defined SMEXT_ENABLE_ADMINSYS +IAdminSystem *adminsys = NULL; +#endif +#if defined SMEXT_ENABLE_TEXTPARSERS +ITextParsers *textparsers = NULL; +#endif +#if defined SMEXT_ENABLE_USERMSGS +IUserMessages *usermsgs = NULL; +#endif +#if defined SMEXT_ENABLE_TRANSLATOR +ITranslator *translator = NULL; +#endif +#if defined SMEXT_ENABLE_ROOTCONSOLEMENU +IRootConsole *rootconsole = NULL; +#endif + +/** Exports the main interface */ +PLATFORM_EXTERN_C IExtensionInterface *GetSMExtAPI() +{ + return g_pExtensionIface; +} + +SDKExtension::SDKExtension() +{ +#if defined SMEXT_CONF_METAMOD + m_SourceMMLoaded = false; + m_WeAreUnloaded = false; + m_WeGotPauseChange = false; +#endif +} + +bool SDKExtension::OnExtensionLoad(IExtension *me, IShareSys *sys, char *error, size_t maxlength, bool late) +{ + g_pShareSys = sharesys = sys; + myself = me; + +#if defined SMEXT_CONF_METAMOD + m_WeAreUnloaded = true; + + if (!m_SourceMMLoaded) + { + if (error) + { + ke::SafeStrcpy(error, maxlength, "Metamod attach failed"); + } + return false; + } +#endif + SM_GET_IFACE(SOURCEMOD, g_pSM); + smutils = g_pSM; +#if defined SMEXT_ENABLE_HANDLESYS + SM_GET_IFACE(HANDLESYSTEM, g_pHandleSys); + handlesys = g_pHandleSys; +#endif +#if defined SMEXT_ENABLE_FORWARDSYS + SM_GET_IFACE(FORWARDMANAGER, g_pForwards); + forwards = g_pForwards; +#endif +#if defined SMEXT_ENABLE_PLAYERHELPERS + SM_GET_IFACE(PLAYERMANAGER, playerhelpers); +#endif +#if defined SMEXT_ENABLE_DBMANAGER + SM_GET_IFACE(DBI, dbi); +#endif +#if defined SMEXT_ENABLE_GAMECONF + SM_GET_IFACE(GAMECONFIG, gameconfs); +#endif +#if defined SMEXT_ENABLE_MEMUTILS + SM_GET_IFACE(MEMORYUTILS, memutils); +#endif +#if defined SMEXT_ENABLE_GAMEHELPERS + SM_GET_IFACE(GAMEHELPERS, gamehelpers); +#endif +#if defined SMEXT_ENABLE_TIMERSYS + SM_GET_IFACE(TIMERSYS, timersys); +#endif +#if defined SMEXT_ENABLE_ADTFACTORY + SM_GET_IFACE(ADTFACTORY, adtfactory); +#endif +#if defined SMEXT_ENABLE_THREADER + SM_GET_IFACE(THREADER, threader); +#endif +#if defined SMEXT_ENABLE_LIBSYS + SM_GET_IFACE(LIBRARYSYS, libsys); +#endif +#if defined SMEXT_ENABLE_PLUGINSYS + SM_GET_IFACE(PLUGINSYSTEM, plsys); +#endif +#if defined SMEXT_ENABLE_MENUS + SM_GET_IFACE(MENUMANAGER, menus); +#endif +#if defined SMEXT_ENABLE_ADMINSYS + SM_GET_IFACE(ADMINSYS, adminsys); +#endif +#if defined SMEXT_ENABLE_TEXTPARSERS + SM_GET_IFACE(TEXTPARSERS, textparsers); +#endif +#if defined SMEXT_ENABLE_USERMSGS + SM_GET_IFACE(USERMSGS, usermsgs); +#endif +#if defined SMEXT_ENABLE_TRANSLATOR + SM_GET_IFACE(TRANSLATOR, translator); +#endif +#if defined SMEXT_ENABLE_ROOTCONSOLEMENU + SM_GET_IFACE(ROOTCONSOLE, rootconsole); +#endif + + if (SDK_OnLoad(error, maxlength, late)) + { +#if defined SMEXT_CONF_METAMOD + m_WeAreUnloaded = true; +#endif + return true; + } + + return false; +} + +bool SDKExtension::IsMetamodExtension() +{ +#if defined SMEXT_CONF_METAMOD + return true; +#else + return false; +#endif +} + +void SDKExtension::OnExtensionPauseChange(bool state) +{ +#if defined SMEXT_CONF_METAMOD + m_WeGotPauseChange = true; +#endif + SDK_OnPauseChange(state); +} + +void SDKExtension::OnExtensionsAllLoaded() +{ + SDK_OnAllLoaded(); +} + +void SDKExtension::OnExtensionUnload() +{ +#if defined SMEXT_CONF_METAMOD + m_WeAreUnloaded = true; +#endif + SDK_OnUnload(); +} + +void SDKExtension::OnDependenciesDropped() +{ + SDK_OnDependenciesDropped(); +} + +const char *SDKExtension::GetExtensionAuthor() +{ + return SMEXT_CONF_AUTHOR; +} + +const char *SDKExtension::GetExtensionDateString() +{ + return SMEXT_CONF_DATESTRING; +} + +const char *SDKExtension::GetExtensionDescription() +{ + return SMEXT_CONF_DESCRIPTION; +} + +const char *SDKExtension::GetExtensionVerString() +{ + return SMEXT_CONF_VERSION; +} + +const char *SDKExtension::GetExtensionName() +{ + return SMEXT_CONF_NAME; +} + +const char *SDKExtension::GetExtensionTag() +{ + return SMEXT_CONF_LOGTAG; +} + +const char *SDKExtension::GetExtensionURL() +{ + return SMEXT_CONF_URL; +} + +bool SDKExtension::SDK_OnLoad(char *error, size_t maxlength, bool late) +{ + return true; +} + +void SDKExtension::SDK_OnUnload() +{ +} + +void SDKExtension::SDK_OnPauseChange(bool paused) +{ +} + +void SDKExtension::SDK_OnAllLoaded() +{ +} + +void SDKExtension::SDK_OnDependenciesDropped() +{ +} + +#if defined SMEXT_CONF_METAMOD + +PluginId g_PLID = 0; /**< Metamod plugin ID */ +ISmmPlugin *g_PLAPI = NULL; /**< Metamod plugin API */ +SourceHook::ISourceHook *g_SHPtr = NULL; /**< SourceHook pointer */ +ISmmAPI *g_SMAPI = NULL; /**< SourceMM API pointer */ + +#ifndef META_NO_HL2SDK +IVEngineServer *engine = NULL; /**< IVEngineServer pointer */ +IServerGameDLL *gamedll = NULL; /**< IServerGameDLL pointer */ +#endif + +/** Exposes the extension to Metamod */ +SMM_API void *PL_EXPOSURE(const char *name, int *code) +{ +#if defined METAMOD_PLAPI_VERSION + if (name && !strcmp(name, METAMOD_PLAPI_NAME)) +#else + if (name && !strcmp(name, PLAPI_NAME)) +#endif + { + if (code) + { + *code = META_IFACE_OK; + } + return static_cast(g_pExtensionIface); + } + + if (code) + { + *code = META_IFACE_FAILED; + } + + return NULL; +} + +bool SDKExtension::Load(PluginId id, ISmmAPI *ismm, char *error, size_t maxlen, bool late) +{ + PLUGIN_SAVEVARS(); + +#ifndef META_NO_HL2SDK +#if !defined METAMOD_PLAPI_VERSION + GET_V_IFACE_ANY(serverFactory, gamedll, IServerGameDLL, INTERFACEVERSION_SERVERGAMEDLL); + GET_V_IFACE_CURRENT(engineFactory, engine, IVEngineServer, INTERFACEVERSION_VENGINESERVER); +#else + GET_V_IFACE_ANY(GetServerFactory, gamedll, IServerGameDLL, INTERFACEVERSION_SERVERGAMEDLL); +#if SOURCE_ENGINE == SE_CSS || SOURCE_ENGINE == SE_DODS || SOURCE_ENGINE == SE_HL2DM || SOURCE_ENGINE == SE_SDK2013 + // Shim to avoid hooking shims + engine = (IVEngineServer *) ismm->GetEngineFactory()("VEngineServer023", nullptr); + if (!engine) + { + engine = (IVEngineServer *) ismm->GetEngineFactory()("VEngineServer022", nullptr); + if (!engine) + { + engine = (IVEngineServer *) ismm->GetEngineFactory()("VEngineServer021", nullptr); + if (!engine) + { + if (error && maxlen) + { + ismm->Format(error, maxlen, "Could not find interface: VEngineServer023 or VEngineServer022"); + } + return false; + } + } + } +#else + GET_V_IFACE_CURRENT(GetEngineFactory, engine, IVEngineServer, INTERFACEVERSION_VENGINESERVER); +#endif // TF2 / CSS / DODS / HL2DM / SDK2013 +#endif // !METAMOD_PLAPI_VERSION +#endif //META_NO_HL2SDK + + m_SourceMMLoaded = true; + + return SDK_OnMetamodLoad(ismm, error, maxlen, late); +} + +bool SDKExtension::Unload(char *error, size_t maxlen) +{ + if (!m_WeAreUnloaded) + { + if (error) + { + ke::SafeStrcpy(error, maxlen, "This extension must be unloaded by SourceMod."); + } + return false; + } + + return SDK_OnMetamodUnload(error, maxlen); +} + +bool SDKExtension::Pause(char *error, size_t maxlen) +{ + if (!m_WeGotPauseChange) + { + if (error) + { + ke::SafeStrcpy(error, maxlen, "This extension must be paused by SourceMod."); + } + return false; + } + + m_WeGotPauseChange = false; + + return SDK_OnMetamodPauseChange(true, error, maxlen); +} + +bool SDKExtension::Unpause(char *error, size_t maxlen) +{ + if (!m_WeGotPauseChange) + { + if (error) + { + ke::SafeStrcpy(error, maxlen, "This extension must be unpaused by SourceMod."); + } + return false; + } + + m_WeGotPauseChange = false; + + return SDK_OnMetamodPauseChange(false, error, maxlen); +} + +const char *SDKExtension::GetAuthor() +{ + return GetExtensionAuthor(); +} + +const char *SDKExtension::GetDate() +{ + return GetExtensionDateString(); +} + +const char *SDKExtension::GetDescription() +{ + return GetExtensionDescription(); +} + +const char *SDKExtension::GetLicense() +{ + return SMEXT_CONF_LICENSE; +} + +const char *SDKExtension::GetLogTag() +{ + return GetExtensionTag(); +} + +const char *SDKExtension::GetName() +{ + return GetExtensionName(); +} + +const char *SDKExtension::GetURL() +{ + return GetExtensionURL(); +} + +const char *SDKExtension::GetVersion() +{ + return GetExtensionVerString(); +} + +bool SDKExtension::SDK_OnMetamodLoad(ISmmAPI *ismm, char *error, size_t maxlength, bool late) +{ + return true; +} + +bool SDKExtension::SDK_OnMetamodUnload(char *error, size_t maxlength) +{ + return true; +} + +bool SDKExtension::SDK_OnMetamodPauseChange(bool paused, char *error, size_t maxlength) +{ + return true; +} + +#endif \ No newline at end of file diff --git a/product.version b/product.version index 7b378be..ff2fd4f 100644 --- a/product.version +++ b/product.version @@ -1 +1 @@ -1.8.4 \ No newline at end of file +1.8.5 \ No newline at end of file