View previous topic :: View next topic |
Author |
Message |
DieparBaby

Joined: 05 Dec 2006 Posts: 44 Location: London, Ontario, Canada, eh
|
Posted: Fri Dec 15, 2006 9:58 pm Post subject: When can I be sure all entities are spawned? |
|
|
I would like entity A to count the number of entity Bs.
I would like entity A to do this at or near the time the map is loaded.
I'm afraid that if entity A is spawned first and does the counting process in its spawn
method that it will miscount the number of entity Bs because some entity Bs may be
spawned after entity A.
When is a good time to or method in which to count entity B. I could get away with
just counting entity Bs without entity A but that is not ideal.
Thanks,
DieparBaby |
|
Back to top |
|
 |
Quake Matt

Joined: 05 Jun 2005 Posts: 129
|
Posted: Fri Dec 15, 2006 10:11 pm Post subject: |
|
|
I don't know exactly, but by general programming methods entities would be spawned sequentially based on the order in which they are listed in the map file. So, doing a check during the spawning sequence wouldn't be a good idea, since it'd be very likely to miscount. Basically, exactly what you were worried about!
If you want an entity to perform the count, I'd recommend doing it after about 0.1 or 0.2 seconds on a .think function. I think 0.2 seconds is how long it takes for a client to be 'woken up' or something, so the delay won't be noticable, and it ensures that everything's been spawned in time.
A more efficient way, if it's possible in this context, is to create a global variable to store the count, then whenever one of these entities is spawned, just add +1 to it.
Hope this helps! |
|
Back to top |
|
 |
DieparBaby

Joined: 05 Dec 2006 Posts: 44 Location: London, Ontario, Canada, eh
|
Posted: Sat Dec 16, 2006 2:06 am Post subject: |
|
|
Very much. I like that global variable idea. I figured a delay would be in order and I can live with it.
Thanks QuakeMatt,
DieparBaby |
|
Back to top |
|
 |
Lardarse

Joined: 05 Nov 2005 Posts: 243 Location: Bristol, UK
|
Posted: Tue Dec 19, 2006 1:22 pm Post subject: |
|
|
QuakeMatt is right. It's probably a lot easier to count in the entities' spawn functions, unless you know that this number will change during the map. |
|
Back to top |
|
 |
Quake Matt

Joined: 05 Jun 2005 Posts: 129
|
Posted: Tue Dec 19, 2006 1:47 pm Post subject: |
|
|
If it's going to change, you could just deduct one from the counter when an entity's removed. A little more book-keeping, I know, but it shouldn't be too tricky most of the time. |
|
Back to top |
|
 |
FrikaC Site Admin

