Added forced yb_csdm_mode.

Do not export functions that aren't needed for plugin loading.
This commit is contained in:
jeefo 2019-08-29 16:24:24 +03:00
commit 296d3a3637
8 changed files with 163 additions and 108 deletions

View file

@ -35,11 +35,13 @@ CR_NAMESPACE_BEGIN
#endif #endif
// configure macroses // configure macroses
#define CR_LINKAGE_C extern "C"
#if defined(CR_WINDOWS) #if defined(CR_WINDOWS)
# define CR_EXPORT extern "C" __declspec (dllexport) # define CR_EXPORT CR_LINKAGE_C __declspec (dllexport)
# define CR_STDCALL __stdcall # define CR_STDCALL __stdcall
#elif defined(CR_LINUX) || defined(CR_OSX) #elif defined(CR_LINUX) || defined(CR_OSX)
# define CR_EXPORT extern "C" __attribute__((visibility("default"))) # define CR_EXPORT CR_LINKAGE_C __attribute__((visibility("default")))
# define CR_STDCALL # define CR_STDCALL
#else #else
# error "Can't configure export macros. Compiler unrecognized." # error "Can't configure export macros. Compiler unrecognized."

View file

@ -171,7 +171,7 @@ public:
bool postload (); bool postload ();
// detects if csdm mod is in use // detects if csdm mod is in use
void detectDeathmatch (); void applyGameModes ();
// executes stuff every 1 second // executes stuff every 1 second
void slowFrame (); void slowFrame ();

View file

@ -121,7 +121,7 @@ public:
~MessageDispatcher () = default; ~MessageDispatcher () = default;
public: public:
void registerMessage (const String &name, int32 id); int32 add (const String &name, int32 id);
void start (edict_t *ent, int32 type); void start (edict_t *ent, int32 type);
void stop (); void stop ();

View file

