Any progs.dat/QuakeC risks reusing free edicts?

Discuss programming topics for the various GPL'd game engine sources.
Post Reply
Baker
Posts: 3666
Joined: Tue Mar 14, 2006 5:15 am

Any progs.dat/QuakeC risks reusing free edicts?

Post by Baker »

I see this in the RMQ engine ...

It will reuse edicts if the protoocol limit for MAX_EDICTS is hit. This pretty damn unlikely in the RMQ engine since it's protocol limit is 65536.

Are there any risks in re-using free edicts? Client baseline comes to mind?

Code: Select all

		// if we hit the absolute upper limit just pick the one with the lowest free time
		float bestfree = pr_progs->time;
		int bestedict = -1;

		for (i = pr_progs->first_edict; i < pr_progs->num_edicts; i++)
		{
			e = GetEdictForNumber (i);

			if (e->free && e->freetime < bestfree)
			{
				bestedict = i;
				bestfree = e->freetime;
			}
		}

		if (bestedict > -1)
		{
			e = GetEdictForNumber (bestedict);
			ED_ClearEdict (e);

			return e;
		}
		// no free edicts at all!!!
		Host_Error ("ED_Alloc: edict count at protocol maximum!");
The night is young. How else can I annoy the world before sunsrise? 8) Inquisitive minds want to know ! And if they don't -- well like that ever has stopped me before ..
Spike
Posts: 2914
Joined: Fri Nov 05, 2004 3:12 am
Location: UK
Contact:

Re: Any progs.dat/QuakeC risks reusing free edicts?

Post by Spike »

all engines reuse entities, if they're free.
you get a 2-second grace time before the entity can be reused (except during initial spawn, when the grace time is ignored completely).
if you exceed the limit then you get engine-specific behaviour (either reusing entities before the grace time runs out, or just out-right crashing).

if an engine doesn't give 2 seconds grace, then yeah, expect problems with mods that expect it.
players also go through a 2-sec zombie state on disconnect, preventing their slot from being reused and sucking up any warnings about bad packets. or maybe this is qw only.

only entities present just after spawn are given any baseline info. these entities are also assumed to remain valid for the entire game. its not really a problem if they're not, but meh.
Cobalt
Posts: 445
Joined: Wed Jun 10, 2009 2:58 am
Location: New England, USA
Contact:

Re: Any progs.dat/QuakeC risks reusing free edicts?

Post by Cobalt »

Recently I became aware that nextent() will point to a free edict, at least in regard to DP.

DP luckily has a "wasfreed" () function to detect if it is a currently free edict, so I was able to continue past and ignore them because my code was only really looking for active edicts. The engine seems to decide / keep track of them, and its possible the engine will re-use a previously freed edict. Not sure if its a convienience based calculation based on RAM, or completely random.

Also, of note, if you makestatic() the ent during the game, or I think after the worldspawn() / Quaked stuff , its completely removed from the game....wont show on the ent list....but the engine will draw it for new clients entering an MP game. Becomes part of the sign on message if I recall?
Spike
Posts: 2914
Joined: Fri Nov 05, 2004 3:12 am
Location: UK
Contact:

Re: Any progs.dat/QuakeC risks reusing free edicts?

Post by Spike »

