Fixed linux listenserver startup problems

Fixed multiple buffer overruns and memory leaks.
This commit is contained in:
jeefo 2020-11-23 00:06:18 +03:00
commit 74f1ab866b
29 changed files with 371 additions and 254 deletions

View file

@ -24,7 +24,7 @@ CR_EXPORT int Server_GetBlendingInterface (int version, struct sv_blending_inter
return api_GetBlendingInterface (version, ppinterface, pstudio, rotationmatrix, bonetransform);
}
void android_LinkEntity (EntityFunction &addr, const char *name, entvars_t *pev) {
void forwardEntity_helper (EntityFunction &addr, const char *name, entvars_t *pev) {
if (!addr) {
addr = game.lib ().resolve <EntityFunction> (name);
}
@ -37,7 +37,7 @@ void android_LinkEntity (EntityFunction &addr, const char *name, entvars_t *pev)
#define LINK_ENTITY(entityName) \
CR_EXPORT void entityName (entvars_t *pev) { \
static EntityFunction addr; \
android_LinkEntity (addr, #entityName, pev); \
forwardEntity_helper (addr, __FUNCTION__, pev); \
}
#else
#define LINK_ENTITY(entityName)
@ -142,6 +142,7 @@ LINK_ENTITY (game_team_master)
LINK_ENTITY (game_team_set)
LINK_ENTITY (game_text)
LINK_ENTITY (game_zone_player)
LINK_ENTITY (gib)
LINK_ENTITY (gibshooter)
LINK_ENTITY (grenade)
LINK_ENTITY (hostage_entity)

View file

@ -193,7 +193,6 @@ void Bot::checkGrenadesThrow () {
allowThrowing = false;
continue;
}
m_throw = graph[predict].origin;
auto throwPos = calcThrow (getEyesPos (), m_throw);
@ -4068,7 +4067,7 @@ void Bot::followUser_ () {
clearSearchNodes ();
int destIndex = graph.getNearest (m_targetEntity->v.origin);
IntArray points = graph.searchRadius (200.0f, m_targetEntity->v.origin);
auto points = graph.searchRadius (200.0f, m_targetEntity->v.origin);
for (auto &newIndex : points) {
// if waypoint not yet used, assign it as dest

View file

@ -51,10 +51,10 @@ int BotGraph::clearConnections (int index) {
}
struct Connection {
int index;
int number;
int distance;
float angles;
int index {};
int number {};
int distance {};
float angles {};
public:
Connection () {
@ -514,7 +514,7 @@ IntArray BotGraph::searchRadius (float radius, const Vector &origin, int maxCoun
if (bucket.empty ()) {
result.push (getNearestNoBuckets (origin, radius));
return cr::move (result);
return result;
}
radius = cr::square (radius);
@ -527,7 +527,7 @@ IntArray BotGraph::searchRadius (float radius, const Vector &origin, int maxCoun
result.push (at);
}
}
return cr::move (result);
return result;
}
void BotGraph::add (int type, const Vector &pos) {
@ -2564,7 +2564,7 @@ bool BotGraph::checkNodes (bool teleportPlayer) {
for (auto &visit : visited) {
visit = false;
}
walk.push (0); // always check from node number 0
walk.add (0); // always check from node number 0
while (!walk.empty ()) {
// pop a node from the stack
@ -2579,7 +2579,7 @@ bool BotGraph::checkNodes (bool teleportPlayer) {
// skip this node as it's already visited
if (exists (index) && !visited[index]) {
visited[index] = true;
walk.push (index);
walk.add (index);
}
}
}
@ -2612,7 +2612,7 @@ bool BotGraph::checkNodes (bool teleportPlayer) {
visit = false;
}
walk.clear ();
walk.push (0); // always check from node number 0
walk.add (0); // always check from node number 0
while (!walk.empty ()) {
const int current = walk.first (); // pop a node from the stack
@ -2623,7 +2623,7 @@ bool BotGraph::checkNodes (bool teleportPlayer) {
continue; // skip this node as it's already visited
}
visited[outgoing] = true;
walk.push (outgoing);
walk.add (outgoing);
}
}
@ -2756,7 +2756,7 @@ void BotGraph::eraseFromDisk () {
// if we're delete graph, delete all corresponding to it files
forErase.push (strings.format ("%spwf/%s.pwf", data, map)); // graph itself
forErase.push (strings.format ("%strain/%s.exp", data, map)); // corresponding to practice
forErase.push (strings.format ("%strain/%s.prc", data, map)); // corresponding to practice
forErase.push (strings.format ("%strain/%s.vis", data, map)); // corresponding to vistable
forErase.push (strings.format ("%strain/%s.pmx", data, map)); // corresponding to matrix
forErase.push (strings.format ("%sgraph/%s.graph", data, map)); // new format graph
@ -2839,8 +2839,6 @@ void BotGraph::setSearchIndex (int index) {
}
BotGraph::BotGraph () {
plat.bzero (m_highestDamage, sizeof (m_highestDamage));
m_endJumpPoint = false;
m_needsVisRebuild = false;
m_jumpLearnNode = false;

View file

@ -10,6 +10,7 @@
ConVar cv_version ("yb_version", product.version.chars (), Var::ReadOnly);
gamefuncs_t dllapi;
newgamefuncs_t newapi;
enginefuncs_t engfuncs;
gamedll_funcs_t dllfuncs;
@ -499,6 +500,17 @@ CR_LINKAGE_C int GetEngineFunctions (enginefuncs_t *table, int *) {
plat.bzero (table, sizeof (enginefuncs_t));
}
if (ents.isWorkaroundNeeded () && !game.is (GameFlags::Metamod)) {
table->pfnCreateNamedEntity = [] (int classname) -> edict_t * {
if (ents.isPaused ()) {
ents.enable ();
ents.setPaused (false);
}
return engfuncs.pfnCreateNamedEntity (classname);
};
}
table->pfnChangeLevel = [] (char *s1, char *s2) {
// 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
@ -790,13 +802,33 @@ CR_EXPORT int GetNewDLLFunctions (newgamefuncs_t *table, int *interfaceVersion)
// 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 <decltype (&GetNewDLLFunctions)> (__FUNCTION__);
plat.bzero (table, sizeof (newgamefuncs_t));
if (!api_GetNewDLLFunctions || !api_GetNewDLLFunctions (table, interfaceVersion)) {
logger.error ("Could not resolve symbol \"%s\" in the game dll. Continuing...", __FUNCTION__);
return HLFalse;
if (!(game.is (GameFlags::Metamod))) {
auto api_GetEntityAPI = game.lib ().resolve <decltype (&GetNewDLLFunctions)> (__FUNCTION__);
// pass other DLLs engine callbacks to function table...
if (!api_GetEntityAPI || api_GetEntityAPI (&newapi, interfaceVersion) == 0) {
logger.error ("Could not resolve symbol \"%s\" in the game dll.", __FUNCTION__);
}
dllfuncs.newapi_table = &newapi;
memcpy (table, &newapi, sizeof (newgamefuncs_t));
}
dllfuncs.newapi_table = table;
table->pfnOnFreeEntPrivateData = [] (edict_t *ent) {
for (auto &bot : bots) {
if (bot->m_enemy == ent) {
bot->m_enemy = nullptr;
bot->m_lastEnemy = nullptr;
}
}
if (game.is (GameFlags::Metamod)) {
RETURN_META (MRES_IGNORED);
}
newapi.pfnOnFreeEntPrivateData (ent);
};
return HLTrue;
}
@ -851,7 +883,7 @@ CR_EXPORT int Meta_Attach (PLUG_LOADTIME now, metamod_funcs_t *functionTable, me
GetEntityAPI_Post, // pfnGetEntityAPI_Post ()
nullptr, // pfnGetEntityAPI2 ()
nullptr, // pfnGetEntityAPI2_Post ()
nullptr, // pfnGetNewDLLFunctions ()
GetNewDLLFunctions, // pfnGetNewDLLFunctions ()
nullptr, // pfnGetNewDLLFunctions_Post ()
GetEngineFunctions, // pfnGetEngineFunctions ()
GetEngineFunctions_Post, // pfnGetEngineFunctions_Post ()
@ -947,14 +979,23 @@ DLL_GIVEFNPTRSTODLL GiveFnptrsToDll (enginefuncs_t *functionTable, globalvars_t
api_GiveFnptrsToDll (functionTable, glob);
}
DETOUR_RETURN EntityLinkage::lookup (SharedLibrary::Handle module, const char *function) {
DLSYM_RETURN EntityLinkage::lookup (SharedLibrary::Handle module, const char *function) {
static const auto &gamedll = game.lib ().handle ();
static const auto &self = m_self.handle ();
const auto resolve = [&] (SharedLibrary::Handle handle) {
return reinterpret_cast <DETOUR_RETURN> (m_dlsym (static_cast <DETOUR_HANDLE> (handle), function));
return reinterpret_cast <DLSYM_RETURN> (m_dlsym (static_cast <DLSYM_HANDLE> (handle), function));
};
if (ents.isWorkaroundNeeded () && !strcmp (function, "CreateInterface")) {
ents.setPaused (true);
auto ret = resolve (module);
ents.disable ();
return ret;
}
// if requested module is yapb module, put in cache the looked up symbol
if (self != module || (plat.win32 && (static_cast <uint16> (reinterpret_cast <uint32> (function) >> 16) & 0xffff) == 0)) {
return resolve (module);
@ -979,13 +1020,18 @@ DETOUR_RETURN EntityLinkage::lookup (SharedLibrary::Handle module, const char *f
}
void EntityLinkage::initialize () {
if (plat.arm) {
if (plat.arm || game.is (GameFlags::Metamod)) {
return;
}
m_dlsym.initialize ("kernel32.dll", "GetProcAddress", DLSYM_FUNCTION);
m_dlsym.install (reinterpret_cast <void *> (EntityLinkage::replacement), true);
m_self.locate (&engfuncs);
}
// add linkents for android
#include "android.cpp"
// override new/delete globally, need to be included in .cpp file
#include <crlib/cr-override.h>

View file

@ -914,6 +914,7 @@ Bot::Bot (edict_t *bot, int difficulty, int personality, int team, int skin) {
// we're not initializing all the variables in bot class, so do an ugly thing... memset this
plat.bzero (this, sizeof (*this));
int clientIndex = game.indexOfEntity (bot);
pev = &bot->v;
@ -1033,6 +1034,9 @@ Bot::Bot (edict_t *bot, int difficulty, int personality, int team, int skin) {
// just to be sure
m_msgQueue.clear ();
// init path walker
m_pathWalk.init (graph.getMaxRouteLength ());
// assign team and class
m_wantedTeam = team;
m_wantedSkin = skin;
@ -1104,18 +1108,18 @@ bool BotManager::isTeamStacked (int team) {
void BotManager::erase (Bot *bot) {
for (auto &e : m_bots) {
if (e.get () == bot) {
bot->showChaterIcon (false);
bot->markStale ();
conf.clearUsedName (bot); // clear the bot name
e.reset ();
m_bots.remove (e); // remove from bots array
break;
if (e.get () != bot) {
continue;
}
bot->markStale ();
auto index = m_bots.index (e);
e.reset ();
m_bots.erase (index, 1); // remove from bots array
break;
}
}
void BotManager::handleDeath (edict_t *killer, edict_t *victim) {
@ -1423,6 +1427,11 @@ void Bot::kick () {
}
void Bot::markStale () {
showChaterIcon (false);
// clear the bot name
conf.clearUsedName (this);
// clear fakeclient bit
pev->flags &= ~FL_FAKECLIENT;

View file

@ -12,9 +12,6 @@ class YaPBModule : public IYaPBModule {
public:
virtual ~YaPBModule () override = default;
public:
CR_DECLARE_DESTRUCTOR ();
private:
Bot *getBot (int index) {
if (index < 1) {

View file

@ -601,7 +601,7 @@ void Bot::checkTerrain (float movedDistance, const Vector &dirNormal) {
m_collStateIndex++;
m_probeTime = game.time () + 0.5f;
if (m_collStateIndex > kMaxCollideMoves) {
if (m_collStateIndex >= kMaxCollideMoves) {
m_navTimeset = game.time () - 5.0f;
resetCollision ();
}
@ -1181,7 +1181,7 @@ void Bot::findShortestPath (int srcIndex, int destIndex) {
m_chosenGoalIndex = srcIndex;
m_goalValue = 0.0f;
m_pathWalk.push (srcIndex);
m_pathWalk.add (srcIndex);
while (srcIndex != destIndex) {
srcIndex = (graph.m_matrix.data () + (srcIndex * graph.length ()) + destIndex)->index;
@ -1192,7 +1192,7 @@ void Bot::findShortestPath (int srcIndex, int destIndex) {
return;
}
m_pathWalk.push (srcIndex);
m_pathWalk.add (srcIndex);
}
}
@ -1406,7 +1406,7 @@ void Bot::findPath (int srcIndex, int destIndex, FindPath pathType /*= FindPath:
int currentIndex = m_routeQue.pop ().first;
// safes us from bad graph...
if (m_routeQue.length () >= kMaxRouteLength - 1) {
if (m_routeQue.length () >= graph.getMaxRouteLength () - 1) {
logger.error ("A* Search for bot \"%s\" has tried to build path with at least %d nodes. Seems to be graph is broken.", pev->netname.chars (), m_routeQue.length ());
kick (); // kick the bot off...
@ -1418,7 +1418,7 @@ void Bot::findPath (int srcIndex, int destIndex, FindPath pathType /*= FindPath:
// build the complete path
do {
m_pathWalk.push (currentIndex);
m_pathWalk.add (currentIndex);
currentIndex = m_routes[currentIndex].parent;
} while (currentIndex != kInvalidNodeIndex);