@ -11,6 +11,21 @@
// until hook code will be compatible with ARM, it's here // until hook code will be compatible with ARM, it's here
#if defined (CR_ANDROID) && defined(CR_ARCH_ARM) #if defined (CR_ANDROID) && defined(CR_ARCH_ARM)
CR_EXPORT int Server_GetBlendingInterface (int version, struct sv_blending_interface_s **ppinterface, struct engine_studio_api_s *pstudio, float *rotationmatrix, float *bonetransform) {
// this function synchronizes the studio model animation blending interface (i.e, what parts
// of the body move, which bones, which hitboxes and how) between the server and the game DLL.
// some MODs can be using a different hitbox scheme than the standard one.
auto api_GetBlendingInterface = game.lib ().resolve <int (*) (int, struct sv_blending_interface_s **, struct engine_studio_api_s *, float *, float *)> (__FUNCTION__);
if (!api_GetBlendingInterface) {
logger.error ("Could not resolve symbol \"%s\" in the game dll. Continuing...", __FUNCTION__);
return FALSE;
}
return api_GetBlendingInterface (version, ppinterface, pstudio, rotationmatrix, bonetransform);
}
void android_LinkEntity (EntityFunction &addr, const char *name, entvars_t *pev) { void android_LinkEntity (EntityFunction &addr, const char *name, entvars_t *pev) {
if (!addr) { if (!addr) {
addr = game.lib ().resolve <EntityFunction> (name); addr = game.lib ().resolve <EntityFunction> (name);

View file

@ -1295,11 +1295,14 @@ void Bot::buyStuff () {
const int *pref = conf.getWeaponPrefs (m_personality) + kNumWeapons; const int *pref = conf.getWeaponPrefs (m_personality) + kNumWeapons;
auto tab = conf.getRawWeapons (); auto tab = conf.getRawWeapons ();
bool isPistolMode = tab[25].teamStandard == -1 && tab[3].teamStandard == 2; const bool isPistolMode = tab[25].teamStandard == -1 && tab[3].teamStandard == 2;
bool teamEcoValid = bots.checkTeamEco (m_team); const bool teamEcoValid = bots.checkTeamEco (m_team);
// do this, because xash engine is not capable to run all the features goldsrc, but we have cs 1.6 on it, so buy table must be the same // do this, because xash engine is not capable to run all the features goldsrc, but we have cs 1.6 on it, so buy table must be the same
bool isOldGame = game.is (GameFlags::Legacy) && !game.is (GameFlags::Xash3D); const bool isOldGame = game.is (GameFlags::Legacy) && !game.is (GameFlags::Xash3D);
const bool hasDefaultPistols = (pev->weapons & (cr::bit (Weapon::USP) | cr::bit (Weapon::Glock18)));
const bool isFirstRound = m_moneyAmount == mp_startmoney.int_ ();
switch (m_buyState) { switch (m_buyState) {
case BuyState::PrimaryWeapon: // if no primary weapon and bot has some money, buy a primary weapon case BuyState::PrimaryWeapon: // if no primary weapon and bot has some money, buy a primary weapon
@ -1493,7 +1496,7 @@ void Bot::buyStuff () {
break; break;
case BuyState::SecondaryWeapon: // if bot has still some money, buy a better secondary weapon case BuyState::SecondaryWeapon: // if bot has still some money, buy a better secondary weapon
if (isPistolMode || (hasPrimaryWeapon () && (pev->weapons & (cr::bit (Weapon::USP) | cr::bit (Weapon::Glock18))) && m_moneyAmount > rg.int_ (7500, 9000))) { if (isPistolMode || (isFirstRound && hasDefaultPistols) || (hasDefaultPistols && bots.getLastWinner () != m_team) || (hasPrimaryWeapon () && hasDefaultPistols) && m_moneyAmount > rg.int_ (7500, 9000)) {
do { do {
pref--; pref--;

View file

@ -9,6 +9,8 @@
#include <yapb.h> #include <yapb.h>
ConVar yb_csdm_mode ("yb_csdm_mode", "0", "Enables or disables CSDM / FFA mode for bots.\nAllowed values: '0', '1', '2', '3'.\nIf '0', CSDM / FFA mode is auto-detected.\nIf '1', CSDM mode is enabled, but FFA is disabled.\nIf '2' CSDM and FFA mode is enabled.\nIf '3' CSDM and FFA mode is disabled.", true, 0.0f, 3.0f);
ConVar sv_skycolor_r ("sv_skycolor_r", nullptr, Var::NoRegister); ConVar sv_skycolor_r ("sv_skycolor_r", nullptr, Var::NoRegister);
ConVar sv_skycolor_g ("sv_skycolor_g", nullptr, Var::NoRegister); ConVar sv_skycolor_g ("sv_skycolor_g", nullptr, Var::NoRegister);
ConVar sv_skycolor_b ("sv_skycolor_b", nullptr, Var::NoRegister); ConVar sv_skycolor_b ("sv_skycolor_b", nullptr, Var::NoRegister);
@ -766,10 +768,34 @@ bool Game::postload () {
return false; return false;
} }
void Game::detectDeathmatch () { void Game::applyGameModes () {
if (!is (GameFlags::Metamod | GameFlags::ReGameDLL)) { if (!is (GameFlags::Metamod | GameFlags::ReGameDLL)) {
return; return;
} }
// handle cvar cases
switch (yb_csdm_mode.int_ ()) {
default:
case 0:
break;
// force CSDM mode
case 1:
m_gameFlags |= GameFlags::CSDM;
m_gameFlags &= ~GameFlags::FreeForAll;
return;
// force CSDM FFA mode
case 2:
m_gameFlags |= GameFlags::CSDM | GameFlags::FreeForAll;
return;
// force disable everything
case 3:
m_gameFlags &= ~(GameFlags::CSDM | GameFlags::FreeForAll);
return;
}
static auto dmActive = engfuncs.pfnCVarGetPointer ("csdm_active"); static auto dmActive = engfuncs.pfnCVarGetPointer ("csdm_active");
static auto freeForAll = engfuncs.pfnCVarGetPointer ("mp_freeforall"); static auto freeForAll = engfuncs.pfnCVarGetPointer ("mp_freeforall");
@ -810,7 +836,7 @@ void Game::slowFrame () {
graph.initLightLevels (); graph.initLightLevels ();
// detect csdm // detect csdm
detectDeathmatch (); applyGameModes ();
// check the cvar bounds // check the cvar bounds
checkCvarsBounds (); checkCvarsBounds ();

View file

@ -74,7 +74,7 @@ namespace variadic {
} }
} }
CR_EXPORT int GetEntityAPI2 (gamefuncs_t *functionTable, int *) { CR_EXPORT int GetEntityAPI2 (gamefuncs_t *table, int *) {
// this function is called right after GiveFnptrsToDll() by the engine in the game DLL (or // this function is called right after GiveFnptrsToDll() by the engine in the game DLL (or
// what it BELIEVES to be the game DLL), in order to copy the list of MOD functions that can // what it BELIEVES to be the game DLL), in order to copy the list of MOD functions that can
// be called by the engine, into a memory block pointed to by the functionTable pointer // be called by the engine, into a memory block pointed to by the functionTable pointer
@ -85,7 +85,7 @@ CR_EXPORT int GetEntityAPI2 (gamefuncs_t *functionTable, int *) {
// engine, and then calls the MOD DLL's version of GetEntityAPI to get the REAL gamedll // engine, and then calls the MOD DLL's version of GetEntityAPI to get the REAL gamedll
// functions this time (to use in the bot code). // functions this time (to use in the bot code).
memset (functionTable, 0, sizeof (gamefuncs_t)); memset (table, 0, sizeof (gamefuncs_t));
if (!(game.is (GameFlags::Metamod))) { if (!(game.is (GameFlags::Metamod))) {
auto api_GetEntityAPI = game.lib ().resolve <int (*) (gamefuncs_t *, int)> ("GetEntityAPI"); auto api_GetEntityAPI = game.lib ().resolve <int (*) (gamefuncs_t *, int)> ("GetEntityAPI");
@ -97,10 +97,10 @@ CR_EXPORT int GetEntityAPI2 (gamefuncs_t *functionTable, int *) {
dllfuncs.dllapi_table = &dllapi; dllfuncs.dllapi_table = &dllapi;
gpGamedllFuncs = &dllfuncs; gpGamedllFuncs = &dllfuncs;
memcpy (functionTable, &dllapi, sizeof (gamefuncs_t)); memcpy (table, &dllapi, sizeof (gamefuncs_t));
} }
functionTable->pfnGameInit = [] () { table->pfnGameInit = [] () {
// this function is a one-time call, and appears to be the second function called in the // this function is a one-time call, and appears to be the second function called in the
// DLL after GiveFntprsToDll() has been called. Its purpose is to tell the MOD DLL to // DLL after GiveFntprsToDll() has been called. Its purpose is to tell the MOD DLL to
// initialize the game before the engine actually hooks into it with its video frames and // initialize the game before the engine actually hooks into it with its video frames and
@ -127,7 +127,7 @@ CR_EXPORT int GetEntityAPI2 (gamefuncs_t *functionTable, int *) {
dllapi.pfnGameInit (); dllapi.pfnGameInit ();
}; };
functionTable->pfnSpawn = [] (edict_t *ent) { table->pfnSpawn = [] (edict_t *ent) {
// this function asks the game DLL to spawn (i.e, give a physical existence in the virtual // this function asks the game DLL to spawn (i.e, give a physical existence in the virtual
// world, in other words to 'display') the entity pointed to by ent in the game. The // world, in other words to 'display') the entity pointed to by ent in the game. The
// Spawn() function is one of the functions any entity is supposed to have in the game DLL, // Spawn() function is one of the functions any entity is supposed to have in the game DLL,
@ -146,7 +146,7 @@ CR_EXPORT int GetEntityAPI2 (gamefuncs_t *functionTable, int *) {
return result; return result;
}; };
functionTable->pfnTouch = [] (edict_t *pentTouched, edict_t *pentOther) { table->pfnTouch = [] (edict_t *pentTouched, edict_t *pentOther) {
// this function is called when two entities' bounding boxes enter in collision. For example, // this function is called when two entities' bounding boxes enter in collision. For example,
// when a player walks upon a gun, the player entity bounding box collides to the gun entity // when a player walks upon a gun, the player entity bounding box collides to the gun entity
// bounding box, and the result is that this function is called. It is used by the game for // bounding box, and the result is that this function is called. It is used by the game for
@ -161,7 +161,7 @@ CR_EXPORT int GetEntityAPI2 (gamefuncs_t *functionTable, int *) {
if (!game.isNullEntity (pentTouched) && pentOther != game.getStartEntity ()) { if (!game.isNullEntity (pentTouched) && pentOther != game.getStartEntity ()) {
auto bot = bots[pentTouched]; auto bot = bots[pentTouched];
if (bot && pentOther != bot->ent () && !util.isPlayer (pentOther)) { if (bot && game.isShootableBreakable (pentOther)) {
bot->checkBreakable (pentOther); bot->checkBreakable (pentOther);
} }
} }
@ -172,7 +172,7 @@ CR_EXPORT int GetEntityAPI2 (gamefuncs_t *functionTable, int *) {
dllapi.pfnTouch (pentTouched, pentOther); dllapi.pfnTouch (pentTouched, pentOther);
}; };
functionTable->pfnClientConnect = [] (edict_t *ent, const char *name, const char *addr, char rejectReason[128]) { table->pfnClientConnect = [] (edict_t *ent, const char *name, const char *addr, char rejectReason[128]) {
// this function is called in order to tell the MOD DLL that a client attempts to connect the // this function is called in order to tell the MOD DLL that a client attempts to connect the
// game. The entity pointer of this client is ent, the name under which he connects is // game. The entity pointer of this client is ent, the name under which he connects is
// pointed to by the pszName pointer, and its IP address string is pointed by the pszAddress // pointed to by the pszName pointer, and its IP address string is pointed by the pszAddress
@ -209,7 +209,7 @@ CR_EXPORT int GetEntityAPI2 (gamefuncs_t *functionTable, int *) {
return dllapi.pfnClientConnect (ent, name, addr, rejectReason); return dllapi.pfnClientConnect (ent, name, addr, rejectReason);
}; };
functionTable->pfnClientDisconnect = [] (edict_t *ent) { table->pfnClientDisconnect = [] (edict_t *ent) {
// this function is called whenever a client is VOLUNTARILY disconnected from the server, // this function is called whenever a client is VOLUNTARILY disconnected from the server,
// either because the client dropped the connection, or because the server dropped him from // either because the client dropped the connection, or because the server dropped him from
// the game (latency timeout). The effect is the freeing of a client slot on the server. Note // the game (latency timeout). The effect is the freeing of a client slot on the server. Note
@ -238,7 +238,7 @@ CR_EXPORT int GetEntityAPI2 (gamefuncs_t *functionTable, int *) {
dllapi.pfnClientDisconnect (ent); dllapi.pfnClientDisconnect (ent);
}; };
functionTable->pfnClientUserInfoChanged = [] (edict_t *ent, char *infobuffer) { table->pfnClientUserInfoChanged = [] (edict_t *ent, char *infobuffer) {
// this function is called when a player changes model, or changes team. Occasionally it // this function is called when a player changes model, or changes team. Occasionally it
// enforces rules on these changes (for example, some MODs don't want to allow players to // enforces rules on these changes (for example, some MODs don't want to allow players to
// change their player model). But most commonly, this function is in charge of handling // change their player model). But most commonly, this function is in charge of handling
@ -252,7 +252,7 @@ CR_EXPORT int GetEntityAPI2 (gamefuncs_t *functionTable, int *) {
dllapi.pfnClientUserInfoChanged (ent, infobuffer); dllapi.pfnClientUserInfoChanged (ent, infobuffer);
}; };
functionTable->pfnClientCommand = [] (edict_t *ent) { table->pfnClientCommand = [] (edict_t *ent) {
// this function is called whenever the client whose player entity is ent issues a client // this function is called whenever the client whose player entity is ent issues a client
// command. How it works is that clients all have a global string in their client DLL that // command. How it works is that clients all have a global string in their client DLL that
// stores the command string; if ever that string is filled with characters, the client DLL // stores the command string; if ever that string is filled with characters, the client DLL
@ -289,7 +289,7 @@ CR_EXPORT int GetEntityAPI2 (gamefuncs_t *functionTable, int *) {
dllapi.pfnClientCommand (ent); dllapi.pfnClientCommand (ent);
}; };
functionTable->pfnServerActivate = [] (edict_t *pentEdictList, int edictCount, int clientMax) { table->pfnServerActivate = [] (edict_t *pentEdictList, int edictCount, int clientMax) {
// this function is called when the server has fully loaded and is about to manifest itself // this function is called when the server has fully loaded and is about to manifest itself
// on the network as such. Since a mapchange is actually a server shutdown followed by a // on the network as such. Since a mapchange is actually a server shutdown followed by a
// restart, this function is also called when a new map is being loaded. Hence it's the // restart, this function is also called when a new map is being loaded. Hence it's the
@ -325,7 +325,7 @@ CR_EXPORT int GetEntityAPI2 (gamefuncs_t *functionTable, int *) {
graph.rebuildVisibility (); graph.rebuildVisibility ();
}; };
functionTable->pfnServerDeactivate = [] () { table->pfnServerDeactivate = [] () {
// this function is called when the server is shutting down. A particular note about map // this function is called when the server is shutting down. A particular note about map
// changes: changing the map means shutting down the server and starting a new one. Of course // changes: changing the map means shutting down the server and starting a new one. Of course
// this process is transparent to the user, but either in single player when the hero reaches // this process is transparent to the user, but either in single player when the hero reaches
@ -366,7 +366,7 @@ CR_EXPORT int GetEntityAPI2 (gamefuncs_t *functionTable, int *) {
dllapi.pfnServerDeactivate (); dllapi.pfnServerDeactivate ();
}; };
functionTable->pfnStartFrame = [] () { table->pfnStartFrame = [] () {
// this function starts a video frame. It is called once per video frame by the game. If // this function starts a video frame. It is called once per video frame by the game. If
// you run Half-Life at 90 fps, this function will then be called 90 times per second. By // you run Half-Life at 90 fps, this function will then be called 90 times per second. By
// placing a hook on it, we have a good place to do things that should be done continuously // placing a hook on it, we have a good place to do things that should be done continuously
@ -408,7 +408,7 @@ CR_EXPORT int GetEntityAPI2 (gamefuncs_t *functionTable, int *) {
bots.frame (); bots.frame ();
}; };
functionTable->pfnCmdStart = [] (const edict_t *player, usercmd_t *cmd, unsigned int random_seed) { table->pfnCmdStart = [] (const edict_t *player, usercmd_t *cmd, unsigned int random_seed) {
auto ent = const_cast <edict_t *> (player); auto ent = const_cast <edict_t *> (player);
// if we're handle pings for bots and clients, clear IN_SCORE button so SV_ShouldUpdatePing engine function return false // if we're handle pings for bots and clients, clear IN_SCORE button so SV_ShouldUpdatePing engine function return false
@ -428,7 +428,7 @@ CR_EXPORT int GetEntityAPI2 (gamefuncs_t *functionTable, int *) {
dllapi.pfnCmdStart (player, cmd, random_seed); dllapi.pfnCmdStart (player, cmd, random_seed);
}; };
functionTable->pfnPM_Move = [] (playermove_t *playerMove, int server) { table->pfnPM_Move = [] (playermove_t *playerMove, int server) {
// this is the player movement code clients run to predict things when the server can't update // this is the player movement code clients run to predict things when the server can't update
// them often enough (or doesn't want to). The server runs exactly the same function for // them often enough (or doesn't want to). The server runs exactly the same function for
// moving players. There is normally no distinction between them, else client-side prediction // moving players. There is normally no distinction between them, else client-side prediction
@ -444,7 +444,7 @@ CR_EXPORT int GetEntityAPI2 (gamefuncs_t *functionTable, int *) {
return TRUE; return TRUE;
} }
CR_EXPORT int GetEntityAPI2_Post (gamefuncs_t *table, int *) { CR_LINKAGE_C int GetEntityAPI2_Post (gamefuncs_t *table, int *) {
// this function is called right after GiveFnptrsToDll() by the engine in the game DLL (or // this function is called right after GiveFnptrsToDll() by the engine in the game DLL (or
// what it BELIEVES to be the game DLL), in order to copy the list of MOD functions that can // what it BELIEVES to be the game DLL), in order to copy the list of MOD functions that can
// be called by the engine, into a memory block pointed to by the functionTable pointer // be called by the engine, into a memory block pointed to by the functionTable pointer
@ -468,7 +468,7 @@ CR_EXPORT int GetEntityAPI2_Post (gamefuncs_t *table, int *) {
if (ent->v.rendermode == kRenderTransTexture) { if (ent->v.rendermode == kRenderTransTexture) {
ent->v.flags &= ~FL_WORLDBRUSH; // clear the FL_WORLDBRUSH flag out of transparent ents ent->v.flags &= ~FL_WORLDBRUSH; // clear the FL_WORLDBRUSH flag out of transparent ents
} }
RETURN_META_VALUE (MRES_IGNORED, 0); RETURN_META_VALUE (MRES_HANDLED, 0);
}; };
table->pfnStartFrame = [] () { table->pfnStartFrame = [] () {
@ -501,30 +501,12 @@ CR_EXPORT int GetEntityAPI2_Post (gamefuncs_t *table, int *) {
return TRUE; return TRUE;
} }
CR_EXPORT int GetNewDLLFunctions (newgamefuncs_t *functionTable, int *interfaceVersion) { CR_LINKAGE_C int GetEngineFunctions (enginefuncs_t *table, int *) {
// it appears that an extra function table has been added in the engine to gamedll interface
// since the date where the first enginefuncs table standard was frozen. These ones are
// facultative and we don't hook them, but since some MODs might be featuring it, we have to
// pass them too, else the DLL interfacing wouldn't be complete and the game possibly wouldn't
// run properly.
auto api_GetNewDLLFunctions = game.lib ().resolve <int (*) (newgamefuncs_t *, int *)> (__FUNCTION__);
if (!api_GetNewDLLFunctions || !api_GetNewDLLFunctions (functionTable, interfaceVersion)) {
logger.error ("Could not resolve symbol \"%s\" in the game dll. Continuing...", __FUNCTION__);
return FALSE;
}
dllfuncs.newapi_table = functionTable;
return TRUE;
}
CR_EXPORT int GetEngineFunctions (enginefuncs_t *functionTable, int *) {
if (game.is (GameFlags::Metamod)) { if (game.is (GameFlags::Metamod)) {
memset (functionTable, 0, sizeof (enginefuncs_t)); memset (table, 0, sizeof (enginefuncs_t));
} }
functionTable->pfnChangeLevel = [] (char *s1, char *s2) { table->pfnChangeLevel = [] (char *s1, char *s2) {
// the purpose of this function is to ask the engine to shutdown the server and restart a // the purpose of this function is to ask the engine to shutdown the server and restart a
// new one running the map whose name is s1. It is used ONLY IN SINGLE PLAYER MODE and is // new one running the map whose name is s1. It is used ONLY IN SINGLE PLAYER MODE and is
// transparent to the user, because it saves the player state and equipment and restores it // transparent to the user, because it saves the player state and equipment and restores it
@ -543,7 +525,7 @@ CR_EXPORT int GetEngineFunctions (enginefuncs_t *functionTable, int *) {
engfuncs.pfnChangeLevel (s1, s2); engfuncs.pfnChangeLevel (s1, s2);
}; };
functionTable->pfnLightStyle = [] (int style, char *val) { table->pfnLightStyle = [] (int style, char *val) {
// ths function update lightstyle for the bots // ths function update lightstyle for the bots
illum.updateLight (style, val); illum.updateLight (style, val);
@ -555,7 +537,7 @@ CR_EXPORT int GetEngineFunctions (enginefuncs_t *functionTable, int *) {
}; };
if (game.is (GameFlags::Legacy)) { if (game.is (GameFlags::Legacy)) {
functionTable->pfnFindEntityByString = [] (edict_t *edictStartSearchAfter, const char *field, const char *value) { table->pfnFindEntityByString = [] (edict_t *edictStartSearchAfter, const char *field, const char *value) {
// round starts in counter-strike 1.5 // round starts in counter-strike 1.5
if (strcmp (value, "info_map_parameters") == 0) { if (strcmp (value, "info_map_parameters") == 0) {
bots.initRound (); bots.initRound ();
@ -568,7 +550,7 @@ CR_EXPORT int GetEngineFunctions (enginefuncs_t *functionTable, int *) {
}; };
} }
functionTable->pfnEmitSound = [] (edict_t *entity, int channel, const char *sample, float volume, float attenuation, int flags, int pitch) { table->pfnEmitSound = [] (edict_t *entity, int channel, const char *sample, float volume, float attenuation, int flags, int pitch) {
// this function tells the engine that the entity pointed to by "entity", is emitting a sound // this function tells the engine that the entity pointed to by "entity", is emitting a sound
// which fileName is "sample", at level "channel" (CHAN_VOICE, etc...), with "volume" as // which fileName is "sample", at level "channel" (CHAN_VOICE, etc...), with "volume" as
// loudness multiplicator (normal volume VOL_NORM is 1.0), with a pitch of "pitch" (normal // loudness multiplicator (normal volume VOL_NORM is 1.0), with a pitch of "pitch" (normal
@ -587,7 +569,7 @@ CR_EXPORT int GetEngineFunctions (enginefuncs_t *functionTable, int *) {
engfuncs.pfnEmitSound (entity, channel, sample, volume, attenuation, flags, pitch); engfuncs.pfnEmitSound (entity, channel, sample, volume, attenuation, flags, pitch);
}; };
functionTable->pfnMessageBegin = [] (int msgDest, int msgType, const float *origin, edict_t *ed) { table->pfnMessageBegin = [] (int msgDest, int msgType, const float *origin, edict_t *ed) {
// this function called each time a message is about to sent. // this function called each time a message is about to sent.
msgs.start (ed, msgType); msgs.start (ed, msgType);
@ -598,16 +580,16 @@ CR_EXPORT int GetEngineFunctions (enginefuncs_t *functionTable, int *) {
engfuncs.pfnMessageBegin (msgDest, msgType, origin, ed); engfuncs.pfnMessageBegin (msgDest, msgType, origin, ed);
}; };
functionTable->pfnMessageEnd = [] () { if (!game.is (GameFlags::Metamod)) {
msgs.stop (); table->pfnMessageEnd = [] () {
if (game.is (GameFlags::Metamod)) {
RETURN_META (MRES_IGNORED);
}
engfuncs.pfnMessageEnd (); engfuncs.pfnMessageEnd ();
};
functionTable->pfnWriteByte = [] (int value) { // this allows us to send messages right in handler code
msgs.stop ();
};
}
table->pfnWriteByte = [] (int value) {
// if this message is for a bot, call the client message function... // if this message is for a bot, call the client message function...
msgs.collect (value); msgs.collect (value);
@ -617,7 +599,7 @@ CR_EXPORT int GetEngineFunctions (enginefuncs_t *functionTable, int *) {
engfuncs.pfnWriteByte (value); engfuncs.pfnWriteByte (value);
}; };
functionTable->pfnWriteChar = [] (int value) { table->pfnWriteChar = [] (int value) {
// if this message is for a bot, call the client message function... // if this message is for a bot, call the client message function...
msgs.collect (value); msgs.collect (value);
@ -627,7 +609,7 @@ CR_EXPORT int GetEngineFunctions (enginefuncs_t *functionTable, int *) {
engfuncs.pfnWriteChar (value); engfuncs.pfnWriteChar (value);
}; };
functionTable->pfnWriteShort = [] (int value) { table->pfnWriteShort = [] (int value) {
// if this message is for a bot, call the client message function... // if this message is for a bot, call the client message function...
msgs.collect (value); msgs.collect (value);
@ -637,7 +619,7 @@ CR_EXPORT int GetEngineFunctions (enginefuncs_t *functionTable, int *) {
engfuncs.pfnWriteShort (value); engfuncs.pfnWriteShort (value);
}; };
functionTable->pfnWriteLong = [] (int value) { table->pfnWriteLong = [] (int value) {
// if this message is for a bot, call the client message function... // if this message is for a bot, call the client message function...
msgs.collect (value); msgs.collect (value);
@ -647,7 +629,7 @@ CR_EXPORT int GetEngineFunctions (enginefuncs_t *functionTable, int *) {
engfuncs.pfnWriteLong (value); engfuncs.pfnWriteLong (value);
}; };
functionTable->pfnWriteAngle = [] (float value) { table->pfnWriteAngle = [] (float value) {
// if this message is for a bot, call the client message function... // if this message is for a bot, call the client message function...
msgs.collect (value); msgs.collect (value);
@ -657,7 +639,7 @@ CR_EXPORT int GetEngineFunctions (enginefuncs_t *functionTable, int *) {
engfuncs.pfnWriteAngle (value); engfuncs.pfnWriteAngle (value);
}; };
functionTable->pfnWriteCoord = [] (float value) { table->pfnWriteCoord = [] (float value) {
// if this message is for a bot, call the client message function... // if this message is for a bot, call the client message function...
msgs.collect (value); msgs.collect (value);
@ -667,7 +649,7 @@ CR_EXPORT int GetEngineFunctions (enginefuncs_t *functionTable, int *) {
engfuncs.pfnWriteCoord (value); engfuncs.pfnWriteCoord (value);
}; };
functionTable->pfnWriteString = [] (const char *sz) { table->pfnWriteString = [] (const char *sz) {
// if this message is for a bot, call the client message function... // if this message is for a bot, call the client message function...
msgs.collect (sz); msgs.collect (sz);
@ -677,7 +659,7 @@ CR_EXPORT int GetEngineFunctions (enginefuncs_t *functionTable, int *) {
engfuncs.pfnWriteString (sz); engfuncs.pfnWriteString (sz);
}; };
functionTable->pfnWriteEntity = [] (int value) { table->pfnWriteEntity = [] (int value) {
// if this message is for a bot, call the client message function... // if this message is for a bot, call the client message function...
msgs.collect (value); msgs.collect (value);
@ -687,7 +669,8 @@ CR_EXPORT int GetEngineFunctions (enginefuncs_t *functionTable, int *) {
engfuncs.pfnWriteEntity (value); engfuncs.pfnWriteEntity (value);
}; };
functionTable->pfnRegUserMsg = [] (const char *name, int size) { if (!game.is (GameFlags::Metamod)) {
table->pfnRegUserMsg = [] (const char *name, int size) {
// this function registers a "user message" by the engine side. User messages are network // this function registers a "user message" by the engine side. User messages are network
// messages the game DLL asks the engine to send to clients. Since many MODs have completely // messages the game DLL asks the engine to send to clients. Since many MODs have completely
// different client features (Counter-Strike has a radar and a timer, for example), network // different client features (Counter-Strike has a radar and a timer, for example), network
@ -698,18 +681,11 @@ CR_EXPORT int GetEngineFunctions (enginefuncs_t *functionTable, int *) {
// using pfnMessageBegin (), it will know what message ID number to send, and the engine will // using pfnMessageBegin (), it will know what message ID number to send, and the engine will
// know what to do, only for non-metamod version // know what to do, only for non-metamod version
int message = engfuncs.pfnRegUserMsg (name, size); return msgs.add (name, engfuncs.pfnRegUserMsg (name, size)); // return privously registered message
// register message for our needs
msgs.registerMessage (name, message);
if (game.is (GameFlags::Metamod)) {
RETURN_META_VALUE (MRES_SUPERCEDE, message);
}
return message;
}; };
}
functionTable->pfnClientPrintf = [] (edict_t *ent, PRINT_TYPE printType, const char *message) { table->pfnClientPrintf = [] (edict_t *ent, PRINT_TYPE printType, const char *message) {
// this function prints the text message string pointed to by message by the client side of // this function prints the text message string pointed to by message by the client side of
// the client entity pointed to by ent, in a manner depending of printType (print_console, // the client entity pointed to by ent, in a manner depending of printType (print_console,
// print_center or print_chat). Be certain never to try to feed a bot with this function, // print_center or print_chat). Be certain never to try to feed a bot with this function,
@ -729,7 +705,7 @@ CR_EXPORT int GetEngineFunctions (enginefuncs_t *functionTable, int *) {
engfuncs.pfnClientPrintf (ent, printType, message); engfuncs.pfnClientPrintf (ent, printType, message);
}; };
functionTable->pfnCmd_Args = [] () { table->pfnCmd_Args = [] () {
// this function returns a pointer to the whole current client command string. Since bots // this function returns a pointer to the whole current client command string. Since bots
// have no client DLL and we may want a bot to execute a client command, we had to implement // have no client DLL and we may want a bot to execute a client command, we had to implement
// a argv string in the bot DLL for holding the bots' commands, and also keep track of the // a argv string in the bot DLL for holding the bots' commands, and also keep track of the
@ -751,7 +727,7 @@ CR_EXPORT int GetEngineFunctions (enginefuncs_t *functionTable, int *) {
return engfuncs.pfnCmd_Args (); // ask the client command string to the engine return engfuncs.pfnCmd_Args (); // ask the client command string to the engine
}; };
functionTable->pfnCmd_Argv = [] (int argc) { table->pfnCmd_Argv = [] (int argc) {
// this function returns a pointer to a certain argument of the current client command. Since // this function returns a pointer to a certain argument of the current client command. Since
// bots have no client DLL and we may want a bot to execute a client command, we had to // bots have no client DLL and we may want a bot to execute a client command, we had to
// implement a argv string in the bot DLL for holding the bots' commands, and also keep // implement a argv string in the bot DLL for holding the bots' commands, and also keep
@ -773,7 +749,7 @@ CR_EXPORT int GetEngineFunctions (enginefuncs_t *functionTable, int *) {
return engfuncs.pfnCmd_Argv (argc); // ask the argument number "argc" to the engine return engfuncs.pfnCmd_Argv (argc); // ask the argument number "argc" to the engine
}; };
functionTable->pfnCmd_Argc = [] () { table->pfnCmd_Argc = [] () {
// this function returns the number of arguments the current client command string has. Since // this function returns the number of arguments the current client command string has. Since
// bots have no client DLL and we may want a bot to execute a client command, we had to // bots have no client DLL and we may want a bot to execute a client command, we had to
// implement a argv string in the bot DLL for holding the bots' commands, and also keep // implement a argv string in the bot DLL for holding the bots' commands, and also keep
@ -795,7 +771,7 @@ CR_EXPORT int GetEngineFunctions (enginefuncs_t *functionTable, int *) {
return engfuncs.pfnCmd_Argc (); // ask the engine how many arguments there are return engfuncs.pfnCmd_Argc (); // ask the engine how many arguments there are
}; };
functionTable->pfnSetClientMaxspeed = [] (const edict_t *ent, float newMaxspeed) { table->pfnSetClientMaxspeed = [] (const edict_t *ent, float newMaxspeed) {
auto bot = bots[const_cast <edict_t *> (ent)]; auto bot = bots[const_cast <edict_t *> (ent)];
// check wether it's not a bot // check wether it's not a bot
@ -809,26 +785,57 @@ CR_EXPORT int GetEngineFunctions (enginefuncs_t *functionTable, int *) {
engfuncs.pfnSetClientMaxspeed (ent, newMaxspeed); engfuncs.pfnSetClientMaxspeed (ent, newMaxspeed);
}; };
functionTable->pfnClientCommand = variadic::clientCommand; table->pfnClientCommand = variadic::clientCommand;
return TRUE; return TRUE;
} }
#if defined (CR_ANDROID) CR_EXPORT int GetNewDLLFunctions (newgamefuncs_t *table, int *interfaceVersion) {
CR_EXPORT int Server_GetBlendingInterface (int version, struct sv_blending_interface_s **ppinterface, struct engine_studio_api_s *pstudio, float *rotationmatrix, float *bonetransform) { // it appears that an extra function table has been added in the engine to gamedll interface
// this function synchronizes the studio model animation blending interface (i.e, what parts // since the date where the first enginefuncs table standard was frozen. These ones are
// of the body move, which bones, which hitboxes and how) between the server and the game DLL. // facultative and we don't hook them, but since some MODs might be featuring it, we have to
// some MODs can be using a different hitbox scheme than the standard one. // pass them too, else the DLL interfacing wouldn't be complete and the game possibly wouldn't
// run properly.
auto api_GetBlendingInterface = game.lib ().resolve <int (*) (int, struct sv_blending_interface_s **, struct engine_studio_api_s *, float *, float *)> (__FUNCTION__); auto api_GetNewDLLFunctions = game.lib ().resolve <int (*) (newgamefuncs_t *, int *)> (__FUNCTION__);
if (!api_GetBlendingInterface) { if (!api_GetNewDLLFunctions || !api_GetNewDLLFunctions (table, interfaceVersion)) {
logger.error ("Could not resolve symbol \"%s\" in the game dll. Continuing...", __FUNCTION__); logger.error ("Could not resolve symbol \"%s\" in the game dll. Continuing...", __FUNCTION__);
return FALSE; return FALSE;
} }
return api_GetBlendingInterface (version, ppinterface, pstudio, rotationmatrix, bonetransform);
dllfuncs.newapi_table = table;
return TRUE;
}
CR_LINKAGE_C int GetEngineFunctions_Post (enginefuncs_t *table, int *) {
memset (table, 0, sizeof (enginefuncs_t));
table->pfnMessageEnd = [] () {
msgs.stop (); // this allows us to send messages right in handler code
RETURN_META (MRES_IGNORED);
};
table->pfnRegUserMsg = [] (const char *name, int) {
// this function registers a "user message" by the engine side. User messages are network
// messages the game DLL asks the engine to send to clients. Since many MODs have completely
// different client features (Counter-Strike has a radar and a timer, for example), network
// messages just can't be the same for every MOD. Hence here the MOD DLL tells the engine,
// "Hey, you have to know that I use a network message whose name is pszName and it is size
// packets long". The engine books it, and returns the ID number under which he recorded that
// custom message. Thus every time the MOD DLL will be wanting to send a message named pszName
// using pfnMessageBegin (), it will know what message ID number to send, and the engine will
// know what to do, only for non-metamod version
// register message for our needs
msgs.add (name, META_RESULT_ORIG_RET (int));
RETURN_META_VALUE (MRES_IGNORED, 0);
};
return TRUE;
} }
#endif
CR_EXPORT int Meta_Query (char *, plugin_info_t **pPlugInfo, mutil_funcs_t *pMetaUtilFuncs) { CR_EXPORT int Meta_Query (char *, plugin_info_t **pPlugInfo, mutil_funcs_t *pMetaUtilFuncs) {
// this function is the first function ever called by metamod in the plugin DLL. Its purpose // this function is the first function ever called by metamod in the plugin DLL. Its purpose
@ -855,7 +862,7 @@ CR_EXPORT int Meta_Attach (PLUG_LOADTIME now, metamod_funcs_t *functionTable, me
nullptr, // pfnGetNewDLLFunctions () nullptr, // pfnGetNewDLLFunctions ()
nullptr, // pfnGetNewDLLFunctions_Post () nullptr, // pfnGetNewDLLFunctions_Post ()
GetEngineFunctions, // pfnGetEngineFunctions () GetEngineFunctions, // pfnGetEngineFunctions ()
nullptr, // pfnGetEngineFunctions_Post () GetEngineFunctions_Post, // pfnGetEngineFunctions_Post ()
}; };
if (now > Plugin_info.loadable) { if (now > Plugin_info.loadable) {
@ -904,7 +911,7 @@ CR_EXPORT void Meta_Init () {
# pragma comment(linker, "/SECTION:.data,RW") # pragma comment(linker, "/SECTION:.data,RW")
# endif # endif
# if defined(CR_CXX_MSVC) && !defined(CR_ARCH_X64) # if defined(CR_CXX_MSVC) && !defined(CR_ARCH_X64)
# define DLL_GIVEFNPTRSTODLL extern "C" void CR_STDCALL # define DLL_GIVEFNPTRSTODLL CR_LINKAGE_C void CR_STDCALL
# elif defined(CR_CXX_CLANG) || defined(CR_ARCH_X64) # elif defined(CR_CXX_CLANG) || defined(CR_ARCH_X64)
# define DLL_GIVEFNPTRSTODLL CR_EXPORT void CR_STDCALL # define DLL_GIVEFNPTRSTODLL CR_EXPORT void CR_STDCALL
# endif # endif

View file

@ -463,11 +463,13 @@ MessageDispatcher::MessageDispatcher () {
m_teamInfoCache["CT"] = Team::CT; m_teamInfoCache["CT"] = Team::CT;
} }
void MessageDispatcher::registerMessage (const String &name, int32 id) { int32 MessageDispatcher::add (const String &name, int32 id) {
if (!m_wanted.exists (name)) { if (!m_wanted.exists (name)) {
return; return id;
} }
m_maps[m_wanted[name]] = id; // add message from engine RegUserMsg m_maps[m_wanted[name]] = id; // add message from engine regusermsg
return id;
} }
void MessageDispatcher::start (edict_t *ent, int32 type) { void MessageDispatcher::start (edict_t *ent, int32 type) {