diff --git a/server/main.h b/server/main.h index 0b603da..7432b19 100644 --- a/server/main.h +++ b/server/main.h @@ -59,6 +59,7 @@ // Std #include #include +#include // Raknet #include "../raknet/RakServer.h" diff --git a/server/plugincommon.h b/server/plugincommon.h index b15463c..89592d5 100644 --- a/server/plugincommon.h +++ b/server/plugincommon.h @@ -4,6 +4,49 @@ //---------------------------------------------------------- +#define SAMP_PLUGIN_VERSION 0x0220 + +//---------------------------------------------------------- + +#ifdef __cplusplus + #define PLUGIN_EXTERN_C extern "C" +#else + #define PLUGIN_EXTERN_C +#endif + +#if defined(LINUX) || defined(FREEBSD) || defined(__FreeBSD__) || defined(__OpenBSD__) + #ifndef __GNUC__ + #pragma message "Warning: Not using a GNU compiler." + #endif + #define PLUGIN_CALL + #ifndef SAMPSVR + // Compile code with -fvisibility=hidden to hide non-exported functions. + #define PLUGIN_EXPORT PLUGIN_EXTERN_C __attribute__((visibility("default"))) + #else + #define PLUGIN_EXPORT PLUGIN_EXTERN_C + #endif +#elif defined(WIN32) || defined(_WIN32) || defined(__WIN32__) + #ifndef _MSC_VER + #pragma message "Warning: Not using a VC++ compiler." + #endif + #define PLUGIN_CALL __stdcall + #define PLUGIN_EXPORT PLUGIN_EXTERN_C +#else + #error "You must define one of WIN32, LINUX or FREEBSD" +#endif + +//---------------------------------------------------------- + +enum SUPPORTS_FLAGS +{ + SUPPORTS_VERSION = SAMP_PLUGIN_VERSION, + SUPPORTS_VERSION_MASK = 0xffff, + SUPPORTS_AMX_NATIVES = 0x10000, + SUPPORTS_PROCESS_TICK = 0x20000, +}; + +//---------------------------------------------------------- + enum PLUGIN_DATA_TYPE { // For some debugging @@ -65,4 +108,9 @@ enum PLUGIN_AMX_EXPORT PLUGIN_AMX_EXPORT_UTF8Put = 43, }; +//---------------------------------------------------------- + #endif // _PLUGINCOMMON_H_INCLUDED + +//---------------------------------------------------------- +// EOF diff --git a/server/plugins.cpp b/server/plugins.cpp index 37586cb..4157416 100644 --- a/server/plugins.cpp +++ b/server/plugins.cpp @@ -127,10 +127,290 @@ CPlugins::CPlugins() CPlugins::~CPlugins() { - // TODO: CPlugins::~CPlugins W: 00469DB0 L: 080D20E0 + ServerPluginVector::iterator itor; + + for(itor=m_Plugins.begin(); itor!=m_Plugins.end(); itor++) + { + ServerPlugin_s* pSPlugin = *itor; + if (pSPlugin->Unload) + pSPlugin->Unload(); + PLUGIN_UNLOAD(pSPlugin->hModule); + delete pSPlugin; + } } +//--------------------------------------- + +BOOL CPlugins::LoadSinglePlugin(char *szPluginPath) +{ + // Load it + ServerPlugin_s* pSPlugin; + pSPlugin = new ServerPlugin_s(); + + pSPlugin->hModule = PLUGIN_LOAD(szPluginPath); + if (pSPlugin->hModule == NULL) + { + // Failed to load + delete pSPlugin; + return FALSE; + } + + pSPlugin->Load = (ServerPluginLoad_t)PLUGIN_GETFUNCTION(pSPlugin->hModule, "Load"); + pSPlugin->Unload = (ServerPluginUnload_t)PLUGIN_GETFUNCTION(pSPlugin->hModule, "Unload"); + pSPlugin->Supports = (ServerPluginSupports_t)PLUGIN_GETFUNCTION(pSPlugin->hModule, "Supports"); + + if (pSPlugin->Load == NULL || pSPlugin->Supports == NULL) + { + // Not proper architecture! + logprintf(" Plugin does not conform to architecture."); + PLUGIN_UNLOAD(pSPlugin->hModule); + delete pSPlugin; + return FALSE; + } + + pSPlugin->dwSupportFlags = (SUPPORTS_FLAGS)pSPlugin->Supports(); + + if ((pSPlugin->dwSupportFlags & SUPPORTS_VERSION_MASK) > SUPPORTS_VERSION) + { + // Unsupported version, sorry! + logprintf(" Unsupported version - This plugin requires version %x.", (pSPlugin->dwSupportFlags & SUPPORTS_VERSION_MASK)); + PLUGIN_UNLOAD(pSPlugin->hModule); + delete pSPlugin; + return FALSE; + } + + if ((pSPlugin->dwSupportFlags & SUPPORTS_AMX_NATIVES) != 0) + { + pSPlugin->AmxLoad = (ServerPluginAmxLoad_t)PLUGIN_GETFUNCTION(pSPlugin->hModule, "AmxLoad"); + pSPlugin->AmxUnload = (ServerPluginAmxUnload_t)PLUGIN_GETFUNCTION(pSPlugin->hModule, "AmxUnload"); + } + else + { + pSPlugin->AmxLoad = NULL; + pSPlugin->AmxUnload = NULL; + } + + if ((pSPlugin->dwSupportFlags & SUPPORTS_PROCESS_TICK) != 0) + { + pSPlugin->ProcessTick = (ServerPluginProcessTick_t)PLUGIN_GETFUNCTION(pSPlugin->hModule, "ProcessTick"); + } + else + { + pSPlugin->ProcessTick = NULL; + } + + if (!pSPlugin->Load(m_PluginData)) + { + // Initialize failed! + PLUGIN_UNLOAD(pSPlugin->hModule); + delete pSPlugin; + return FALSE; + } + + m_Plugins.push_back(pSPlugin); + + return TRUE; +} + +//--------------------------------------- + void CPlugins::LoadPlugins(char *szSearchPath) { - // TODO: CPlugins::LoadPlugins W: 0046A570 L: 080D29E0 + char szPath[MAX_PATH]; + char szFullPath[MAX_PATH]; + char *szDlerror = NULL; + strcpy(szPath, szSearchPath); + +#ifdef LINUX + if (szPath[strlen(szPath)-1] != '/') + strcat(szPath, "/"); +#else + if (szPath[strlen(szPath)-1] != '\\') + strcat(szPath, "\\"); +#endif + + logprintf(""); + logprintf("Server Plugins"); + logprintf("--------------"); + + char* szFilename = strtok(pConsole->GetStringVariable("plugins"), " "); + while (szFilename) + { + logprintf(" Loading plugin: %s", szFilename); + + strcpy(szFullPath, szPath); + strcat(szFullPath, szFilename); + + if (LoadSinglePlugin(szFullPath)) + { + logprintf(" Loaded."); + } + else + { +#ifdef LINUX + szDlerror = PLUGIN_GETERROR(); + if (szDlerror) + logprintf(" Failed (%s)", szDlerror); + else + logprintf(" Failed."); +#else + logprintf(" Failed."); +#endif + } + + szFilename = strtok(NULL, " "); + } + logprintf(" Loaded %d plugins.\n", GetPluginCount()); } + +// [OBSOLETE: Using the non search defined method] +void CPlugins::LoadPluginsSearch(char *szSearchPath) +{ +#ifdef LINUX + DIR *dir = opendir(szSearchPath); + struct dirent *file; + char *szFilename = NULL; + char *szExt = NULL; + int iStrLen; + char szPath[255]; + strcpy(szPath, szSearchPath); + if (szPath[strlen(szPath)-1] != '/') strcat(szPath, "/"); + char szFullPath[255]; + char *szDlerror = NULL; + if (dir) + { + logprintf(""); + logprintf("Server Plugins"); + logprintf("--------------"); + + // Load the plugins + while (dir) + { + strcpy(szFullPath, szPath); + if ((file = readdir(dir)) != NULL) + { + szFilename = (char*)file->d_name; + iStrLen = strlen(szFilename); + if (iStrLen > 3) + { + szExt = szFilename+iStrLen-3; + if (strcmp(".so", szExt) == 0) + { + logprintf(" Loading plugin: %s", szFilename); + strcat(szFullPath, szFilename); + bool bSuccess = LoadSinglePlugin(szFullPath); + if (!bSuccess) + { + szDlerror = PLUGIN_GETERROR(); + if (szDlerror) + logprintf(" Failed (%s)", szDlerror); + else + logprintf((" Failed."); + } + } + } + } + else + { + closedir(dir); + dir = NULL; + } + } + logprintf(""); + } +#else + char szPath[MAX_PATH]; + char szSearch[MAX_PATH]; + + strcpy(szPath, szSearchPath); + + char cLastChar = szPath[strlen(szPath)-1]; + if (cLastChar != '\\' && cLastChar != '/') + strcat(szPath, "\\"); + + DWORD szPathLen = strlen(szPath); + + strcpy(szSearch, szPath); + strcat(szSearch, "*.dll"); + + WIN32_FIND_DATA fdFindData; + HANDLE hFindFile = FindFirstFile(szSearch, &fdFindData); + if (hFindFile != INVALID_HANDLE_VALUE) + { + logprintf(""); + logprintf("Server Plugins"); + logprintf("--------------"); + + // Load the plugins + while(true) { + logprintf(" Loading plugin: %s", fdFindData.cFileName); + strcpy(szPath+szPathLen, fdFindData.cFileName); + BOOL bSuccess = LoadSinglePlugin(szPath); + if (!bSuccess) + logprintf(" Failed."); + if(!FindNextFile(hFindFile, &fdFindData)) + break; + } + logprintf(""); + } + FindClose(hFindFile); +#endif +} + +//--------------------------------------- + +DWORD CPlugins::GetPluginCount() +{ + return (DWORD)m_Plugins.size(); +} + +//--------------------------------------- + +ServerPlugin_s* CPlugins::GetPlugin(DWORD index) +{ + return m_Plugins[index]; +} + +//--------------------------------------- + +void CPlugins::DoProcessTick() +{ + ServerPluginVector::iterator itor; + + for(itor=m_Plugins.begin(); itor!=m_Plugins.end(); itor++) { + ServerPlugin_s* pSPlugin = *itor; + if ((pSPlugin->dwSupportFlags & SUPPORTS_PROCESS_TICK) != 0) + if (pSPlugin->ProcessTick != NULL) + pSPlugin->ProcessTick(); + } +} + +//--------------------------------------- + +void CPlugins::DoAmxLoad(AMX *amx) +{ + ServerPluginVector::iterator itor; + + for(itor=m_Plugins.begin(); itor!=m_Plugins.end(); itor++) { + ServerPlugin_s* pSPlugin = *itor; + if ((pSPlugin->dwSupportFlags & SUPPORTS_AMX_NATIVES) != 0) + if (pSPlugin->AmxLoad != NULL) + pSPlugin->AmxLoad(amx); + } +} + +//--------------------------------------- + +void CPlugins::DoAmxUnload(AMX *amx) +{ + ServerPluginVector::iterator itor; + + for(itor=m_Plugins.begin(); itor!=m_Plugins.end(); itor++) { + ServerPlugin_s* pSPlugin = *itor; + if ((pSPlugin->dwSupportFlags & SUPPORTS_AMX_NATIVES) != 0) + if (pSPlugin->AmxUnload != NULL) + pSPlugin->AmxUnload(amx); + } +} + +//--------------------------------------- diff --git a/server/plugins.h b/server/plugins.h index b7e8ce1..9ff544e 100644 --- a/server/plugins.h +++ b/server/plugins.h @@ -5,18 +5,74 @@ #include "plugincommon.h" #include "plugininternal.h" -class CPlugins // size: W: 1216 L: 1212 +#ifdef LINUX + #include + + #define PLUGIN_LOAD(p) dlopen(p, RTLD_LAZY) + #define PLUGIN_UNLOAD dlclose + #define PLUGIN_GETFUNCTION dlsym +#else + #define PLUGIN_LOAD LoadLibrary + #define PLUGIN_UNLOAD FreeLibrary + #define PLUGIN_GETFUNCTION GetProcAddress +#endif + +typedef bool (PLUGIN_CALL *ServerPluginLoad_t)(void **data); +typedef void (PLUGIN_CALL *ServerPluginUnload_t)(); +typedef unsigned int (PLUGIN_CALL *ServerPluginSupports_t)(); +typedef void (PLUGIN_CALL *ServerPluginProcessTick_t)(); + +typedef int (PLUGIN_CALL *ServerPluginAmxLoad_t)(AMX *amx); +typedef int (PLUGIN_CALL *ServerPluginAmxUnload_t)(AMX *amx); + +struct ServerPlugin_s +{ +#ifdef LINUX + void *hModule; +#else + HMODULE hModule; +#endif + SUPPORTS_FLAGS dwSupportFlags; + + // Core Plugin Interface + ServerPluginLoad_t Load; + ServerPluginUnload_t Unload; + ServerPluginSupports_t Supports; + ServerPluginProcessTick_t ProcessTick; + + // AMX Plugin Interface + ServerPluginAmxLoad_t AmxLoad; + ServerPluginAmxUnload_t AmxUnload; +}; + +typedef std::vector ServerPluginVector; + +//--------------------------------------- + +class CPlugins { private: void* m_PluginData[MAX_PLUGIN_DATA]; void* m_AMXExports[MAX_PLUGIN_AMX_EXPORT]; + ServerPluginVector m_Plugins; + + BOOL LoadSinglePlugin(char *szPluginPath); + public: CPlugins(); ~CPlugins(); void LoadPlugins(char *szSearchPath); + void LoadPluginsSearch(char *szSearchPath); + DWORD GetPluginCount(); + ServerPlugin_s* GetPlugin(DWORD index); + + void DoProcessTick(); + + void DoAmxLoad(AMX *amx); + void DoAmxUnload(AMX *amx); }; #endif