amxmodx/amxmodx/modules.cpp

660 lines
14 KiB
C++
Raw Normal View History

2004-03-06 00:03:14 +03:00
/* AMX Mod X
*
* by the AMX Mod X Development Team
* originally developed by OLO
*
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at
* your option) any later version.
*
* 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, write to the Free Software Foundation,
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* In addition, as a special exception, the author gives permission to
* link the code of this program with the Half-Life Game Engine ("HL
* Engine") and Modified Game Libraries ("MODs") developed by Valve,
* L.L.C ("Valve"). You must obey the GNU General Public License in all
* respects for all of the code used other than the HL Engine and MODs
* from Valve. If you modify this file, you may extend this exception
* to your version of the file, but you are not obligated to do so. If
* you do not wish to do so, delete this exception statement from your
* version.
*/
2004-01-31 23:56:22 +03:00
#include <extdll.h>
#include <meta_api.h>
2004-03-24 04:35:44 +03:00
#include "amxmodx.h"
2004-01-31 23:56:22 +03:00
#include "osdep.h" // sleep, etc
#include "CFile.h"
CList<CModule> g_modules;
CList<CScript,AMX*> g_loadedscripts;
CModule *g_CurrentlyAttachedModule = NULL; // The module we are attaching at the moment; NULL otherwise
// also NULL for non-amxx modules
// This is needed so we know which module called a function
2004-01-31 23:56:22 +03:00
#ifdef __cplusplus
extern "C" {
#endif
2004-01-31 23:56:22 +03:00
extern const char* no_function; // stupid work around
2004-01-31 23:56:22 +03:00
#ifdef __cplusplus
}
#endif
void report_error( int code, char* fmt, ... )
{
va_list argptr;
char string[256];
*string = 0;
va_start (argptr, fmt);
vsnprintf (string, 255, fmt,argptr);
string[255] = 0;
va_end (argptr);
if ( *string ) {
//File fp( "error_amx.log","a" );
//fp << string;
AMXXLOG_Log(string);
AMXXLOG_Log("[AMXX] Make sure that modules are compatible with AMX Mod X %s" , AMX_VERSION );
AMXXLOG_Log("[AMXX] Please fix the problem then start the server again" );
2004-01-31 23:56:22 +03:00
}
sleep( 5 );
exit( code );
}
void print_srvconsole( char *fmt, ... )
{
va_list argptr;
char string[256];
va_start (argptr, fmt);
vsnprintf (string, 255, fmt,argptr);
string[255] = 0;
va_end (argptr);
SERVER_PRINT(string);
}
void* alloc_amxmemory(void** p, int size)
{
*p = new unsigned char[ size ];
return *p;
}
void free_amxmemory(void **ptr)
{
delete[] *ptr;
*ptr = 0;
}
int load_amxscript(AMX *amx, void **program, const char *filename, char error[64]){
AMX_HEADER hdr;
int err;
FILE *fp;
memset(amx, 0, sizeof(*amx));
*program = 0;
*error = 0;
if ( (fp = fopen( filename, "rb" )) == NULL)
{
strcpy(error,"Plugin file open error");
return (amx->error = AMX_ERR_NOTFOUND);
}
fread(&hdr, sizeof(hdr), 1, fp);
amx_Align16(&hdr.magic);
if (hdr.magic!=AMX_MAGIC)
{
strcpy(error,"Invalid plugin");
return (amx->error = AMX_ERR_FORMAT);
}
amx_Align32((uint32_t *)&hdr.stp);
amx_Align32((uint32_t *)&hdr.size);
if ( (*program = new unsigned char[ (int)hdr.stp ]) == 0 )
//if ( (*program = malloc( (int)hdr.stp )) == 0 )
{
strcpy(error,"Failed to allocate memory");
return (amx->error = AMX_ERR_MEMORY);
}
rewind(fp);
fread(*program, 1, (size_t)hdr.size, fp);
fclose(fp);
if ((err = amx_Init( amx, *program )) != AMX_ERR_NONE)
{
sprintf(error,"Load error %d (invalid file format or version)", err);
return (amx->error = AMX_ERR_INIT);
}
#ifdef JIT
void *np = new unsigned char[ amx->code_size ];
void *rt = new unsigned char[ amx->reloc_size ];
if ( !np || (!rt && amx->reloc_size > 0) )
{
delete[] np;
delete[] rt;
strcpy(error,"Failed to initialize plugin");
return (amx->error = AMX_ERR_INIT);
}
if (amx_InitJIT(amx, rt, np) == AMX_ERR_NONE)
{
//amx->base = (unsigned char FAR *)realloc( np, amx->code_size );
amx->base = new unsigned char FAR[ amx->code_size ];
if ( amx->base )
memcpy( amx->base , np , amx->code_size );
delete[] np;
delete[] rt;
delete[] *program;
(*program) = amx->base;
if ( *program == 0 ){
strcpy(error,"Failed to allocate memory");
return (amx->error = AMX_ERR_MEMORY);
}
}
else
{
delete[] np;
delete[] rt;
strcpy(error,"Failed to initialize plugin");
return (amx->error = AMX_ERR_INIT_JIT);
}
#endif
CScript* aa = new CScript(amx,*program,filename);
if ( aa == 0 )
{
strcpy(error,"Failed to allocate memory");
return (amx->error = AMX_ERR_MEMORY);
}
g_loadedscripts.put( aa );
return set_amxnatives(amx,error);
}
int set_amxnatives(AMX* amx,char error[64])
{
for ( CList<CModule>::iterator a = g_modules.begin(); a ; ++a )
{
for( CList<AMX_NATIVE_INFO*>::iterator cc =
(*a).m_Natives.begin(); cc; ++cc )
2004-01-31 23:56:22 +03:00
amx_Register(amx, *cc , -1);
}
amx_Register(amx, string_Natives, -1);
amx_Register(amx, float_Natives, -1);
amx_Register(amx, file_Natives, -1);
amx_Register(amx, amxmod_Natives, -1);
amx_Register(amx, power_Natives, -1);
amx_Register(amx, time_Natives, -1);
amx_Register(amx, vault_Natives, -1);
if ( amx_Register(amx, core_Natives, -1) != AMX_ERR_NONE )
{
sprintf(error,"Function not found (name \"%s\")",no_function);
return (amx->error = AMX_ERR_NATIVE);
}
return AMX_ERR_NONE;
}
int unload_amxscript(AMX* amx, void** program)
{
CList<CScript,AMX*>::iterator a = g_loadedscripts.find( amx );
if ( a ) a.remove();
delete[] *program;
//free( *program );
*program = 0;
return AMX_ERR_NONE;
}
AMX* get_amxscript(int id , void** code, const char** filename)
{
CList<CScript,AMX*>::iterator a = g_loadedscripts.begin();
while ( a && id-- )
++a;
if ( a ){
*filename = (*a).getName();
*code = (*a).getCode();
return (*a).getAMX();
}
return 0;
}
const char* get_amxscriptname(AMX* amx)
{
CList<CScript,AMX*>::iterator a = g_loadedscripts.find( amx );
return a ? (*a).getName() : "";
}
void get_modname(char* buffer )
{
strcpy( buffer , g_mod_name.str() );
}
char* build_pathname(char *fmt, ... )
{
static char string[256];
int b;
int a = b = snprintf(string , 255 ,
#ifndef __linux__
"%s\\",
#else
"%s/",
#endif
g_mod_name.str());
va_list argptr;
va_start (argptr, fmt);
a += vsnprintf (&string[a], 255 - a , fmt,argptr);
string[ a ] = 0;
va_end (argptr);
char* path = &string[b];
while (*path)
{
#ifndef __linux__
if (*path == '/') *path = '\\';
#else
if (*path == '\\') *path = '/';
#endif
++path;
}
return string;
}
// build pathname based on addons dir
char* build_pathname_addons(char *fmt, ... )
{
static char string[256];
va_list argptr;
va_start (argptr, fmt);
vsnprintf (string, 255, fmt, argptr);
va_end (argptr);
char* path = string;
while (*path)
{
#ifndef __linux__
if (*path == '/') *path = '\\';
#else
if (*path == '\\') *path = '/';
#endif
++path;
}
return string;
}
2004-01-31 23:56:22 +03:00
int add_amxnatives(module_info_s* info,AMX_NATIVE_INFO*natives)
{
CList<CModule>::iterator a = g_modules.begin();
while ( a )
{
if ( (*a).getInfo() == info )
{
AMX_NATIVE_INFO** aa = new AMX_NATIVE_INFO*(natives);
if ( aa == 0 ) return AMX_ERR_NATIVE;
(*a).m_Natives.put( aa );
2004-01-31 23:56:22 +03:00
return AMX_ERR_NONE;
}
++a;
}
return AMX_ERR_NATIVE;
}
bool validFile(const char* file)
{
const char* a = 0;
while(*file)
if (*file++=='.')
a = file;
#ifndef __linux__
return (a && !strcmp(a,"dll"));
#else
return (a && !strcmp(a,"so"));
#endif
}
int loadModules(const char* filename)
{
File fp( build_pathname("%s",filename), "r" );
if ( !fp )
{
AMXXLOG_Log( "[AMXX] Modules list not found (file \"%s\")",filename);
2004-01-31 23:56:22 +03:00
return 0;
}
char line[256], moduleName[256];
int loaded = 0;
while ( fp.getline( line , 255 ) )
{
*moduleName = 0;
sscanf(line,"%s",moduleName);
if (!isalnum(*moduleName) || !validFile(moduleName) )
continue;
2004-03-24 21:59:37 +03:00
char* pathname = build_pathname("%s/%s", get_localinfo("amxx_modulesdir", "addons/amxx/modules"), line);
2004-01-31 23:56:22 +03:00
CList<CModule>::iterator a = g_modules.find( pathname );
if ( a ) continue; // already loaded
CModule* cc = new CModule( pathname );
if ( cc == 0 ) return loaded;
cc->queryModule();
switch( cc->getStatusValue() ) {
case MODULE_BADLOAD:
report_error( 1 , "[AMXX] Module is not a valid library (file \"%s\")",pathname );
2004-01-31 23:56:22 +03:00
break;
case MODULE_NOINFO:
report_error( 1 ,"[AMXX] Couldn't find info. about module (file \"%s\")",pathname );
2004-01-31 23:56:22 +03:00
break;
case MODULE_NOQUERY:
report_error( 1 , "[AMXX] Couldn't find \"AMX_Query\" or \"AMXX_Query\" (file \"%s\")", pathname );
2004-01-31 23:56:22 +03:00
break;
case MODULE_NOATTACH:
report_error( 1 , "[AMXX] Couldn't find \"%s\" (file \"%s\")", cc->isAmxx() ? "AMXX_Attach" : "AMX_Attach", pathname );
2004-01-31 23:56:22 +03:00
break;
case MODULE_OLD:
report_error( 1 , "[AMXX] Module has a different interface version (file \"%s\")",pathname );
2004-01-31 23:56:22 +03:00
break;
case MODULE_NEWER:
report_error(1, "[AMXX] Module has a newer interface version (file \"%s\"). Please download a new amxmodx.", pathname);
break;
case MODULE_INTERROR:
report_error(1, "[AMXX] Internal error during module load (file \"%s\")", pathname);
break;
2004-01-31 23:56:22 +03:00
default:
++loaded;
}
g_modules.put( cc );
}
return loaded;
}
void dettachModules()
{
CList<CModule>::iterator a = g_modules.begin();
while ( a )
{
(*a).detachModule();
a.remove();
}
}
void dettachReloadModules()
{
CList<CModule>::iterator a = g_modules.begin();
while ( a )
{
if ( (*a).isReloadable() )
{
(*a).detachModule();
a.remove();
continue;
}
++a;
}
}
void attachModules()
{
CList<CModule>::iterator a = g_modules.begin();
while ( a )
{
bool retVal = (*a).attachModule();
if ((*a).isAmxx() && !retVal)
{
switch ((*a).getStatusValue())
{
case MODULE_FUNCNOTPRESENT:
report_error(1, "[AMXX] Module requested a not exisitng function (file \"%s\")%s%s%s", (*a).getFilename(), (*a).getMissingFunc() ? " (func \"" : "",
(*a).getMissingFunc() ? (*a).getMissingFunc() : "", (*a).getMissingFunc() ? "\")" : "");
break;
case MODULE_INTERROR:
report_error(1, "[AMXX] Internal error during module load (file \"%s\")", (*a).getFilename());
break;
case MODULE_BADLOAD:
report_error( 1 , "[AMXX] Module is not a valid library (file \"%s\")", (*a).getFilename());
break;
default:
break;
}
}
2004-01-31 23:56:22 +03:00
++a;
}
}
const char* strip_name( const char* a )
{
const char* ret = a;
while(*a){
if ( *a== '/' || *a=='\\' ){
ret = ++a;
continue;
}
++a;
}
return ret;
}
void dettachMetaModModules( const char* filename )
{
File fp( build_pathname("%s",filename), "r" );
if ( !fp )
{
AMXXLOG_Log( "[AMXX] Modules list not found (file \"%s\")",filename);
2004-01-31 23:56:22 +03:00
return;
}
char line[256], moduleName[256], cmdline[256];
DLHANDLE module;
while ( fp.getline( line , 255 ) )
{
*moduleName = 0;
sscanf(line,"%s",moduleName);
if (!isalnum(*moduleName) || !validFile(moduleName) )
continue;
2004-03-24 21:59:37 +03:00
char* pathname = build_pathname("%s/%s", get_localinfo("amxx_modulesdir", "addons/amxx/modules"), line);
char* mmpathname = build_pathname_addons("%s/%s", get_localinfo("amxx_modulesdir", "addons/amxx/modules"), line);
2004-01-31 23:56:22 +03:00
module = DLLOAD( pathname ); // link dll
if ( module )
{
int a = (int)DLPROC(module,"Meta_Attach");
if ( a )
{
snprintf(cmdline,255, "meta unload %s\n", strip_name(mmpathname) );
2004-01-31 23:56:22 +03:00
cmdline[255] = 0;
SERVER_COMMAND( cmdline );
}
DLFREE(module);
}
}
}
void attachMetaModModules( const char* filename )
{
File fp( build_pathname("%s",filename), "r" );
if ( !fp )
{
AMXXLOG_Log( "[AMXX] Modules list not found (file \"%s\")",filename);
2004-01-31 23:56:22 +03:00
return;
}
char line[256], moduleName[256], cmdline[256];
DLHANDLE module;
int loaded = 0;
while ( fp.getline( line , 255 ) )
{
*moduleName = 0;
sscanf(line,"%s",moduleName);
if (!isalnum(*moduleName) || !validFile(moduleName) )
continue;
2004-03-24 21:59:37 +03:00
char* pathname = build_pathname("%s/%s", get_localinfo("amxx_modulesdir", "addons/amxx/modules"), line);
char* mmpathname = build_pathname_addons("%s/%s", get_localinfo("amxx_modulesdir", "addons/amxx/modules"), line);
2004-01-31 23:56:22 +03:00
module = DLLOAD( pathname ); // link dll
if ( module )
{
int a = (int)DLPROC(module,"Meta_Attach");
if ( a )
{
snprintf(cmdline,255, "meta load %s\n", mmpathname );
2004-01-31 23:56:22 +03:00
cmdline[255] = 0;
SERVER_COMMAND( cmdline );
++loaded;
}
DLFREE(module);
}
}
if ( loaded )
{
SERVER_COMMAND( "restart\n" );
/* must be or modules can cause crash
since they were not initialized with all routines (spawn, server active
players think, etc.) and metamod calls other routines
like nothing has never happened. */
}
}
// Get the number of running modules
int countModules(CountModulesMode mode)
{
CList<CModule>::iterator iter;
int num;
switch (mode)
{
case CountModules_All:
return g_modules.size();
case CountModules_Running:
iter = g_modules.begin();
num = 0;
while (iter)
{
if ((*iter).getStatusValue() == MODULE_LOADED)
++num;
++iter;
}
return num;
case CountModules_Stopped:
iter = g_modules.begin();
num = 0;
while (iter)
{
if ((*iter).getStatusValue() != MODULE_LOADED)
++num;
++iter;
}
return num;
}
return 0;
}
// new functions
// :TODO: Add functions
int MNF_AddNatives(AMX_NATIVE_INFO* natives)
{
CList<CModule>::iterator a = g_modules.begin();
if (!g_CurrentlyAttachedModule)
return AMX_ERR_NATIVE; // not possible tho ;]
// This is needed so that CList can free it ;]
AMX_NATIVE_INFO** pPtr = new AMX_NATIVE_INFO*(natives);
if (!pPtr)
return AMX_ERR_NONE;
g_CurrentlyAttachedModule->m_Natives.put(pPtr);
return AMX_ERR_NONE;
}
// Fnptr Request function for the new interface
const char *g_LastRequestedFunc = NULL;
void *Module_ReqFnptr(const char *funcName)
{
// func table
struct Func_s
{
const char *name;
void *ptr;
};
static Func_s functions[] = {
{ "AddNatives", MNF_AddNatives },
};
// code
g_LastRequestedFunc = funcName;
for (int i = 0; i < (sizeof(functions) / sizeof(Func_s)); ++i)
{
if (strcmp(funcName, functions[i].name) == 0)
return functions[i].ptr;
}
return NULL;
}