.:: Bots United ::.

.:: Bots United ::. (http://forums.bots-united.com/index.php)
-   Half-Life 1 SDK (http://forums.bots-united.com/forumdisplay.php?f=33)
-   -   Safe to keep edict_t pointers ? (http://forums.bots-united.com/showthread.php?t=3517)

koraX 02-02-2005 17:54

Safe to keep edict_t pointers ?
 
Some edict_t are indeed useful, like listenserver or worldspawn.

Clients edict_t (Bots or players) is also obviously useful. These edicts can be acquired by pfnPEntityOfEntIndex() (or INDEXENT macro), however I don't like idea of calling HL engine if we don't have to.

My question is, is it safe to keep these entities and use them within your plugin ? Of course every map change I shall update listenserver, worldspawn and remove all player edicts.

I don't know what could replace listenserver (acquired in ClientConnect()) and worldspawn (acquired in Spawn()).

Client edicts could be replaced by client indexes and every time I will need edict, I call pfnPEntityOfEntIndex().

I shall think of "new client is here, add it to your list" in ClientPutInServer() and of "client left, remove it from your list" in ClientDisconnect() and on map change.

So is this approach with using edicts OK ? Is it safe to think location of edicts doesn't change as long as client is connected ?

(It really helps to understand the problem when you write everything down :) )

Rick 02-02-2005 18:11

Re: Safe to keep edict_t pointers ?
 
Sure as long as you check if their still valid(ie not kicked or removed):
Code:

bool IsNull (edict_t *pEdict)
{
        // thanx to PMB for this function
        try
        {
                if (pEdict == NULL)
                        return true;
 
                if (g_engfuncs.pfnEntOffsetOfPEntity (pEdict) == 0)
                        return true;
   
                if (pEdict->free)
                        return true;
 
                if (pEdict->v.flags & FL_KILLME)
                        return true;
  }
  catch (...)
  {
#ifdef _DEBUG
                FILE *fp = fopen("bot.txt", "a");
                if(fp)
                {
                        fprintf(fp, "IsNull(edict_t *) Error\n");
                        fclose(fp);
                }
#endif
          return true; // failed so assuming entity isn't valid...
  }
 
  return false;
}

and for players/bots specific

Code:

// Check if a player is valid
// CheckAlive(default true): check if this player is alive, if not return false
// CheckObserver(default true): If observer mode on and if this player is NOT a bot return false
bool UTIL_IsValidPlayer(CBasePlayer *pPlayer, bool CheckAlive, bool CheckObserver)
{
        if (!pPlayer || !pPlayer->pev)
                return false;
 
        if (IsNull(pPlayer))
                return false;
       
        if ((CheckObserver) && (BotManager.ObserverMode()) && (!UTIL_IsBot(pPlayer)))
                return false;
 
        if (FStrEq(STRING(pPlayer->pev->netname),""))
                return false;
 
        if ((CheckAlive) && ((!pPlayer->IsAlive()) || (pPlayer->m_fObserverFlag)))
                return false;
 
        if (!(pPlayer->pev->flags & FL_CLIENT))
                return false;
 
        return true;
}


Pierre-Marie Baty 02-02-2005 23:53

Re: Safe to keep edict_t pointers ?
 
In the HL1 engine, it is safe to keep track of entities either by pointer, or by index. Entities (at least their edict_t) don't get relocated by the engine in memory. However, some slots in the entity list may be empty, because of entities that are created and destroyed dynamically. Typically, entity #0 is worldspawn, entities #1 to #maxClients are player slots (the listenserver being NOT NECESSARILY entity #1), entities from #maxClients+1 are the map's entities, beyond are the dynamically spawned ones and even beyond are the temporary entities.

Be aware that the HL1 engine can leave bad entity pointers around, i.e. edict_t pointers that are not NULL, that do point to somewhere, but where there's no more edict_t structure behind. That's why I highly recommend to check your edict_t pointers with FNullEnt() as often as possible. BE AWARE AGAIN though, that the FNullEnt() provided in the HL1 SDK is itself buggy! it does NOT make enough checks to test for an edict pointer's validity! You also have to check if the entity classname is defined, like this:

Code:

// fixed FNullEnt(). You can trust this one.
#define SAFE_FNullEnt(a) (((a) == NULL) \\
                                                || ((*g_engfuncs.pfnEntOffsetOfPEntity) (a) == 0) \\
                                                || ((a)->v.classname == NULL) \\
                                                || (STRING ((a)->v.classname)[0] == 0))

Use this one everywhere, but for checking the edict_t returned by pfnCreateFakeClient(), since for this one the "player" classname is not set yet (it is set during the game DLL's "player" call).


All times are GMT +2. The time now is 09:20.

Powered by vBulletin® Version 3.8.2
Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.