Joined: 08 Oct 2004 Posts: 947
|
Posted: Wed Dec 20, 2006 6:21 am Post subject: |
|
|
To answer the question of the topic (QuakeMatt's methods are ideal for counting entities, so ignoring the problem and answering the question) you can be sure that all map entities that will be spawned and kept are done by the second frame, and all have been spawned by the first frame.
When Quake initializes a map, it runs all the spawn functions for each map entity, then it runs two server frames back to back. This allows all entities to 'settle': items will droptofloor(), doors will link and so forth.
After these two frames, Quake makes baselines of all entities (used for the network 'delta' compression: Quake sends the baselines to connecting clients, and then only sends differences from these baselines in entity update packets).
So after two server frames one should be assured that everything is in it's final state. The first server frame begins just after the entities are all spawned, so that's useful as well. The problem becomes when to trap it. Quake's frames, as described in the FrikBot dissection, each begin with a call to StartFrame then a call to the .think() function of each entity in turn provided the .nextthink value is greater than zero and less than the current time.
The easiest way therefore is to tap into StartFrame(), and keep an eye on the framecount var id set up there (or make one if you code doesn't already have one). Upon entering the first server frame, after every entity has spawned, framecount will be 0. After the first frame and beginning on the second, framecount should be 1.
You could also trap the second frame using a .think function (not the first for reasons I will discuss).
When Quake runs the two first frames it locks in the frametime to 0.1, but time (the variable) doesn't update untill the end of a frame, thus the first frame runs at a time value of 0 and the second at time 0.1. Since the restriction on nextthink is it must be a value greater than 0, you can make the nextthink of an entity equal 0.001 (or any value between 0 and 0.1) when it is first spawned in the map, and it will occur in the second server frame.
The reason you can't trap the first frame, then, is that you need to have a nextthink between 0 and the current time, which would also be 0.
I know this is a far more technical description than you probably wanted or needed, but the subject of how to trap the first two frames is something people who are doing more advanced QuakeC need to know if they don't already, and I thought I'd take the time to explain it as best I can. _________________
 |
|
Back to top |
|
 |
DieparBaby

Joined: 05 Dec 2006 Posts: 44 Location: London, Ontario, Canada, eh
|
Posted: Wed Dec 20, 2006 2:31 pm Post subject: |
|
|
Thanks FrikaC. That's very helpful. I'm always interested in knowing the in and outs of Quake C. |
|
Back to top |
|
 |
Lardarse

Joined: 05 Nov 2005 Posts: 243 Location: Bristol, UK
|
Posted: Fri Dec 22, 2006 11:48 am Post subject: |
|
|
Thanks, Frik. Even I learnt something there... |
|
Back to top |
|
 |
Sajt
Joined: 16 Oct 2004 Posts: 1026
|
Posted: Sat Dec 23, 2006 10:33 am Post subject: |
|
|
Great job kids! You guys have skills that even I'M impressed with!
Anyway good job FrikaC, even the great I learned something! _________________ F. A. Špork, an enlightened nobleman and a great patron of art, had a stately Baroque spa complex built on the banks of the River Labe. |
|
Back to top |
|
 |
LordHavoc
Joined: 05 Nov 2004 Posts: 243 Location: western Oregon, USA
|
Posted: Wed May 23, 2007 6:01 pm Post subject: |
|
|
FrikaC wrote: | When Quake runs the two first frames it locks in the frametime to 0.1, but time (the variable) doesn't update untill the end of a frame, thus the first frame runs at a time value of 0 and the second at time 0.1. Since the restriction on nextthink is it must be a value greater than 0, you can make the nextthink of an entity equal 0.001 (or any value between 0 and 0.1) when it is first spawned in the map, and it will occur in the second server frame. |
Sorry to inform you but you got two things wrong:
- time begins at 1.0, then goes to 1.1, then 1.2 is the first real frame (when clients who are already connected are told to login, etc), so there is no issue with nextthink = 0 because the nextthink would be 1.0 the way you're thinking about it.
- nextthink is not triggered if it is 0 or > time + frametime, note the use of frametime (which is 0.1 on these first two frames).
So basically, entities are spawned (with time = 1.0, frametime = 0.0), then two physics updates are done (which call think functions in the time range 1.0 to 1.1 with frametime 0.1, and 1.1 to 1.2 with frametime 0.1), you want to get any delayed init code done by the end of the second physics frame so that the baselines are correct.
I think the ideal nextthink to play it safe is Code: | self.nextthink = time + 0.15; | but the > time + frametime check means that time + 0.2 should work fine as well.
That is definitely going to happen in the second physics frame, before baselines are locked in.
The id code uses some + 0.1 and some + 0.2, I'd play it safer by using + 0.15 though. |
|
Back to top |
|
 |
FrikaC Site Admin

Joined: 08 Oct 2004 Posts: 947
|
Posted: Thu May 24, 2007 1:48 am Post subject: |
|
|
LordHavoc wrote: |
Sorry to inform you but you got two things wrong:
- time begins at 1.0, then goes to 1.1, then 1.2 is the first real frame (when clients who are already connected are told to login, etc), so there is no issue with nextthink = 0 because the nextthink would be 1.0 the way you're thinking about it.
- nextthink is not triggered if it is 0 or > time + frametime, note the use of frametime (which is 0.1 on these first two frames).
|
No, sorry, you're wrong. Time begins, from the perspective of the QC, at 0 not 1.0.
Take a look at SV_SpawnServer in detail. Quake loads the progs first. The QuakeC variable "time" will be initialized to whatever the QuakeC compiler set it to, in order to remain perfectly compatible with Quake, it will be set to 0.
Next it sets sv.time to 1.0 as you say, but this has no effect on the pr_global_struct->time, QuakeC's view of the time variable. Then it runs the first physics frame, during which time will still be 0 because the update for pr_global_struct->time will not occur until after the frame is over. So time, from the perspective of QuakeC will be 0.0 then 0.0 and finally 1.1 on the first two frames. I was slightly incorrect in saying it would be 0.1 and not 1.1, but it is basically functionally identical to as I described.
I never tested the time value from QuakeC on the second frame (and when I learned all this stuff, the Quake source was unavailable). Also when I researched this to explain it in detail, I somehow overlooked the sv.time = 1.0; line tucked in there, but it does very little from the perspective of QuakeC.
Quote: |
I think the ideal nextthink to play it safe is
Code: |
self.nextthink = time + 0.15;
|
|
Which will fire on the first frame, because the value of nextthink will be 0.15 (time = 0). sv.time, what it is actually compared against, will be 1.0 (+ frametime, 1.1). Upon execution time will NOT advance to the correct sv.time, but be back dated to 0.15, so again, basing it off of time will still be incorrect even within that think function.
Quote: | nextthink is not triggered if it is 0 or > time + frametime, note the use of frametime (which is 0.1 on these first two frames). |
Also incorrect. think is not triggered if nextthink <= 0 or greater than sv.time+frametime. The 'less than' part is important to note in this case because it means you cannot set nextthink to -1 and have it work.
My statement as far as "less than the current time" was just a generalization, I didn't state exactly what it was compared against, so I hardly 'got it wrong'.
From a QuakeC perspective, time is always advanced to the nextthink value when the think runs, so prior to the source release it was impossible to determine when exactly the think ran in relative terms to time, I was speaking from QuakeC experience, not from knowing the engine code too well. So the term 'current time' was a little vague and not perfectly accurate. Sue me. |
|
Back to top |
|
 |
LordHavoc
Joined: 05 Nov 2004 Posts: 243 Location: western Oregon, USA
|
Posted: Thu May 24, 2007 2:08 am Post subject: |
|
|
FrikaC wrote: | No, sorry, you're wrong. Time begins, from the perspective of the QC, at 0 not 1.0. |
That's bizarre, I should fix that in DarkPlaces so that the id code works as it was intended to. |
|
Back to top |
|
 |
FrikaC Site Admin

Joined: 08 Oct 2004 Posts: 947
|
Posted: Thu May 24, 2007 2:21 am Post subject: |
|
|
FrikaC wrote: | You could also trap the second frame using a .think function (not the first for reasons I will discuss).
|
Sorry, you're also wrong. Because sv.time is set to 1.0 on startup, thinks will indeed fire on the first frame, because that's what they're actually compared against. Any value between 0 to 1.1 (See above) will work for the first frame. |
|
Back to top |
|
 |
LordHavoc
Joined: 05 Nov 2004 Posts: 243 Location: western Oregon, USA
|
Posted: Thu May 24, 2007 5:19 am Post subject: |
|
|
id code has dumbfounded us again, with cleverness or dumbness, either way  |
|
Back to top |
|
 |
Preach
Joined: 25 Nov 2004 Posts: 122
|
Posted: Fri May 25, 2007 6:17 pm Post subject: Re: When can I be sure all entities are spawned? |
|
|
On a fairly related note, does anyone know why is it that the startup sequence behaves differently when you have the console is down as you start the map, as opposed to when you don't. It causes all sorts of entity related bugs and so knowing why it happens might allow a fix on the qc side for some of the bugs. At the very least, understanding what causes it should allow an engine side fix... |
|
Back to top |
|
 |
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2004 phpBB Group
|