diff --git a/dlls/CBaseEntity.cpp b/dlls/CBaseEntity.cpp index afb85b26..48cf21d9 100644 --- a/dlls/CBaseEntity.cpp +++ b/dlls/CBaseEntity.cpp @@ -325,7 +325,7 @@ CBaseEntity* CBaseEntity::Create(const char* szName, const Vector& vecOrigin, co edict_t* pent; CBaseEntity* pEntity; - pent = CREATE_NAMED_ENTITY(MAKE_STRING(szName)); + pent = CREATE_NAMED_ENTITY(ALLOC_STRING(szName)); // not using MAKE_STRING in case an unloaded plugin called this func if (FNullEnt(pent)) { ALERT(at_console, UTIL_VarArgs("NULL Ent '%s' in Create!\n", szName)); diff --git a/dlls/CBasePlayer.cpp b/dlls/CBasePlayer.cpp index 253e3fbe..920524ab 100644 --- a/dlls/CBasePlayer.cpp +++ b/dlls/CBasePlayer.cpp @@ -1687,7 +1687,7 @@ void CBasePlayer::LeaveObserver() // void CBasePlayer::PlayerUse ( void ) { - CALL_HOOKS_VOID(&HLCOOP_PLUGIN_HOOKS::pfnPlayerUse, this); + CALL_HOOKS_VOID(pfnPlayerUse, this); if ( IsObserver() ) return; @@ -2225,7 +2225,7 @@ void CBasePlayer::UpdateStatusBar() void CBasePlayer::PreThink(void) { - CALL_HOOKS_VOID(&HLCOOP_PLUGIN_HOOKS::pfnPlayerPreThink, this); + CALL_HOOKS_VOID(pfnPlayerPreThink, this); int buttonsChanged = (m_afButtonLast ^ pev->button); // These buttons have changed this frame @@ -2997,7 +2997,7 @@ void CBasePlayer :: UpdatePlayerSound ( void ) void CBasePlayer::PostThink() { - CALL_HOOKS_VOID(&HLCOOP_PLUGIN_HOOKS::pfnPlayerPostThink, this); + CALL_HOOKS_VOID(pfnPlayerPostThink, this); if ( g_fGameOver ) goto pt_end; // intermission or finale diff --git a/dlls/CWorld.cpp b/dlls/CWorld.cpp index 89fc3f68..778d02d5 100644 --- a/dlls/CWorld.cpp +++ b/dlls/CWorld.cpp @@ -345,7 +345,7 @@ void CWorld::Precache(void) CVAR_SET_FLOAT("mp_defaultteam", 0); } - CALL_HOOKS_VOID(&HLCOOP_PLUGIN_HOOKS::pfnMapInit); + CALL_HOOKS_VOID(pfnMapInit); } diff --git a/dlls/PluginHooks.h b/dlls/PluginHooks.h index 41731b1d..5280c973 100644 --- a/dlls/PluginHooks.h +++ b/dlls/PluginHooks.h @@ -21,6 +21,9 @@ struct HLCOOP_PLUGIN_HOOKS { // called after map entities are spawned HOOK_RETURN_DATA (*pfnMapActivate)(); + // called when the server is about to load a new map + HOOK_RETURN_DATA (*pfnMapChange)(); + // called before the player PreThink function HOOK_RETURN_DATA (*pfnPlayerPreThink)(CBasePlayer* pPlayer); @@ -36,13 +39,25 @@ struct HLCOOP_PLUGIN_HOOKS { // called when a client connects to the server. Return 0 to reject the connection with the given reason. HOOK_RETURN_DATA (*pfnClientConnect)(edict_t* pEntity, const char* pszName, const char* pszAddress, char szRejectReason[128]); + // called when a client disconnects from the server. + HOOK_RETURN_DATA(*pfnClientDisconnect)(edict_t* pEntity); + // called when a player is fully connected to the server and is about to spawn HOOK_RETURN_DATA (*pfnClientPutInServer)(CBasePlayer* pPlayer); + + // called when a player changes model, name, colors, etc. + HOOK_RETURN_DATA (*pfnClientUserInfoChanged)(edict_t* pPlayer, char* infobuffer); }; +EXPORT void RegisterPlugin(void* plugin, HLCOOP_PLUGIN_HOOKS* hooks, const char* name); + +// must call this instead of registering cvars directly or else the game crashes when the plugin unloads +// and any cvar is used EXPORT cvar_t* RegisterPluginCVar(void* plugin, char* name, char* strDefaultValue, int intDefaultValue, int flags); -EXPORT void RegisterPlugin(void* plugin, HLCOOP_PLUGIN_HOOKS* hooks, const char* name); +// must call this instead of registering commands directly or else the game crashes when the plugin unloads +// and the registered command is used +EXPORT void RegisterPluginCommand(void* plugin, char* cmd, void (*function)(void)); // boilerplate for PluginInit functions // must be inline so that plugins don't reference the game definition of HLCOOP_API_VERSION diff --git a/dlls/PluginManager.cpp b/dlls/PluginManager.cpp index 8007a5ff..a746dfaf 100644 --- a/dlls/PluginManager.cpp +++ b/dlls/PluginManager.cpp @@ -8,15 +8,25 @@ PluginManager g_pluginManager; #define MAX_PLUGIN_CVARS 256 +#define MAX_PLUGIN_COMMANDS 256 struct ExternalCvar { int pluginId; cvar_t cvar; }; +struct ExternalCommand { + int pluginId; + char name[64]; + void (*function)(void); +}; + ExternalCvar g_plugin_cvars[MAX_PLUGIN_CVARS]; int g_plugin_cvar_count = 0; +ExternalCommand g_plugin_commands[MAX_PLUGIN_COMMANDS]; +int g_plugin_command_count = 0; + int g_plugin_id = 0; #ifdef _WIN32 @@ -193,8 +203,11 @@ void PluginManager::UpdateServerPlugins(bool forceUpdate) { { lineNum++; - line = trimSpaces(line); - if (line.empty() || line[0] == '/' || line[0] == '#') { + int endPos = line.find_first_of("#/"); + if (endPos != -1) + line = trimSpaces(line.substr(0, endPos)); + + if (line.empty()) { continue; } @@ -302,7 +315,7 @@ void PluginManager::ReloadPlugins() { void PluginManager::ListPlugins(edict_t* plr) { std::vector lines; - bool isAdmin = !plr; + bool isAdmin = !plr || AdminLevel(plr) > ADMIN_NO; lines.push_back(UTIL_VarArgs("\n %-20s %-8s %-44s\n", "Name", "Type", isAdmin ? "File path" : "")); lines.push_back("--------------------------------------------------------------------------------\n"); @@ -311,7 +324,7 @@ void PluginManager::ListPlugins(edict_t* plr) { const Plugin& plugin = plugins[i]; const char* type = plugin.isMapPlugin ? "MAP" : "SERVER"; - + if (isAdmin) { lines.push_back(UTIL_VarArgs("%2d) %-20s %-8s %-44s\n", i + 1, plugin.name, type, plugin.fpath.c_str())); } @@ -320,6 +333,12 @@ void PluginManager::ListPlugins(edict_t* plr) { lines.push_back(UTIL_VarArgs("%2d) %-20s %-8s\n", i + 1, plugin.name, type)); } } + + if (isAdmin) { + lines.push_back(UTIL_VarArgs("\n Registered %d cvars, %d commands\n", + g_plugin_cvar_count, g_plugin_command_count)); + } + lines.push_back("--------------------------------------------------------------------------------\n"); for (std::string& line : lines) { @@ -332,6 +351,16 @@ void PluginManager::ListPlugins(edict_t* plr) { } } +Plugin* PluginManager::FindPlugin(int id) { + for (Plugin& plugin : plugins) { + if (plugin.id == id) { + return &plugin; + } + } + + return NULL; +} + ENTITYINIT PluginManager::GetCustomEntityInitFunc(const char* pname) { for (const Plugin& plugin : plugins) { ENTITYINIT initFunc = (ENTITYINIT)GetProcAddress((HMODULE)plugin.h_module, pname); @@ -358,7 +387,7 @@ cvar_t* RegisterPluginCVar(void* pluginptr, char* name, char* strDefaultValue, i cvar_t* existing = CVAR_GET_POINTER(name); if (existing) { - g_engfuncs.pfnServerPrint(UTIL_VarArgs("Plugin cvar already registered: %s\n", name)); + //g_engfuncs.pfnServerPrint(UTIL_VarArgs("Plugin cvar already registered: %s\n", name)); // update the owner of the cvar for (int i = 0; i < MAX_PLUGIN_CVARS; i++) { @@ -386,6 +415,64 @@ cvar_t* RegisterPluginCVar(void* pluginptr, char* name, char* strDefaultValue, i return CVAR_GET_POINTER(name); } +void ExternalPluginCommand() { + const char* cmd = CMD_ARGV(0); + + ExternalCommand* ecmd = NULL; + + for (int i = 0; i < g_plugin_command_count; i++) { + if (!strcmp(g_plugin_commands[i].name, cmd)) { + ecmd = &g_plugin_commands[i]; + break; + } + } + + if (!ecmd) { + // should never happen + g_engfuncs.pfnServerPrint(UTIL_VarArgs("Unrecognized external plugin command: %s\n", cmd)); + return; + } + + Plugin* plugin = g_pluginManager.FindPlugin(ecmd->pluginId); + + if (!plugin) { + g_engfuncs.pfnServerPrint(UTIL_VarArgs("Command from unloaded plugin can't be called: %s\n", cmd)); + return; + } + + ecmd->function(); +} + +void RegisterPluginCommand(void* pluginptr, char* cmd, void (*function)(void)) { + if (!pluginptr) { + return; + } + + Plugin* plugin = (Plugin*)pluginptr; + + if (g_plugin_command_count >= MAX_PLUGIN_COMMANDS) { + ALERT(at_error, "Plugin command limit exceeded! Failed to register: %s\n", cmd); + return; + } + + for (int i = 0; i < g_plugin_command_count; i++) { + if (!strcmp(g_plugin_commands[i].name, cmd)) { + //g_engfuncs.pfnServerPrint(UTIL_VarArgs("Plugin command already registered: %s\n", cmd)); + g_plugin_commands[i].pluginId = plugin->id; + g_plugin_commands[i].function = function; + return; + } + } + + ExternalCommand& ecmd = g_plugin_commands[g_plugin_command_count]; + ecmd.pluginId = plugin->id; + ecmd.function = function; + strcpy_safe(ecmd.name, cmd, sizeof(ecmd.name)); + g_plugin_command_count++; + + g_engfuncs.pfnAddServerCommand(ecmd.name, ExternalPluginCommand); +} + void RegisterPlugin(void* pluginptr, HLCOOP_PLUGIN_HOOKS* hooks, const char* name) { if (!pluginptr) { return; diff --git a/dlls/PluginManager.h b/dlls/PluginManager.h index c745a0cb..e95b3922 100644 --- a/dlls/PluginManager.h +++ b/dlls/PluginManager.h @@ -17,10 +17,10 @@ struct Plugin { typedef void(*ENTITYINIT)(struct entvars_s*); #define CALL_HOOKS_VOID(...) \ - if (g_pluginManager.CallHooks(__VA_ARGS__).code & HOOKBIT_OVERRIDE) { return; } + if (g_pluginManager.CallHooks(&HLCOOP_PLUGIN_HOOKS::__VA_ARGS__).code & HOOKBIT_OVERRIDE) { return; } #define CALL_HOOKS(type, ...) { \ - HOOK_RETURN_DATA ret = g_pluginManager.CallHooks(__VA_ARGS__); \ + HOOK_RETURN_DATA ret = g_pluginManager.CallHooks(&HLCOOP_PLUGIN_HOOKS::__VA_ARGS__); \ if (ret.code & HOOKBIT_OVERRIDE) { \ return (type)ret.data; \ } \ @@ -51,6 +51,8 @@ class PluginManager { // print loaded server and map plugins to console or client void ListPlugins(edict_t* plr); + Plugin* FindPlugin(int id); + template HOOK_RETURN_DATA CallHooks(Func hookFunction, Args&&... args) { HOOK_RETURN_DATA totalRet = {0, 0}; diff --git a/dlls/Scheduler.cpp b/dlls/Scheduler.cpp index 4d1199ae..2a4894a6 100644 --- a/dlls/Scheduler.cpp +++ b/dlls/Scheduler.cpp @@ -51,7 +51,6 @@ void Scheduler::RemoveTimers(const char* owner) { for (int i = 0; i < (int)functions.size(); i++) { if (strcmp(functions[i].owner, owner)) { newFuncs.push_back(functions[i]); - return; } } diff --git a/dlls/TextMenu.h b/dlls/TextMenu.h index 6da1080b..db5a18a1 100644 --- a/dlls/TextMenu.h +++ b/dlls/TextMenu.h @@ -29,24 +29,24 @@ class TextMenu { // use this to create menus for each player. // When creating a menu for all players, pass NULL for player. - static TextMenu* init(edict_t* player, TextMenuCallback callback); + EXPORT static TextMenu* init(edict_t* player, TextMenuCallback callback); - static TextMenu* init(edict_t* player, EntityTextMenuCallback callback, CBaseEntity* ent); + EXPORT static TextMenu* init(edict_t* player, EntityTextMenuCallback callback, CBaseEntity* ent); - void SetTitle(std::string title); + EXPORT void SetTitle(std::string title); - void AddItem(std::string displayText, std::string optionData); + EXPORT void AddItem(std::string displayText, std::string optionData); // set player to NULL to send to all players. // This should be the same target as was used with initMenuForPlayer // paging not supported yet - void Open(uint8_t duration, uint8_t page, edict_t* player); + EXPORT void Open(uint8_t duration, uint8_t page, edict_t* player); // don't call directly. This is triggered by global hook functions - void handleMenuMessage(int msg_dest, edict_t* ed); + EXPORT void handleMenuMessage(int msg_dest, edict_t* ed); // don't call directly. This is triggered by global hook functions - void handleMenuselectCmd(edict_t* pEntity, int selection); + EXPORT void handleMenuselectCmd(edict_t* pEntity, int selection); private: void initAnon(TextMenuCallback callback); diff --git a/dlls/cbase.cpp b/dlls/cbase.cpp index 4ccbed64..056dd8f3 100644 --- a/dlls/cbase.cpp +++ b/dlls/cbase.cpp @@ -456,6 +456,9 @@ void SaveReadFields( SAVERESTOREDATA *pSaveData, const char *pname, void *pBaseD restoreHelper.ReadFields( pname, pBaseData, pFields, fieldCount ); } +EHANDLE::EHANDLE(edict_t* pent) { + Set(pent); +} edict_t * EHANDLE::GetEdict( void ) { diff --git a/dlls/cbase.h b/dlls/cbase.h index 7fab5615..f7438fc9 100644 --- a/dlls/cbase.h +++ b/dlls/cbase.h @@ -121,6 +121,8 @@ class EXPORT EHANDLE edict_t *m_pent; int m_serialnumber; public: + EHANDLE() : m_pent(0), m_serialnumber(0) {} + EHANDLE(edict_t* pent); edict_t *GetEdict( void ); CBaseEntity *GetEntity( void ); edict_t *Set( edict_t *pent ); diff --git a/dlls/client.cpp b/dlls/client.cpp index 9664aae4..9469fa49 100644 --- a/dlls/client.cpp +++ b/dlls/client.cpp @@ -91,7 +91,7 @@ called when a player connects to a server */ BOOL ClientConnect( edict_t *pEntity, const char *pszName, const char *pszAddress, char szRejectReason[ 128 ] ) { - CALL_HOOKS(BOOL, &HLCOOP_PLUGIN_HOOKS::pfnClientConnect, pEntity, pszName, pszAddress, szRejectReason); + CALL_HOOKS(BOOL, pfnClientConnect, pEntity, pszName, pszAddress, szRejectReason); return g_pGameRules->ClientConnected( pEntity, pszName, pszAddress, szRejectReason ); @@ -113,6 +113,8 @@ GLOBALS ASSUMED SET: g_fGameOver */ void ClientDisconnect( edict_t *pEntity ) { + CALL_HOOKS_VOID(pfnClientDisconnect, pEntity); + if (mp_debugmsg.value) { writeNetworkMessageHistory(std::string(STRING(pEntity->v.netname)) + " dropped on map " + STRING(gpGlobals->mapname)); @@ -283,7 +285,7 @@ void ClientPutInServer( edict_t *pEntity ) // Reset interpolation during first frame pPlayer->pev->effects |= EF_NOINTERP; - CALL_HOOKS_VOID(&HLCOOP_PLUGIN_HOOKS::pfnClientPutInServer, pPlayer); + CALL_HOOKS_VOID(pfnClientPutInServer, pPlayer); // Allocate a CBasePlayer for pev, and call spawn pPlayer->Spawn(); @@ -308,6 +310,8 @@ void ClientUserInfoChanged( edict_t *pEntity, char *infobuffer ) if ( !pEntity->pvPrivateData ) return; + CALL_HOOKS_VOID(pfnClientUserInfoChanged, pEntity, infobuffer); + // msg everyone if someone changes their name, and it isn't the first time (changing no name to current name) if ( pEntity->v.netname && STRING(pEntity->v.netname)[0] != 0 && !FStrEq( STRING(pEntity->v.netname), g_engfuncs.pfnInfoKeyValue( infobuffer, "name" )) ) { @@ -421,6 +425,8 @@ void ServerDeactivate( void ) // below and try keenrace instead. // SHA-1: 0c95b51652eda12e0b268631d1421634614c661f // fix physics breaking after long uptime + + CALL_HOOKS_VOID(pfnMapChange); } #include "lagcomp.h" @@ -689,7 +695,7 @@ void ServerActivate( edict_t *pEdictList, int edictCount, int clientMax ) LoadAdminList(); - CALL_HOOKS_VOID(&HLCOOP_PLUGIN_HOOKS::pfnMapActivate); + CALL_HOOKS_VOID(pfnMapActivate); } /* diff --git a/dlls/client_commands.cpp b/dlls/client_commands.cpp index 38302906..7f5aa554 100644 --- a/dlls/client_commands.cpp +++ b/dlls/client_commands.cpp @@ -384,7 +384,7 @@ void ClientCommand(edict_t* pEntity) return; } - CALL_HOOKS_VOID(&HLCOOP_PLUGIN_HOOKS::pfnClientCommand, pPlayer); + CALL_HOOKS_VOID(pfnClientCommand, pPlayer); TextMenuClientCommandHook(pEntity); diff --git a/dlls/mstream.h b/dlls/mstream.h index 74871c6f..a4f4da05 100644 --- a/dlls/mstream.h +++ b/dlls/mstream.h @@ -1,7 +1,7 @@ #pragma once #include -class mstream +class EXPORT mstream { public: diff --git a/dlls/util.cpp b/dlls/util.cpp index 753603dd..14927962 100644 --- a/dlls/util.cpp +++ b/dlls/util.cpp @@ -47,9 +47,10 @@ using namespace std::chrono; #ifndef WIN32 #include -#endif - -#ifdef WIN32 +#include +#include +#include +#else #define stat _stat #endif @@ -689,6 +690,18 @@ CBasePlayer* UTIL_PlayerByUserId(int userid) return NULL; } +CBasePlayer* UTIL_PlayerByUniqueId(const char* id) { + for (int i = 1; i <= gpGlobals->maxClients; i++) { + CBasePlayer* pPlayer = UTIL_PlayerByIndex(i); + + if (!strcmp(id, getPlayerUniqueId(pPlayer->edict()))) { + return pPlayer; + } + } + + return NULL; +} + edict_t* UTIL_ClientsInPVS(edict_t* edict, int& playerCount) { // TODO: reimplement engine func so that it only iterates 32 edicts edict_t* pvsents = UTIL_EntitiesInPVS(edict); @@ -1177,7 +1190,7 @@ void UTIL_ClientPrint( edict_t* client, int msg_dest, const char * msg) void UTIL_SayText( const char *pText, CBaseEntity *pEntity ) { - if ( !pEntity->IsNetClient() ) + if ( !pEntity || !pEntity->IsNetClient() ) return; MESSAGE_BEGIN( MSG_ONE, gmsgSayText, NULL, pEntity->edict() ); @@ -1188,8 +1201,10 @@ void UTIL_SayText( const char *pText, CBaseEntity *pEntity ) void UTIL_SayTextAll( const char *pText, CBaseEntity *pEntity ) { + int idx = pEntity ? pEntity->entindex() : 0; + MESSAGE_BEGIN( MSG_ALL, gmsgSayText, NULL ); - WRITE_BYTE( pEntity->entindex() ); + WRITE_BYTE(idx); WRITE_STRING( pText ); MESSAGE_END(); } @@ -3753,6 +3768,16 @@ uint64_t steamid_to_steamid64(const char* steamid) { return steam64id; } +std::string steamid64_to_steamid(uint64_t steam64) { + steam64 -= 76561197960265728; + + if (steam64 & 1) { + return "STEAM_0:1:" + std::to_string((steam64 - 1) / 2); + } + + return "STEAM_0:0:" + std::to_string(steam64 / 2); +} + uint64_t getPlayerCommunityId(edict_t* plr) { const char* id = getPlayerUniqueId(plr); @@ -4835,24 +4860,25 @@ void LoadAdminList(bool forceUpdate) { } // strip comments - int endPos = line.find_first_of(" \t#/\n"); - std::string steamId = trimSpaces(line.substr(0, endPos)); + int endPos = line.find_first_of("#/"); + if (endPos != -1) + line = trimSpaces(line.substr(0, endPos)); - if (steamId.length() < 1) { + if (line.length() < 1) { continue; } int adminLevel = ADMIN_YES; - if (steamId[0] == '*') { + if (line[0] == '*') { adminLevel = ADMIN_OWNER; - steamId = steamId.substr(1); + line = line.substr(1); } - g_admins[steamId] = adminLevel; + g_admins[line] = adminLevel; } - g_engfuncs.pfnServerPrint(UTIL_VarArgs("Loaded %d admin(s) from file", g_admins.size())); + g_engfuncs.pfnServerPrint(UTIL_VarArgs("Loaded %d admin(s) from file\n", g_admins.size())); } int AdminLevel(edict_t* plr) { @@ -4869,4 +4895,83 @@ int AdminLevel(edict_t* plr) { } return ADMIN_NO; +} + +void winPath(std::string& path) { + for (int i = 0, size = path.size(); i < size; i++) { + if (path[i] == '/') + path[i] = '\\'; + } +} + +std::vector getDirFiles(std::string path, std::string extension, std::string startswith, bool onlyOne) +{ + std::vector results; + +#if defined(WIN32) || defined(_WIN32) + path = path + startswith + "*." + extension; + winPath(path); + WIN32_FIND_DATA FindFileData; + HANDLE hFind; + + //println("Target file is " + path); + hFind = FindFirstFile(path.c_str(), &FindFileData); + if (hFind == INVALID_HANDLE_VALUE) + { + //println("FindFirstFile failed " + str((int)GetLastError()) + " " + path); + return results; + } + else + { + results.push_back(FindFileData.cFileName); + + while (FindNextFile(hFind, &FindFileData) != 0) + { + results.push_back(FindFileData.cFileName); + if (onlyOne) + break; + } + + FindClose(hFind); + } +#else + extension = toLowerCase(extension); + startswith = toLowerCase(startswith); + startswith.erase(std::remove(startswith.begin(), startswith.end(), '*'), startswith.end()); + DIR* dir = opendir(path.c_str()); + + if (!dir) + return results; + + while (true) + { + dirent* entry = readdir(dir); + + if (!entry) + break; + + if (entry->d_type == DT_DIR) + continue; + + std::string name = std::string(entry->d_name); + std::string lowerName = toLowerCase(name); + + if (extension.size() > name.size() || startswith.size() > name.size()) + continue; + + if (extension == "*" || std::equal(extension.rbegin(), extension.rend(), lowerName.rbegin())) + { + if (startswith.size() == 0 || std::equal(startswith.begin(), startswith.end(), lowerName.begin())) + { + results.push_back(name); + if (onlyOne) + break; + } + } + } + + closedir(dir); +#endif + + return results; } \ No newline at end of file diff --git a/dlls/util.h b/dlls/util.h index 7653770f..104b73df 100644 --- a/dlls/util.h +++ b/dlls/util.h @@ -323,8 +323,9 @@ EXPORT CBaseEntity *UTIL_FindEntityGeneric(const char *szName, Vector &vecSrc, f // returns a CBaseEntity pointer to a player by index. Only returns if the player is spawned and connected // otherwise returns NULL // Index is 1 based -extern CBasePlayer *UTIL_PlayerByIndex( int playerIndex ); -extern CBasePlayer *UTIL_PlayerByUserId( int userid ); +EXPORT extern CBasePlayer *UTIL_PlayerByIndex( int playerIndex ); +EXPORT extern CBasePlayer *UTIL_PlayerByUserId( int userid ); +EXPORT extern CBasePlayer *UTIL_PlayerByUniqueId(const char* id); #define UTIL_EntitiesInPVS(pent) (*g_engfuncs.pfnEntitiesInPVS)(pent) EXPORT edict_t* UTIL_ClientsInPVS(edict_t* edict, int& playerCount); @@ -427,7 +428,7 @@ EXPORT void UTIL_ClientPrint(edict_t* client, int msg_dest, const char *msg ); // prints a message to the HUD say (chat) EXPORT void UTIL_SayText( const char *pText, CBaseEntity *pEntity ); -EXPORT void UTIL_SayTextAll( const char *pText, CBaseEntity *pEntity ); +EXPORT void UTIL_SayTextAll( const char *pText, CBaseEntity *pEntity=NULL ); typedef struct hudtextparms_s @@ -480,7 +481,7 @@ void DBG_AssertFunction(BOOL fExpr, const char* szExpr, const char* szFile, int #endif // !DEBUG -extern DLL_GLOBAL const Vector g_vecZero; +EXPORT extern const Vector g_vecZero; // // Constants that were used only by QC (maybe not used at all now) @@ -879,6 +880,8 @@ EXPORT const char* getPlayerUniqueId(edict_t* plr); EXPORT uint64_t steamid_to_steamid64(const char* steamid); +EXPORT std::string steamid64_to_steamid(uint64_t steam64); + EXPORT uint64_t getPlayerCommunityId(edict_t* plr); EXPORT void LoadAdminList(bool forceUpdate=false); // call on each map change, so AdminLevel can work @@ -887,4 +890,6 @@ EXPORT int AdminLevel(edict_t* player); EXPORT uint64_t getEpochMillis(); -EXPORT double TimeDifference(uint64_t start, uint64_t end); \ No newline at end of file +EXPORT double TimeDifference(uint64_t start, uint64_t end); + +EXPORT std::vector getDirFiles(std::string path, std::string extension, std::string startswith, bool onlyOne); diff --git a/sevenkewp b/sevenkewp index 7c4df33c..82521c02 160000 --- a/sevenkewp +++ b/sevenkewp @@ -1 +1 @@ -Subproject commit 7c4df33c3887a2c5f80a32426381cdfd6aac71f3 +Subproject commit 82521c02d6241a584cba10ff06076e7a2d374050