nextent() is meant to skip free entities... sounds like a DP bug.
wasfreed() comes from FTE. :)
makestatic() acts as a remove(), yes. the entities visuals become handled by the engine somehow (svc_spawnstatic inside the msg_init buffer, if you must know). this builtin might be buggy if you call it at any point other than during spawn functions (ie: players currently on the server won't see additions to the msg_init buffer, although some engines *might* fix this by writing to both msg_init and msg_all although you might still see some flickering).
Cobalt
Posts: 445
Joined: Wed Jun 10, 2009 2:58 am
Location: New England, USA
Contact:

Re: Any progs.dat/QuakeC risks reusing free edicts?

Post by Cobalt »

Could be a bug, or intended to be that way. Depends on weather or not you believe the freed ent is still really an ent if it was freed up already. I say, yea it would be technicly, but of course its now an irelevent ent in regards to what the progs considers otherwise useful in some way.

If you were to be debugging, and wanted to count how many ents in your mod of a certain class wound up being freed, I guess this could be a way to find them and count them....in code that may otherwise not be removing any other ents for example.

wasfreed() is def a neat one, glad you added it.

Strange , to me remove () should act more like makestatic () as the remove does not really remove the ent, "frees" it up, is not the same as completely discarding it, which is closer to what makestatic does - if you go nextent and walk down the ent list, you wont find any makestatic ents ever.

I did have a need for something along these lines where I was redoing the bubbles code for the air bubbles, and in the case where the bubble traveled up and was blocked by a piect of the map sticking out, it would travel randomly around , and if it could now move past the obstacle, it would begin traveling up again. The case where it would never find an exit would be a timeout after moving around for a long time, then I would count how many of those cases there are, and if too many would be an fps hit, I decided instead of removing them, use makestatic. Of course if you watched this process happen, the bubble would disappear, unless you reconnected...then you would see the bubble in the last place it was at, not moving. Experiment concluded, though it would be nice if you could classify those kinds of ents somehow so that they dont disappear, or somehow get them to be only moving around a small fraction of what they use to and have it only client side. Perhaps csqc would be a possibility?
Spike wrote:nextent() is meant to skip free entities... sounds like a DP bug.
wasfreed() comes from FTE. :)
makestatic() acts as a remove(), yes. the entities visuals become handled by the engine somehow (svc_spawnstatic inside the msg_init buffer, if you must know). this builtin might be buggy if you call it at any point other than during spawn functions (ie: players currently on the server won't see additions to the msg_init buffer, although some engines *might* fix this by writing to both msg_init and msg_all although you might still see some flickering).
Spike
Posts: 2914
Joined: Fri Nov 05, 2004 3:12 am
Location: UK
Contact:

Re: Any progs.dat/QuakeC risks reusing free edicts?

Post by Spike »

Cobalt wrote:Strange , to me remove () should act more like makestatic () as the remove does not really remove the ent, "frees" it up, is not the same as completely discarding it, which is closer to what makestatic does - if you go nextent and walk down the ent list, you wont find any makestatic ents ever.
what the hell? The *only* difference between the two is that makestatic splurges some visible stuff into the MSG_INIT(in qc terms) buffer.

Code: Select all

//gpl, everyone flee in terror (vanilla quake)
void PF_Remove (void)
{
	edict_t	*ed;
	
	ed = G_EDICT(OFS_PARM0);
	ED_Free (ed);
}
void PF_makestatic (void)
{
	edict_t	*ent;
	int		i;
	
	ent = G_EDICT(OFS_PARM0);

	MSG_WriteByte (&sv.signon,svc_spawnstatic);

	MSG_WriteByte (&sv.signon, SV_ModelIndex(pr_strings + ent->v.model));

	MSG_WriteByte (&sv.signon, ent->v.frame);
	MSG_WriteByte (&sv.signon, ent->v.colormap);
	MSG_WriteByte (&sv.signon, ent->v.skin);
	for (i=0 ; i<3 ; i++)
	{
		MSG_WriteCoord(&sv.signon, ent->v.origin[i]);
		MSG_WriteAngle(&sv.signon, ent->v.angles[i]);
	}

// throw the entity away now
	ED_Free (ent);
}
See, both call ED_Free.
While an engine could make the QC crash if it tries poking an entity that was removed, doing so would be suicide as it would cause about 99.9% of mods to crash...
if you want to prevent the engine from reusing an entity index, you should simply never bother removing the entity... then it'll crash when you start spamming rockets. hurrah. so yeah, don't do that.

the wasfreed() builtin is kinda evil, you probably shouldn't use it. if you do need to use it then its probably because you're being too lazy. you get greater compatibility from seeing if the classname is still valid. the one place where its useful is if you're calling random think functions and making sure the entity is still valid afterwards.
Post Reply