amxmodx/amxmodx/meta_api.cpp

1489 lines
40 KiB
C++
Raw Normal View History

2004-03-05 21:04:17 +00:00
/* AMX Mod X
2004-01-31 20:56:22 +00:00
*
2004-03-05 21:04:17 +00:00
* by the AMX Mod X Development Team
* originally developed by OLO
2004-01-31 20:56:22 +00:00
*
*
2004-03-05 21:04:17 +00:00
* 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.
2004-01-31 20:56:22 +00:00
*
2004-03-05 21:04:17 +00:00
* 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.
2004-01-31 20:56:22 +00:00
*
2004-03-05 21:04:17 +00:00
* 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
2004-01-31 20:56:22 +00:00
*
2004-03-05 21:04:17 +00:00
* 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 20:56:22 +00:00
*/
#include <time.h>
2005-09-16 23:48:51 +00:00
2005-08-21 19:30:27 +00:00
#if defined WIN32
#include <direct.h>
#endif
2005-09-16 23:48:51 +00:00
2004-03-24 01:35:44 +00:00
#include "amxmodx.h"
#include "fakemeta.h"
2005-07-29 06:33:57 +00:00
#include "newmenus.h"
2005-07-31 20:11:58 +00:00
#include "natives.h"
2004-01-31 20:56:22 +00:00
#define MIN_COMPAT_MM_VERS "5:11"
plugin_info_t Plugin_info =
{
MIN_COMPAT_MM_VERS, // ifvers
"AMX Mod X", // name
AMX_VERSION, // version
__DATE__, // date
"AMX Mod X Dev Team", // author
"http://www.amxmodx.org", // url
"AMXX", // logtag
PT_ANYTIME, // (when) loadable
PT_ANYTIME, // (when) unloadable
2004-01-31 20:56:22 +00:00
};
meta_globals_t *gpMetaGlobals;
gamedll_funcs_t *gpGamedllFuncs;
mutil_funcs_t *gpMetaUtilFuncs;
enginefuncs_t g_engfuncs;
globalvars_t *gpGlobals;
2005-02-16 20:36:04 +00:00
pextension_funcs_t *gpMetaPExtFuncs;
2004-01-31 20:56:22 +00:00
funEventCall modMsgsEnd[MAX_REG_MSGS];
funEventCall modMsgs[MAX_REG_MSGS];
2005-09-16 23:48:51 +00:00
2004-01-31 20:56:22 +00:00
void (*function)(void*);
void (*endfunction)(void*);
2004-07-08 16:02:01 +00:00
CLog g_log;
CForwardMngr g_forwards;
2004-01-31 20:56:22 +00:00
CList<CPlayer*> g_auth;
CList<CCVar> g_cvars;
CList<ForceObject> g_forcemodels;
CList<ForceObject> g_forcesounds;
CList<ForceObject> g_forcegeneric;
CPlayer g_players[33];
CPlayer* mPlayer;
CPluginMngr g_plugins;
CTaskMngr g_tasksMngr;
CmdMngr g_commands;
2005-09-16 23:48:51 +00:00
2004-01-31 20:56:22 +00:00
EventsMngr g_events;
Grenades g_grenades;
LogEventsMngr g_logevents;
MenuMngr g_menucmds;
2004-07-28 18:33:20 +00:00
CLangMngr g_langMngr;
String g_log_dir;
String g_mod_name;
2004-01-31 20:56:22 +00:00
XVars g_xvars;
2005-09-16 23:48:51 +00:00
2004-01-31 20:56:22 +00:00
bool g_bmod_cstrike;
bool g_bmod_dod;
bool g_dontprecache;
bool g_forcedmodules;
bool g_forcedsounds;
2005-09-16 23:48:51 +00:00
2004-01-31 20:56:22 +00:00
fakecmd_t g_fakecmd;
2005-09-16 23:48:51 +00:00
2004-01-31 20:56:22 +00:00
float g_game_restarting;
float g_game_timeleft;
float g_task_time;
float g_auth_time;
2005-09-16 23:48:51 +00:00
bool g_initialized = false;
bool g_IsNewMM = false;
bool g_NeedsP = false;
bool g_coloredmenus;
2005-08-17 17:07:41 +00:00
bool g_activated = false;
bool g_NewDLL_Available = false;
int g_mm_vers = 0;
#ifdef MEMORY_TEST
float g_next_memreport_time;
unsigned int g_memreport_count;
String g_memreport_dir;
bool g_memreport_enabled;
#define MEMREPORT_INTERVAL 300.0f /* 5 mins */
#endif // MEMORY_TEST
2004-01-31 20:56:22 +00:00
hudtextparms_t g_hudset;
//int g_edict_point;
int g_players_num;
int mPlayerIndex;
int mState;
int g_srvindex;
cvar_t init_amxmodx_version = {"amxmodx_version", "", FCVAR_SERVER | FCVAR_SPONLY};
cvar_t init_amxmodx_modules = {"amxmodx_modules", "", FCVAR_SPONLY};
2004-09-15 21:21:46 +00:00
cvar_t init_amxmodx_debug = {"amx_debug", "1", FCVAR_SPONLY};
2006-01-24 18:47:08 +00:00
cvar_t init_amxmodx_mldebug = {"amx_mldebug", "", FCVAR_SPONLY};
2004-02-03 15:26:57 +00:00
cvar_t* amxmodx_version = NULL;
cvar_t* amxmodx_modules = NULL;
2004-01-31 20:56:22 +00:00
cvar_t* hostname = NULL;
cvar_t* mp_timelimit = NULL;
// main forwards
int FF_ClientCommand = -1;
int FF_ClientConnect = -1;
int FF_ClientDisconnect = -1;
int FF_ClientInfoChanged = -1;
int FF_ClientPutInServer = -1;
int FF_PluginInit = -1;
int FF_PluginCfg = -1;
int FF_PluginPrecache = -1;
int FF_PluginLog = -1;
int FF_PluginEnd = -1;
int FF_InconsistentFile = -1;
int FF_ClientAuthorized = -1;
2004-08-29 13:32:31 +00:00
// Precache stuff from force consistency calls
// or check for pointed files won't be done
int C_PrecacheModel(char *s)
{
if (!g_forcedmodules)
{
g_forcedmodules = true;
for (CList<ForceObject>::iterator a = g_forcemodels.begin(); a; ++a)
{
PRECACHE_MODEL((char*)(*a).getFilename());
ENGINE_FORCE_UNMODIFIED((*a).getForceType(), (*a).getMin(), (*a).getMax(), (*a).getFilename());
}
}
RETURN_META_VALUE(MRES_IGNORED, 0);
2004-01-31 20:56:22 +00:00
}
int C_PrecacheSound(char *s)
{
if (!g_forcedsounds)
{
g_forcedsounds = true;
for (CList<ForceObject>::iterator a = g_forcesounds.begin(); a; ++a)
{
PRECACHE_SOUND((char*)(*a).getFilename());
2005-09-10 20:09:14 +00:00
ENGINE_FORCE_UNMODIFIED((*a).getForceType(), (*a).getMin(), (*a).getMax(), (*a).getFilename());
}
if (!g_bmod_cstrike)
{
PRECACHE_SOUND("weapons/cbar_hitbod1.wav");
PRECACHE_SOUND("weapons/cbar_hitbod2.wav");
PRECACHE_SOUND("weapons/cbar_hitbod3.wav");
}
}
RETURN_META_VALUE(MRES_IGNORED, 0);
2004-01-31 20:56:22 +00:00
}
2004-08-29 13:32:31 +00:00
// On InconsistentFile call forward function from plugins
int C_InconsistentFile(const edict_t *player, const char *filename, char *disconnect_message)
2004-01-31 20:56:22 +00:00
{
if (FF_InconsistentFile < 0)
RETURN_META_VALUE(MRES_IGNORED, FALSE);
2004-01-31 20:56:22 +00:00
if (MDLL_InconsistentFile(player, filename, disconnect_message))
{
CPlayer *pPlayer = GET_PLAYER_POINTER((edict_t *)player);
2004-01-31 20:56:22 +00:00
if (executeForwards(FF_InconsistentFile, static_cast<cell>(pPlayer->index),
filename, disconnect_message) == 1)
RETURN_META_VALUE(MRES_SUPERCEDE, FALSE);
RETURN_META_VALUE(MRES_SUPERCEDE, TRUE);
}
2004-01-31 20:56:22 +00:00
RETURN_META_VALUE(MRES_IGNORED, FALSE);
2004-01-31 20:56:22 +00:00
}
const char* get_localinfo(const char* name, const char* def)
2004-01-31 20:56:22 +00:00
{
const char* b = LOCALINFO((char*)name);
if (b == 0 || *b == 0)
2005-09-10 20:09:14 +00:00
SET_LOCALINFO((char*)name, (char*)(b = def));
return b;
2004-01-31 20:56:22 +00:00
}
2004-08-29 13:32:31 +00:00
// Very first point at map load
// Load AMX modules for new native functions
// Initialize AMX stuff and load it's plugins from plugins.ini list
// Call precache forward function from plugins
int C_Spawn(edict_t *pent)
2005-08-17 17:07:41 +00:00
{
if (g_initialized)
RETURN_META_VALUE(MRES_IGNORED, 0);
g_activated = false;
g_initialized = true;
g_forcedmodules = false;
g_forcedsounds = false;
g_srvindex = IS_DEDICATED_SERVER() ? 0 : 1;
hostname = CVAR_GET_POINTER("hostname");
mp_timelimit = CVAR_GET_POINTER("mp_timelimit");
g_forwards.clear();
g_log.MapChange();
// ###### Initialize task manager
g_tasksMngr.registerTimers(&gpGlobals->time, &mp_timelimit->value, &g_game_timeleft);
// ###### Load lang
char file[256];
2005-09-16 23:48:51 +00:00
g_langMngr.LoadCache(build_pathname_r(file, sizeof(file) - 1, "%s/dictionary.cache", get_localinfo("amxx_datadir", "addons/amxmodx/data")));
if (!g_langMngr.Load(build_pathname_r(file, sizeof(file) - 1, "%s/languages.dat", get_localinfo("amxmodx_datadir", "addons/amxmodx/data"))))
{
g_langMngr.InvalidateCache();
}
// ###### Initialize commands prefixes
g_commands.registerPrefix("amx");
g_commands.registerPrefix("amxx");
g_commands.registerPrefix("say");
g_commands.registerPrefix("admin_");
g_commands.registerPrefix("sm_");
g_commands.registerPrefix("cm_");
// make sure localinfos are set
get_localinfo("amxx_basedir", "addons/amxmodx");
get_localinfo("amxx_pluginsdir", "addons/amxmodx/plugins");
get_localinfo("amxx_modulesdir", "addons/amxmodx/modules");
get_localinfo("amxx_configsdir", "addons/amxmodx/configs");
get_localinfo("amxx_customdir", "addons/amxmodx/custom");
// ###### Load modules
loadModules(get_localinfo("amxx_modules", "addons/amxmodx/configs/modules.ini"), PT_ANYTIME);
int loaded = countModules(CountModules_Running); // Call after attachModules so all modules don't have pending stat
2005-09-16 23:48:51 +00:00
// Set some info about amx version and modules
CVAR_SET_STRING(init_amxmodx_version.name, AMX_VERSION);
char buffer[32];
sprintf(buffer, "%d", loaded);
CVAR_SET_STRING(init_amxmodx_modules.name, buffer);
// ###### Load Vault
2005-09-16 23:48:51 +00:00
g_vault.setSource(build_pathname_r(file, sizeof(file) - 1, "%s", get_localinfo("amxx_vault", "addons/amxmodx/configs/vault.ini")));
g_vault.loadVault();
if (strlen(g_vault.get("server_language")) < 1)
{
g_vault.put("server_language", "en");
g_vault.saveVault();
}
// ###### Init time and freeze tasks
g_game_timeleft = g_bmod_dod ? 1.0f : 0.0f;
g_task_time = gpGlobals->time + 99999.0f;
g_auth_time = gpGlobals->time + 99999.0f;
#ifdef MEMORY_TEST
g_next_memreport_time = gpGlobals->time + 99999.0f;
#endif
g_players_num = 0;
// Set server flags
memset(g_players[0].flags, -1, sizeof(g_players[0].flags));
// ###### Load AMX scripts
g_plugins.loadPluginsFromFile(get_localinfo("amxx_plugins", "addons/amxmodx/configs/plugins.ini"));
g_plugins.Finalize();
// Register forwards
FF_PluginInit = registerForward("plugin_init", ET_IGNORE, FP_DONE);
FF_ClientCommand = registerForward("client_command", ET_STOP, FP_CELL, FP_DONE);
FF_ClientConnect = registerForward("client_connect", ET_IGNORE, FP_CELL, FP_DONE);
FF_ClientDisconnect = registerForward("client_disconnect", ET_IGNORE, FP_CELL, FP_DONE);
FF_ClientInfoChanged = registerForward("client_infochanged", ET_IGNORE, FP_CELL, FP_DONE);
FF_ClientPutInServer = registerForward("client_putinserver", ET_IGNORE, FP_CELL, FP_DONE);
FF_PluginCfg = registerForward("plugin_cfg", ET_IGNORE, FP_DONE);
FF_PluginPrecache = registerForward("plugin_precache", ET_IGNORE, FP_DONE);
FF_PluginLog = registerForward("plugin_log", ET_STOP, FP_DONE);
FF_PluginEnd = registerForward("plugin_end", ET_IGNORE, FP_DONE);
FF_InconsistentFile = registerForward("inconsistent_file", ET_STOP, FP_CELL, FP_STRING, FP_STRINGEX, FP_DONE);
FF_ClientAuthorized = registerForward("client_authorized", ET_IGNORE, FP_CELL, FP_DONE);
modules_callPluginsLoaded();
// ###### Call precache forward function
g_dontprecache = false;
executeForwards(FF_PluginPrecache);
g_dontprecache = true;
for (CList<ForceObject>::iterator a = g_forcegeneric.begin(); a; ++a)
{
PRECACHE_GENERIC((char*)(*a).getFilename());
ENGINE_FORCE_UNMODIFIED((*a).getForceType(),
2005-09-10 20:09:14 +00:00
(*a).getMin(), (*a).getMax(), (*a).getFilename());
}
RETURN_META_VALUE(MRES_IGNORED, 0);
2004-01-31 20:56:22 +00:00
}
struct sUserMsg
{
const char* name;
int* id;
funEventCall func;
bool endmsg;
bool cstrike;
} g_user_msg[] =
{
{"CurWeapon", &gmsgCurWeapon, Client_CurWeapon, false, false},
{"Damage", &gmsgDamage, Client_DamageEnd, true, true},
{"DeathMsg", &gmsgDeathMsg, Client_DeathMsg, false, true},
{"TextMsg", &gmsgTextMsg, Client_TextMsg, false, false},
{"TeamInfo", &gmsgTeamInfo, Client_TeamInfo, false, false},
{"WeaponList", &gmsgWeaponList, Client_WeaponList, false, false},
{"MOTD", &gmsgMOTD, 0, false, false},
{"ServerName", &gmsgServerName, 0, false, false},
{"Health", &gmsgHealth, 0, false, false},
{"Battery", &gmsgBattery, 0, false, false},
{"ShowMenu", &gmsgShowMenu, Client_ShowMenu, false, false},
{"SendAudio", &gmsgSendAudio, 0, false, false},
{"AmmoX", &gmsgAmmoX, Client_AmmoX, false, false},
{"ScoreInfo", &gmsgScoreInfo, Client_ScoreInfo, false, false},
{"VGUIMenu", &gmsgVGUIMenu, Client_VGUIMenu, false, false},
{"AmmoPickup", &gmsgAmmoPickup, Client_AmmoPickup, false, false},
{"WeapPickup", &gmsgWeapPickup, 0, false, false},
{"ResetHUD", &gmsgResetHUD, 0, false, false},
{"RoundTime", &gmsgRoundTime, 0, false, false},
{0, 0, 0, false, false}
2004-01-31 20:56:22 +00:00
};
int C_RegUserMsg_Post(const char *pszName, int iSize)
2004-01-31 20:56:22 +00:00
{
for (int i = 0; g_user_msg[i].name; ++i)
{
if (strcmp(g_user_msg[i].name, pszName) == 0)
{
int id = META_RESULT_ORIG_RET(int);
*g_user_msg[i].id = id;
if (!g_user_msg[i].cstrike || g_bmod_cstrike)
{
if (g_user_msg[i].endmsg)
modMsgsEnd[id] = g_user_msg[i].func;
else
modMsgs[id] = g_user_msg[i].func;
}
break;
}
}
2004-01-31 20:56:22 +00:00
RETURN_META_VALUE(MRES_IGNORED, 0);
2004-01-31 20:56:22 +00:00
}
/*
2004-08-29 13:32:31 +00:00
Much more later after precache. All is precached, server
will be flaged as ready to use so call
plugin_init forward function from plugins
2004-01-31 20:56:22 +00:00
*/
void C_ServerActivate(edict_t *pEdictList, int edictCount, int clientMax)
2005-08-17 17:07:41 +00:00
{
int id;
for (int i = 0; g_user_msg[i].name; ++i)
{
if ((*g_user_msg[i].id == 0) && (id = GET_USER_MSG_ID(PLID, g_user_msg[i].name, NULL)) != 0)
{
*g_user_msg[i].id = id;
if (!g_user_msg[i].cstrike || g_bmod_cstrike)
{
if (g_user_msg[i].endmsg)
modMsgsEnd[id] = g_user_msg[i].func;
else
modMsgs[id] = g_user_msg[i].func;
}
}
}
2004-01-31 20:56:22 +00:00
RETURN_META(MRES_IGNORED);
2004-01-31 20:56:22 +00:00
}
void C_ServerActivate_Post(edict_t *pEdictList, int edictCount, int clientMax)
2005-08-17 17:07:41 +00:00
{
if (g_activated)
RETURN_META(MRES_IGNORED);
2004-01-31 20:56:22 +00:00
2005-09-10 20:09:14 +00:00
for (int i = 1; i <= gpGlobals->maxClients; ++i)
{
CPlayer *pPlayer = GET_PLAYER_POINTER_I(i);
pPlayer->Init(pEdictList + i, i);
}
2004-01-31 20:56:22 +00:00
executeForwards(FF_PluginInit);
executeForwards(FF_PluginCfg);
2004-01-31 20:56:22 +00:00
// ###### Save lang
char file[256];
2005-09-16 23:48:51 +00:00
g_langMngr.Save(build_pathname_r(file, sizeof(file) - 1, "%s/languages.dat", get_localinfo("amxx_datadir", "addons/amxmodx/data")));
g_langMngr.SaveCache(build_pathname_r(file, sizeof(file) - 1, "%s/dictionary.cache", get_localinfo("amxx_datadir", "addons/amxmodx/data")));
2004-07-28 18:33:20 +00:00
// Correct time in Counter-Strike and other mods (except DOD)
if (!g_bmod_dod)
g_game_timeleft = 0;
2004-01-31 20:56:22 +00:00
g_task_time = gpGlobals->time;
g_auth_time = gpGlobals->time;
2004-01-31 20:56:22 +00:00
#ifdef MEMORY_TEST
g_next_memreport_time = gpGlobals->time + MEMREPORT_INTERVAL;
g_memreport_count = 0;
g_memreport_enabled = true;
#endif
g_activated = true;
2005-08-17 17:07:41 +00:00
RETURN_META(MRES_IGNORED);
2004-01-31 20:56:22 +00:00
}
2004-08-29 13:32:31 +00:00
// Call plugin_end forward function from plugins.
2005-08-17 17:07:41 +00:00
void C_ServerDeactivate()
{
if (!g_activated)
RETURN_META(MRES_IGNORED);
for (int i = 1; i <= gpGlobals->maxClients; ++i)
{
CPlayer *pPlayer = GET_PLAYER_POINTER_I(i);
if (pPlayer->initialized)
executeForwards(FF_ClientDisconnect, static_cast<cell>(pPlayer->index));
2004-01-31 20:56:22 +00:00
if (pPlayer->ingame)
{
pPlayer->Disconnect();
--g_players_num;
}
}
2004-01-31 20:56:22 +00:00
g_players_num = 0;
executeForwards(FF_PluginEnd);
2004-01-31 20:56:22 +00:00
RETURN_META(MRES_IGNORED);
2004-01-31 20:56:22 +00:00
}
// After all clear whole AMX configuration
// However leave AMX modules which are loaded only once
2005-08-17 17:07:41 +00:00
void C_ServerDeactivate_Post()
{
if (!g_initialized)
RETURN_META(MRES_IGNORED);
detachReloadModules();
g_auth.clear();
g_commands.clear();
g_forcemodels.clear();
g_forcesounds.clear();
g_forcegeneric.clear();
g_grenades.clear();
g_tasksMngr.clear();
g_forwards.clear();
g_logevents.clearLogEvents();
g_events.clearEvents();
g_menucmds.clear();
ClearMenus();
g_vault.clear();
g_xvars.clear();
g_plugins.clear();
ClearPluginLibraries();
2005-09-16 23:48:51 +00:00
char file[256];
2005-09-16 23:48:51 +00:00
g_langMngr.Save(build_pathname_r(file, sizeof(file) - 1, "%s/languages.dat", get_localinfo("amxx_datadir", "addons/amxmodx/data")));
g_langMngr.SaveCache(build_pathname_r(file, sizeof(file) - 1, "%s/dictionary.cache", get_localinfo("amxx_datadir", "addons/amxmodx/data")));
g_langMngr.Clear();
// last memreport
#ifdef MEMORY_TEST
if (g_memreport_enabled)
{
if (g_memreport_count == 0)
{
// make new directory
time_t td;
time(&td);
tm *curTime = localtime(&td);
int i = 0;
#ifdef __linux__
2004-09-02 02:16:38 +00:00
mkdir(build_pathname("%s/memreports", get_localinfo("amxx_basedir", "addons/amxmodx")), 0700);
#else
2004-09-02 02:16:38 +00:00
mkdir(build_pathname("%s/memreports", get_localinfo("amxx_basedir", "addons/amxmodx")));
#endif
while (true)
{
char buffer[256];
2004-09-02 02:16:38 +00:00
sprintf(buffer, "%s/memreports/D%02d%02d%03d", get_localinfo("amxx_basedir", "addons/amxmodx"), curTime->tm_mon + 1, curTime->tm_mday, i);
#ifdef __linux__
2004-08-13 08:46:04 +00:00
mkdir(build_pathname("%s", g_log_dir.c_str()), 0700);
if (mkdir(build_pathname(buffer), 0700) < 0)
#else
2004-08-13 08:46:04 +00:00
mkdir(build_pathname("%s", g_log_dir.c_str()));
if (mkdir(build_pathname(buffer)) < 0)
#endif
{
if (errno == EEXIST)
{
// good
++i;
continue;
} else {
// bad
g_memreport_enabled = false;
AMXXLOG_Log("[AMXX] Fatal error: Can't create directory for memreport files (%s)", buffer);
break;
}
}
2004-08-13 08:46:04 +00:00
g_memreport_dir.assign(buffer);
2005-09-16 23:48:51 +00:00
// g_memreport_dir should be valid now
break;
}
}
2005-09-16 23:48:51 +00:00
m_dumpMemoryReport(build_pathname("%s/r%03d.txt", g_memreport_dir.c_str(), g_memreport_count));
AMXXLOG_Log("Memreport #%d created (file \"%s/r%03d.txt\") (interval %f)", g_memreport_count + 1, g_memreport_dir.c_str(), g_memreport_count, MEMREPORT_INTERVAL);
2005-09-16 23:48:51 +00:00
g_memreport_count++;
}
#endif // MEMORY_TEST
g_initialized = false;
RETURN_META(MRES_IGNORED);
2004-01-31 20:56:22 +00:00
}
BOOL C_ClientConnect_Post(edict_t *pEntity, const char *pszName, const char *pszAddress, char szRejectReason[128])
2005-08-17 17:07:41 +00:00
{
CPlayer* pPlayer = GET_PLAYER_POINTER(pEntity);
if (!pPlayer->bot)
{
bool a = pPlayer->Connect(pszName, pszAddress);
executeForwards(FF_ClientConnect, static_cast<cell>(pPlayer->index));
if (a)
{
CPlayer** aa = new CPlayer*(pPlayer);
if (aa)
g_auth.put(aa);
} else {
pPlayer->Authorize();
executeForwards(FF_ClientAuthorized, static_cast<cell>(pPlayer->index));
}
}
RETURN_META_VALUE(MRES_IGNORED, TRUE);
2004-01-31 20:56:22 +00:00
}
void C_ClientDisconnect(edict_t *pEntity)
2005-08-17 17:07:41 +00:00
{
CPlayer *pPlayer = GET_PLAYER_POINTER(pEntity);
if (pPlayer->initialized)
executeForwards(FF_ClientDisconnect, static_cast<cell>(pPlayer->index));
2004-01-31 20:56:22 +00:00
if (pPlayer->ingame)
{
--g_players_num;
}
pPlayer->Disconnect();
2004-01-31 20:56:22 +00:00
RETURN_META(MRES_IGNORED);
2004-01-31 20:56:22 +00:00
}
void C_ClientPutInServer_Post(edict_t *pEntity)
2005-08-17 17:07:41 +00:00
{
CPlayer *pPlayer = GET_PLAYER_POINTER(pEntity);
if (!pPlayer->bot)
{
pPlayer->PutInServer();
++g_players_num;
executeForwards(FF_ClientPutInServer, static_cast<cell>(pPlayer->index));
}
RETURN_META(MRES_IGNORED);
}
2004-01-31 20:56:22 +00:00
void C_ClientUserInfoChanged_Post(edict_t *pEntity, char *infobuffer)
{
CPlayer *pPlayer = GET_PLAYER_POINTER(pEntity);
executeForwards(FF_ClientInfoChanged, static_cast<cell>(pPlayer->index));
2005-09-10 20:09:14 +00:00
const char* name = INFOKEY_VALUE(infobuffer, "name");
2004-01-31 20:56:22 +00:00
// Emulate bot connection and putinserver
if (pPlayer->ingame)
{
2005-09-16 23:48:51 +00:00
pPlayer->name.assign(name); // Make sure player have name up to date
}
2005-09-10 20:09:14 +00:00
else if (pPlayer->IsBot())
{
pPlayer->Connect(name, "127.0.0.1"/*CVAR_GET_STRING("net_address")*/);
2004-01-31 20:56:22 +00:00
executeForwards(FF_ClientConnect, static_cast<cell>(pPlayer->index));
2004-01-31 20:56:22 +00:00
pPlayer->Authorize();
executeForwards(FF_ClientAuthorized, static_cast<cell>(pPlayer->index));
2004-01-31 20:56:22 +00:00
pPlayer->PutInServer();
++g_players_num;
2004-01-31 20:56:22 +00:00
executeForwards(FF_ClientPutInServer, static_cast<cell>(pPlayer->index));
}
2004-01-31 20:56:22 +00:00
RETURN_META(MRES_IGNORED);
2004-01-31 20:56:22 +00:00
}
void C_ClientCommand(edict_t *pEntity)
2005-08-17 17:07:41 +00:00
{
CPlayer *pPlayer = GET_PLAYER_POINTER(pEntity);
2005-09-16 23:48:51 +00:00
META_RES result = MRES_IGNORED;
cell ret = 0;
2005-09-16 23:48:51 +00:00
const char* cmd = CMD_ARGV(0);
const char* arg = CMD_ARGV(1);
// Handle "amxx" if not on listenserver
if (IS_DEDICATED_SERVER())
{
if (cmd && stricmp(cmd, "amxx") == 0)
{
// Print version
static char buf[1024];
2005-09-16 23:48:51 +00:00
sprintf(buf, "%s %s\n", Plugin_info.name, Plugin_info.version);
CLIENT_PRINT(pEntity, print_console, buf);
sprintf(buf, "Authors: %s (%s)\n", "Felix \"SniperBeamer\" Geyer, David \"BAILOPAN\" Anderson, Pavol \"PM OnoTo\" Marko, Jonny \"Got His Gun\" Bergstrom, and Lukasz \"SidLuke\" Wlasinski.", Plugin_info.url);
CLIENT_PRINT(pEntity, print_console, buf);
sprintf(buf, "Compiled: %s\n", __DATE__ ", " __TIME__);
CLIENT_PRINT(pEntity, print_console, buf);
2004-11-10 05:38:23 +00:00
#ifdef JIT
sprintf(buf, "Core mode: JIT\n");
2004-11-10 05:38:23 +00:00
#else
#ifdef ASM32
sprintf(buf, "Core mode: ASM\n");
2004-11-10 05:38:23 +00:00
#else
sprintf(buf, "Core mode: Normal\n");
2004-11-10 05:38:23 +00:00
#endif
#endif
CLIENT_PRINT(pEntity, print_console, buf);
RETURN_META(MRES_SUPERCEDE);
}
}
2004-01-31 20:56:22 +00:00
if (executeForwards(FF_ClientCommand, static_cast<cell>(pPlayer->index)) > 0)
RETURN_META(MRES_SUPERCEDE);
2004-01-31 20:56:22 +00:00
/* check for command and if needed also for first argument and call proper function */
2004-01-31 20:56:22 +00:00
CmdMngr::iterator aa = g_commands.clcmdprefixbegin(cmd);
2005-09-16 23:48:51 +00:00
if (!aa)
aa = g_commands.clcmdbegin();
2004-01-31 20:56:22 +00:00
while (aa)
{
if ((*aa).matchCommandLine(cmd, arg) && (*aa).getPlugin()->isExecutable((*aa).getFunction()))
{
ret = executeForwards((*aa).getFunction(), static_cast<cell>(pPlayer->index),
static_cast<cell>((*aa).getFlags()), static_cast<cell>((*aa).getId()));
if (ret & 2) result = MRES_SUPERCEDE;
if (ret & 1) RETURN_META(MRES_SUPERCEDE);
}
++aa;
}
2004-01-31 20:56:22 +00:00
/* check menu commands */
2004-01-31 20:56:22 +00:00
2005-09-10 20:09:14 +00:00
if (!strcmp(cmd, "menuselect"))
{
int pressed_key = atoi(arg) - 1;
int bit_key = (1<<pressed_key);
2004-01-31 20:56:22 +00:00
if (pPlayer->keys & bit_key)
{
2005-11-17 23:04:43 +00:00
if ((pPlayer->menu > 0 && !pPlayer->vgui) && (gpGlobals->time > pPlayer->menuexpire))
2005-11-13 20:33:30 +00:00
{
pPlayer->menu = 0;
pPlayer->keys = 0;
RETURN_META(MRES_SUPERCEDE);
}
int menuid = pPlayer->menu;
pPlayer->menu = 0;
2004-01-31 20:56:22 +00:00
MenuMngr::iterator a = g_menucmds.begin();
2004-01-31 20:56:22 +00:00
while (a)
{
if ((*a).matchCommand(menuid, bit_key) && (*a).getPlugin()->isExecutable((*a).getFunction()))
{
if (pPlayer->newmenu != -1)
{
int menu = pPlayer->newmenu;
pPlayer->newmenu = -1;
if (menu >= 0 && menu < (int)g_NewMenus.size())
{
Menu *pMenu = g_NewMenus[menu];
int item = pMenu->PagekeyToItem(pPlayer->page, pressed_key);
ret = executeForwards((*a).getFunction(), static_cast<cell>(pPlayer->index),
static_cast<cell>(menu), static_cast<cell>(item));
2005-09-16 23:48:51 +00:00
if (ret & 2)
result = MRES_SUPERCEDE;
else if (ret & 1)
RETURN_META(MRES_SUPERCEDE);
else
{
if (item == MENU_BACK)
{
2005-09-16 23:48:51 +00:00
pMenu->Display(pPlayer->index, pPlayer->page - 1);
2005-09-10 20:09:14 +00:00
}
else if (item == MENU_MORE)
{
2005-09-10 20:09:14 +00:00
pMenu->Display(pPlayer->index, pPlayer->page + 1);
}
else if (item == MENU_EXIT)
{
//nothing
}
}
}
} else {
ret = executeForwards((*a).getFunction(), static_cast<cell>(pPlayer->index),
static_cast<cell>(pressed_key), 0);
if (ret & 2) result = MRES_SUPERCEDE;
if (ret & 1) RETURN_META(MRES_SUPERCEDE);
}
}
++a;
}
}
}
/* check for PLUGIN_HANDLED_MAIN and block hl call if needed */
RETURN_META(result);
2004-01-31 20:56:22 +00:00
}
void C_StartFrame_Post(void)
2005-08-17 17:07:41 +00:00
{
if (g_auth_time < gpGlobals->time)
{
g_auth_time = gpGlobals->time + 0.7f;
CList<CPlayer*>::iterator a = g_auth.begin();
while (a)
{
const char* auth = GETPLAYERAUTHID((*a)->pEdict);
2004-01-31 20:56:22 +00:00
if ((auth == 0) || (*auth == 0))
{
a.remove();
continue;
}
2004-01-31 20:56:22 +00:00
if (strcmp(auth, "STEAM_ID_PENDING"))
{
(*a)->Authorize();
executeForwards(FF_ClientAuthorized, static_cast<cell>((*a)->index));
a.remove();
2005-09-16 23:48:51 +00:00
continue;
}
++a;
}
}
2004-01-31 20:56:22 +00:00
#ifdef MEMORY_TEST
if (g_memreport_enabled && g_next_memreport_time <= gpGlobals->time)
{
g_next_memreport_time = gpGlobals->time + MEMREPORT_INTERVAL;
if (g_memreport_count == 0)
{
// make new directory
time_t td;
time(&td);
tm *curTime = localtime(&td);
2005-09-16 23:48:51 +00:00
int i = 0;
2004-05-03 19:40:49 +00:00
#ifdef __linux__
2004-09-02 02:16:38 +00:00
mkdir(build_pathname("%s/memreports", get_localinfo("amxx_basedir", "addons/amxmodx")), 0700);
2004-05-03 19:40:49 +00:00
#else
2004-09-02 02:16:38 +00:00
mkdir(build_pathname("%s/memreports", get_localinfo("amxx_basedir", "addons/amxmodx")));
2004-05-03 19:40:49 +00:00
#endif
while (true)
{
char buffer[256];
2004-09-02 02:16:38 +00:00
sprintf(buffer, "%s/memreports/D%02d%02d%03d", get_localinfo("amxx_basedir", "addons/amxmodx"), curTime->tm_mon + 1, curTime->tm_mday, i);
2004-05-03 19:40:49 +00:00
#ifdef __linux__
2004-08-13 08:46:04 +00:00
mkdir(build_pathname("%s", g_log_dir.c_str()), 0700);
2004-05-03 19:40:49 +00:00
if (mkdir(build_pathname(buffer), 0700) < 0)
#else
2004-08-13 08:46:04 +00:00
mkdir(build_pathname("%s", g_log_dir.c_str()));
if (mkdir(build_pathname(buffer)) < 0)
2004-05-03 19:40:49 +00:00
#endif
{
if (errno == EEXIST)
{
// good
++i;
continue;
} else {
// bad
g_memreport_enabled = false;
AMXXLOG_Log("[AMXX] Fatal error: Can't create directory for memreport files (%s)", buffer);
break;
}
}
2004-08-13 08:46:04 +00:00
g_memreport_dir.assign(buffer);
// g_memreport_dir should be valid now
break;
}
}
2005-09-16 23:48:51 +00:00
m_dumpMemoryReport(build_pathname("%s/r%03d.txt", g_memreport_dir.c_str(), g_memreport_count));
AMXXLOG_Log("Memreport #%d created (file \"%s/r%03d.txt\") (interval %f)", g_memreport_count + 1, g_memreport_dir.c_str(), g_memreport_count, MEMREPORT_INTERVAL);
2005-09-16 23:48:51 +00:00
g_memreport_count++;
}
#endif // MEMORY_TEST
2004-01-31 20:56:22 +00:00
if (g_task_time > gpGlobals->time)
RETURN_META(MRES_IGNORED);
2004-01-31 20:56:22 +00:00
g_task_time = gpGlobals->time + 0.1f;
g_tasksMngr.startFrame();
2005-08-27 23:00:44 +00:00
RETURN_META(MRES_IGNORED);
2004-01-31 20:56:22 +00:00
}
2005-08-17 17:07:41 +00:00
void C_MessageBegin_Post(int msg_dest, int msg_type, const float *pOrigin, edict_t *ed)
{
if (ed)
{
if (gmsgBattery == msg_type && g_bmod_cstrike)
{
void* ptr = GET_PRIVATE(ed);
2004-01-31 20:56:22 +00:00
#ifdef __linux__
int *z = (int*)ptr + 0x171;
2004-01-31 20:56:22 +00:00
#else
int *z = (int*)ptr + 0x16C;
2004-01-31 20:56:22 +00:00
#endif
int stop = (int)ed->v.armorvalue;
2005-09-16 23:48:51 +00:00
*z = stop;
ed->v.armorvalue = (float)stop;
}
mPlayerIndex = ENTINDEX(ed);
mPlayer = GET_PLAYER_POINTER_I(mPlayerIndex);
} else {
mPlayerIndex = 0;
mPlayer = 0;
}
if (msg_type < 0 || msg_type >= MAX_REG_MSGS)
msg_type = 0;
2004-01-31 20:56:22 +00:00
mState = 0;
2005-09-16 23:48:51 +00:00
function = modMsgs[msg_type];
endfunction = modMsgsEnd[msg_type];
g_events.parserInit(msg_type, &gpGlobals->time, mPlayer, mPlayerIndex);
RETURN_META(MRES_IGNORED);
2004-01-31 20:56:22 +00:00
}
void C_WriteByte_Post(int iValue)
2005-08-17 17:07:41 +00:00
{
g_events.parseValue(iValue);
if (function) (*function)((void *)&iValue);
RETURN_META(MRES_IGNORED);
2004-01-31 20:56:22 +00:00
}
void C_WriteChar_Post(int iValue)
2005-08-17 17:07:41 +00:00
{
g_events.parseValue(iValue);
if (function) (*function)((void *)&iValue);
RETURN_META(MRES_IGNORED);
2004-01-31 20:56:22 +00:00
}
2005-08-17 17:07:41 +00:00
void C_WriteShort_Post(int iValue)
{
g_events.parseValue(iValue);
if (function) (*function)((void *)&iValue);
RETURN_META(MRES_IGNORED);
2004-01-31 20:56:22 +00:00
}
void C_WriteLong_Post(int iValue)
2005-08-17 17:07:41 +00:00
{
g_events.parseValue(iValue);
if (function) (*function)((void *)&iValue);
RETURN_META(MRES_IGNORED);
2004-01-31 20:56:22 +00:00
}
2005-08-17 17:07:41 +00:00
void C_WriteAngle_Post(float flValue)
{
g_events.parseValue(flValue);
if (function) (*function)((void *)&flValue);
RETURN_META(MRES_IGNORED);
2004-01-31 20:56:22 +00:00
}
2005-08-17 17:07:41 +00:00
void C_WriteCoord_Post(float flValue)
{
g_events.parseValue(flValue);
if (function) (*function)((void *)&flValue);
RETURN_META(MRES_IGNORED);
2004-01-31 20:56:22 +00:00
}
2005-08-17 17:07:41 +00:00
void C_WriteString_Post(const char *sz)
{
g_events.parseValue(sz);
if (function) (*function)((void *)sz);
RETURN_META(MRES_IGNORED);
2004-01-31 20:56:22 +00:00
}
2005-08-17 17:07:41 +00:00
void C_WriteEntity_Post(int iValue)
{
g_events.parseValue(iValue);
if (function) (*function)((void *)&iValue);
RETURN_META(MRES_IGNORED);
2004-01-31 20:56:22 +00:00
}
2005-08-17 17:07:41 +00:00
void C_MessageEnd_Post(void)
{
g_events.executeEvents();
if (endfunction) (*endfunction)(NULL);
RETURN_META(MRES_IGNORED);
2004-01-31 20:56:22 +00:00
}
2004-05-28 11:26:05 +00:00
const char *C_Cmd_Args(void)
2004-05-28 11:26:05 +00:00
{
// if the global "fake" flag is set, which means that engclient_cmd was used, supercede the function
if (g_fakecmd.fake)
RETURN_META_VALUE(MRES_SUPERCEDE, (g_fakecmd.argc > 1) ? g_fakecmd.args : g_fakecmd.argv[0]);
2004-05-28 11:26:05 +00:00
// otherwise ignore it
RETURN_META_VALUE(MRES_IGNORED, NULL);
2004-01-31 20:56:22 +00:00
}
2004-05-28 11:26:05 +00:00
const char *C_Cmd_Argv(int argc)
{
// if the global "fake" flag is set, which means that engclient_cmd was used, supercede the function
if (g_fakecmd.fake)
RETURN_META_VALUE(MRES_SUPERCEDE, (argc < 3) ? g_fakecmd.argv[argc] : "");
2004-05-28 11:26:05 +00:00
// otherwise ignore it
RETURN_META_VALUE(MRES_IGNORED, NULL);
2004-01-31 20:56:22 +00:00
}
int C_Cmd_Argc(void)
2004-05-28 11:26:05 +00:00
{
// if the global "fake" flag is set, which means that engclient_cmd was used, supercede the function
if (g_fakecmd.fake)
RETURN_META_VALUE(MRES_SUPERCEDE, g_fakecmd.argc);
2004-05-28 11:26:05 +00:00
// otherwise ignore it
RETURN_META_VALUE(MRES_IGNORED, 0);
2004-01-31 20:56:22 +00:00
}
// Grenade has been thrown.
// Only here we may find out who is an owner.
void C_SetModel(edict_t *e, const char *m)
2005-08-17 17:07:41 +00:00
{
if (e->v.owner && m[7]=='w' && m[8]=='_' && m[9]=='h')
g_grenades.put(e, 1.75, 4, GET_PLAYER_POINTER(e->v.owner));
RETURN_META(MRES_IGNORED);
2004-01-31 20:56:22 +00:00
}
// Save at what part of body a player is aiming
2005-08-17 17:07:41 +00:00
void C_TraceLine_Post(const float *v1, const float *v2, int fNoMonsters, edict_t *e, TraceResult *ptr)
{
if (e && (e->v.flags & (FL_CLIENT | FL_FAKECLIENT)))
{
CPlayer* pPlayer = GET_PLAYER_POINTER(e);
if (ptr->pHit && (ptr->pHit->v.flags & (FL_CLIENT | FL_FAKECLIENT)))
pPlayer->aiming = ptr->iHitgroup;
pPlayer->lastTrace = pPlayer->thisTrace;
pPlayer->thisTrace = ptr->vecEndPos;
}
RETURN_META(MRES_IGNORED);
2004-01-31 20:56:22 +00:00
}
2004-05-28 11:26:05 +00:00
void C_AlertMessage_Post(ALERT_TYPE atype, char *szFmt, ...)
{
if (atype != at_logged)
RETURN_META(MRES_IGNORED);
/* There are also more messages but we want only logs
2004-05-28 11:26:05 +00:00
at_notice,
at_console, // same as at_notice, but forces a ConPrintf, not a message box
at_aiconsole, // same as at_console, but only shown if developer level is 2!
at_warning,
at_error,
at_logged // Server print to console ( only in multiplayer games ).
*/
// execute logevents and plugin_log forward
if (g_logevents.logEventsExist() || FF_PluginLog >= 0)
{
2004-05-28 11:26:05 +00:00
va_list logArgPtr;
2005-09-16 23:48:51 +00:00
va_start(logArgPtr, szFmt);
g_logevents.setLogString(szFmt, logArgPtr);
2005-09-16 23:48:51 +00:00
va_end(logArgPtr);
g_logevents.parseLogString();
2004-05-28 11:26:05 +00:00
if (g_logevents.logEventsExist())
g_logevents.executeLogEvents();
2004-10-03 07:04:08 +00:00
cell retVal = executeForwards(FF_PluginLog);
2004-10-03 07:04:08 +00:00
if (retVal)
RETURN_META(MRES_HANDLED);
}
2004-01-31 20:56:22 +00:00
2004-05-28 11:26:05 +00:00
RETURN_META(MRES_IGNORED);
2004-01-31 20:56:22 +00:00
}
void C_CvarValue2(const edict_t *pEdict, int requestId, const char *cvar, const char *value)
2005-08-27 23:00:44 +00:00
{
CPlayer *pPlayer = GET_PLAYER_POINTER(pEdict);
if (pPlayer->queries.empty())
2005-08-27 23:00:44 +00:00
RETURN_META(MRES_IGNORED);
List<ClientCvarQuery_Info *>::iterator iter, end=pPlayer->queries.end();
ClientCvarQuery_Info *info;
for (iter=pPlayer->queries.begin(); iter!=end; iter++)
2005-08-27 23:00:44 +00:00
{
info = (*iter);
if ( info->requestId == requestId )
{
if (info->paramLen)
{
cell arr = prepareCellArray(info->params, info->paramLen);
executeForwards(info->resultFwd, static_cast<cell>(ENTINDEX(pEdict)),
cvar, value, arr);
} else {
executeForwards(info->resultFwd, static_cast<cell>(ENTINDEX(pEdict)),
cvar, value);
}
unregisterSPForward(info->resultFwd);
pPlayer->queries.erase(iter);
delete [] info->params;
delete info;
break;
}
2005-08-27 23:00:44 +00:00
}
RETURN_META(MRES_HANDLED);
2005-08-27 23:00:44 +00:00
}
bool m_NeedsP = false;
C_DLLEXPORT int Meta_Query(char *ifvers, plugin_info_t **pPlugInfo, mutil_funcs_t *pMetaUtilFuncs)
{
2005-09-16 23:48:51 +00:00
gpMetaUtilFuncs = pMetaUtilFuncs;
*pPlugInfo = &Plugin_info;
int mmajor = 0, mminor = 0, pmajor = 0, pminor = 0;
sscanf(ifvers, "%d:%d", &mmajor, &mminor);
sscanf(META_INTERFACE_VERSION, "%d:%d", &pmajor, &pminor);
g_mm_vers = mminor;
if (strcmp(ifvers, Plugin_info.ifvers))
{
if (pmajor > mmajor)
{
LOG_ERROR(PLID, "metamod version is too old for this plugin; update metamod");
return (FALSE);
} else if (pmajor < mmajor) {
LOG_ERROR(PLID, "metamod version is incompatible with this plugin; please find a newer version of this plugin");
return (FALSE);
} else if (pmajor == mmajor) {
//wait it out... pminor should never be greater than 11 as of 1.65
// so mminor should be 10 at most.
if (pminor > mminor)
{
//we need at least Metamod-p now
if (mminor == 10)
{
//wait for P extensions
g_NeedsP = true;
LOG_MESSAGE(PLID, "warning! old metamod detecting, expecting metamod-p");
} else {
//if we have less than 1.17, there's no hope.
LOG_ERROR(PLID, "metamod version is incompatible with this plugin; please find a newer version of this plugin");
return FALSE;
}
} else if (pminor < mminor) {
//if we have 1.19, tell MM that we're okay.
//NOTE: ifvers 5:12 did not exist.
if (mminor == 13)
{
Plugin_info.ifvers = "5:13";
}
}
}
}
if (!g_NeedsP)
g_IsNewMM = true;
2005-02-16 20:36:04 +00:00
// We can set this to null here because Meta_PExtGiveFnptrs is called after this
gpMetaPExtFuncs = NULL;
2005-02-16 20:36:04 +00:00
// :NOTE: Don't call modules query here (g_FakeMeta.Meta_Query), because we don't know modules yet. Do it in Meta_Attach
return (TRUE);
2004-01-31 20:56:22 +00:00
}
2005-02-16 20:36:04 +00:00
// evilspy's patch for mm-p ext support
// this is called right after Meta_Query
C_DLLEXPORT int Meta_PExtGiveFnptrs(int interfaceVersion, pextension_funcs_t *pMetaPExtFuncs)
{
if (interfaceVersion < META_PEXT_VERSION)
{
return (META_PEXT_VERSION);
2005-02-16 20:36:04 +00:00
}
2005-02-16 20:36:04 +00:00
gpMetaPExtFuncs = pMetaPExtFuncs;
return (META_PEXT_VERSION);
2005-02-16 20:36:04 +00:00
}
2004-01-31 20:56:22 +00:00
static META_FUNCTIONS gMetaFunctionTable;
C_DLLEXPORT int Meta_Attach(PLUG_LOADTIME now, META_FUNCTIONS *pFunctionTable, meta_globals_t *pMGlobals, gamedll_funcs_t *pGamedllFuncs)
{
if (now > Plugin_info.loadable)
{
LOG_ERROR(PLID, "Can't load plugin right now");
return (FALSE);
}
if (g_NeedsP && !gpMetaPExtFuncs)
{
LOG_ERROR(PLID, "You need Metamod-P or Metamod-1.18+ to use AMX Mod X %s!", AMX_VERSION);
return (FALSE);
}
2005-09-16 23:48:51 +00:00
gpMetaGlobals = pMGlobals;
gMetaFunctionTable.pfnGetEntityAPI2 = GetEntityAPI2;
gMetaFunctionTable.pfnGetEntityAPI2_Post = GetEntityAPI2_Post;
gMetaFunctionTable.pfnGetEngineFunctions = GetEngineFunctions;
gMetaFunctionTable.pfnGetEngineFunctions_Post = GetEngineFunctions_Post;
gMetaFunctionTable.pfnGetNewDLLFunctions = GetNewDLLFunctions;
memcpy(pFunctionTable, &gMetaFunctionTable, sizeof(META_FUNCTIONS));
gpGamedllFuncs=pGamedllFuncs;
Module_CacheFunctions();
CVAR_REGISTER(&init_amxmodx_version);
CVAR_REGISTER(&init_amxmodx_modules);
CVAR_REGISTER(&init_amxmodx_debug);
2006-01-24 18:47:08 +00:00
CVAR_REGISTER(&init_amxmodx_mldebug);
2005-09-16 23:48:51 +00:00
amxmodx_version = CVAR_GET_POINTER(init_amxmodx_version.name);
2005-09-16 23:48:51 +00:00
REG_SVR_COMMAND("amxx", amx_command);
char gameDir[512];
GET_GAME_DIR(gameDir);
char *a = gameDir;
int i = 0;
while (gameDir[i])
if (gameDir[i++] == '/')
a = &gameDir[i];
g_mod_name.assign(a);
2005-09-16 23:48:51 +00:00
if (g_mod_name.compare("cstrike") == 0 || g_mod_name.compare("czero") == 0 || g_mod_name.compare("dod") == 0)
g_coloredmenus = true;
else
g_coloredmenus = false;
// ###### Print short GPL
print_srvconsole("\n AMX Mod X version %s Copyright (c) 2004-2006 AMX Mod X Development Team \n"
" AMX Mod X comes with ABSOLUTELY NO WARRANTY; for details type `amxx gpl'.\n", AMX_VERSION);
print_srvconsole(" This is free software and you are welcome to redistribute it under \n"
" certain conditions; type 'amxx gpl' for details.\n \n");
// ###### Load custom path configuration
Vault amx_config;
amx_config.setSource(build_pathname("%s", get_localinfo("amxx_cfg", "addons/amxmodx/configs/core.ini")));
if (amx_config.loadVault())
{
Vault::iterator a = amx_config.begin();
while (a != amx_config.end())
{
SET_LOCALINFO((char*)a.key().c_str(), (char*)a.value().c_str());
++a;
}
amx_config.clear();
}
// ###### Initialize logging here
g_log_dir.assign(get_localinfo("amxx_logs", "addons/amxmodx/logs"));
// ###### Now attach metamod modules
// This will also call modules Meta_Query and Meta_Attach functions
loadModules(get_localinfo("amxx_modules", "addons/amxmodx/configs/modules.ini"), now);
2004-01-31 20:56:22 +00:00
return (TRUE);
2004-01-31 20:56:22 +00:00
}
C_DLLEXPORT int Meta_Detach(PLUG_LOADTIME now, PL_UNLOAD_REASON reason)
{
if (now > Plugin_info.unloadable && reason != PNL_CMD_FORCED)
{
LOG_ERROR(PLID, "Can't unload plugin right now");
return (FALSE);
}
g_auth.clear();
g_forwards.clear();
g_commands.clear();
g_forcemodels.clear();
g_forcesounds.clear();
g_forcegeneric.clear();
g_grenades.clear();
g_tasksMngr.clear();
g_logevents.clearLogEvents();
g_events.clearEvents();
g_menucmds.clear();
ClearMenus();
g_vault.clear();
g_xvars.clear();
g_plugins.clear();
g_cvars.clear();
detachModules();
g_log.CloseFile();
2004-07-08 16:02:01 +00:00
Module_UncacheFunctions();
return (TRUE);
2004-01-31 20:56:22 +00:00
}
#ifdef __linux__
// linux prototype
C_DLLEXPORT void GiveFnptrsToDll(enginefuncs_t* pengfuncsFromEngine, globalvars_t *pGlobals)
{
#else
#ifdef _MSC_VER
// MSVC: Simulate __stdcall calling convention
C_DLLEXPORT __declspec(naked) void GiveFnptrsToDll(enginefuncs_t* pengfuncsFromEngine, globalvars_t *pGlobals)
{
__asm // Prolog
{
// Save ebp
push ebp
// Set stack frame pointer
mov ebp, esp
// Allocate space for local variables
// The MSVC compiler gives us the needed size in __LOCAL_SIZE.
sub esp, __LOCAL_SIZE
// Push registers
push ebx
push esi
push edi
}
#else // _MSC_VER
#ifdef __GNUC__
// GCC can also work with this
C_DLLEXPORT void __stdcall GiveFnptrsToDll(enginefuncs_t* pengfuncsFromEngine, globalvars_t *pGlobals)
{
#else // __GNUC__
// compiler not known
#error There is no support (yet) for your compiler. Please use MSVC or GCC compilers or contact the AMX Mod X dev team.
#endif // __GNUC__
#endif // _MSC_VER
#endif // __linux__
// ** Function core <--
memcpy(&g_engfuncs, pengfuncsFromEngine, sizeof(enginefuncs_t));
gpGlobals = pGlobals;
// --> ** Function core
#ifdef _MSC_VER
// Epilog
if (sizeof(int*) == 8)
{ // 64 bit
__asm
{
// Pop registers
pop edi
pop esi
pop ebx
// Restore stack frame pointer
mov esp, ebp
// Restore ebp
pop ebp
// 2 * sizeof(int*) = 16 on 64 bit
ret 16
}
}
else
{ // 32 bit
__asm
{
// Pop registers
pop edi
pop esi
pop ebx
// Restore stack frame pointer
mov esp, ebp
// Restore ebp
pop ebp
// 2 * sizeof(int*) = 8 on 32 bit
ret 8
}
}
#endif // #ifdef _MSC_VER
2004-01-31 20:56:22 +00:00
}
DLL_FUNCTIONS gFunctionTable;
C_DLLEXPORT int GetEntityAPI2(DLL_FUNCTIONS *pFunctionTable, int *interfaceVersion)
{
memset(&gFunctionTable, 0, sizeof(DLL_FUNCTIONS));
gFunctionTable.pfnSpawn = C_Spawn;
gFunctionTable.pfnClientCommand = C_ClientCommand;
gFunctionTable.pfnServerDeactivate = C_ServerDeactivate;
gFunctionTable.pfnClientDisconnect = C_ClientDisconnect;
gFunctionTable.pfnInconsistentFile = C_InconsistentFile;
gFunctionTable.pfnServerActivate = C_ServerActivate;
memcpy(pFunctionTable, &gFunctionTable, sizeof(DLL_FUNCTIONS));
return 1;
2004-01-31 20:56:22 +00:00
}
DLL_FUNCTIONS gFunctionTable_Post;
C_DLLEXPORT int GetEntityAPI2_Post(DLL_FUNCTIONS *pFunctionTable, int *interfaceVersion)
{
memset(&gFunctionTable_Post, 0, sizeof(DLL_FUNCTIONS));
gFunctionTable_Post.pfnClientPutInServer = C_ClientPutInServer_Post;
gFunctionTable_Post.pfnClientUserInfoChanged = C_ClientUserInfoChanged_Post;
gFunctionTable_Post.pfnServerActivate = C_ServerActivate_Post;
gFunctionTable_Post.pfnClientConnect = C_ClientConnect_Post;
gFunctionTable_Post.pfnStartFrame = C_StartFrame_Post;
gFunctionTable_Post.pfnServerDeactivate = C_ServerDeactivate_Post;
memcpy(pFunctionTable, &gFunctionTable_Post, sizeof(DLL_FUNCTIONS));
return 1;
2004-01-31 20:56:22 +00:00
}
enginefuncs_t meta_engfuncs;
C_DLLEXPORT int GetEngineFunctions(enginefuncs_t *pengfuncsFromEngine, int *interfaceVersion)
{
memset(&meta_engfuncs, 0, sizeof(enginefuncs_t));
2005-09-10 20:09:14 +00:00
if (stricmp(g_mod_name.c_str(), "cstrike") == 0 || stricmp(g_mod_name.c_str(), "czero") == 0)
{
meta_engfuncs.pfnSetModel = C_SetModel;
g_bmod_cstrike = true;
} else {
g_bmod_cstrike = false;
2005-09-10 20:09:14 +00:00
g_bmod_dod = !stricmp(g_mod_name.c_str(), "dod");
}
meta_engfuncs.pfnCmd_Argc = C_Cmd_Argc;
meta_engfuncs.pfnCmd_Argv = C_Cmd_Argv;
meta_engfuncs.pfnCmd_Args = C_Cmd_Args;
meta_engfuncs.pfnPrecacheModel = C_PrecacheModel;
meta_engfuncs.pfnPrecacheSound = C_PrecacheSound;
2004-01-31 20:56:22 +00:00
memcpy(pengfuncsFromEngine, &meta_engfuncs, sizeof(enginefuncs_t));
return 1;
2004-01-31 20:56:22 +00:00
}
enginefuncs_t meta_engfuncs_post;
C_DLLEXPORT int GetEngineFunctions_Post(enginefuncs_t *pengfuncsFromEngine, int *interfaceVersion)
{
memset(&meta_engfuncs_post, 0, sizeof(enginefuncs_t));
meta_engfuncs_post.pfnTraceLine = C_TraceLine_Post;
meta_engfuncs_post.pfnMessageBegin = C_MessageBegin_Post;
meta_engfuncs_post.pfnMessageEnd = C_MessageEnd_Post;
meta_engfuncs_post.pfnWriteByte = C_WriteByte_Post;
meta_engfuncs_post.pfnWriteChar = C_WriteChar_Post;
meta_engfuncs_post.pfnWriteShort = C_WriteShort_Post;
meta_engfuncs_post.pfnWriteLong = C_WriteLong_Post;
meta_engfuncs_post.pfnWriteAngle = C_WriteAngle_Post;
meta_engfuncs_post.pfnWriteCoord = C_WriteCoord_Post;
meta_engfuncs_post.pfnWriteString = C_WriteString_Post;
meta_engfuncs_post.pfnWriteEntity = C_WriteEntity_Post;
meta_engfuncs_post.pfnAlertMessage = C_AlertMessage_Post;
meta_engfuncs_post.pfnRegUserMsg = C_RegUserMsg_Post;
memcpy(pengfuncsFromEngine, &meta_engfuncs_post, sizeof(enginefuncs_t));
return 1;
2004-01-31 20:56:22 +00:00
}
//quick hack - disable all newdll stuff for AMD64
// until VALVe gets their act together!
#if !defined AMD64
NEW_DLL_FUNCTIONS gNewDLLFunctionTable;
C_DLLEXPORT int GetNewDLLFunctions(NEW_DLL_FUNCTIONS *pNewFunctionTable, int *interfaceVersion)
{
memset(&gNewDLLFunctionTable, 0, sizeof(NEW_DLL_FUNCTIONS));
2005-08-27 23:00:44 +00:00
// default metamod does not call this if the gamedll doesn't provide it
g_NewDLL_Available = true;
// If pfnQueryClientCvarValue is not available, the newdllfunctions table will probably
// not have the pfnCvarValue member -> better don't write there to avoid corruption
if (g_mm_vers >= 13)
{
if (g_engfuncs.pfnQueryClientCvarValue2)
gNewDLLFunctionTable.pfnCvarValue2 = C_CvarValue2;
memcpy(pNewFunctionTable, &gNewDLLFunctionTable, sizeof(NEW_DLL_FUNCTIONS));
} else {
memcpy(pNewFunctionTable, &gNewDLLFunctionTable, sizeof(NEW_DLL_FUNCTIONS) - sizeof(void *));
}
2005-08-27 23:00:44 +00:00
return 1;
}
#endif