|Date:||12/3/2003 4:56:51 AM|
|Subject:||RE: Dynamic thinking entities: A study in opti|
That's what static and I were just talking about. Currently to keep the Autonomous/Bot AI sane I added allot of boolean (true,false) indexes to the entities for rockets, deployables, and grenades. If it's this->type avoid it, if it's this->type2 shoot at it, if it's this->type3 shoot it at all costs and don't avoid this->type, if (boolean) HasFlag(this) do that. (recon avoiding goodyears, marines shooting lasers, cyborg going nuts and ignoring everything). the final product looks like a mess (if you've never worked with fortran or cobol) with tons of | and && and ()'s everywhere; formatted but still a mess.
And still allot of index lookups. I was ready to use the same approach to the dynamic think.
What static suggested for the dynamically thinking function was adding bitflags at entity creation. Since there are only about a dozen different types of entities that I could ever possibly worry about, it would make it allot easier and more efficient as I can put the target 'bit(s)' in the actual function call. (I can also rape the same style for the Bot AI and eliminate about 20 lines of code per bot per function.)
There are only a few places where the target's flags would change; when the person dies or changes teams (including going spec), or at a call ClientUserInfoChanged when the person changes class, skin, weapon, or anything else that's meant to be broadcast to the rest of the clients as a change in the client's "state".
Additionally the flags are not sepecific to the dll; they are done in the main engine include header itself and passed over to the dll's that use em. I can already think where this could be used in the main binary and the client module later on.
With my test code running I fired up 14 bots and made them constantly spam UNLIMITED goodyears at each other (ok, well I can do this and it looked funny as hell with q3ctf all lit up) and let the dedicated server run. I was using maybe 2% processor on my dual, and 10 megs. bots are clients. (on a side note max_entites limit is client side, I couldn't connect to check in on them after a while but they were still running around getting flags, killing each other and the like)
I also look at loads of debugging information for the process on windows; how frequent the memory calls are, faults, etc. and it did chop memory calls down to 7% of what it formerly was with stock code on a small map like q3ctf1.
See there are ALLOT less entities on q3ctf1 then the average weaponsfactory map... could call it entityfactory. I'd say roughly that there are usually 3x more map-based entities to check on wfa maps then there are on stock q3 maps. (I have the server print out statistics on entities after the engine loads them). In q3 there are no deployables, in wf a full pub server can have over 50 at any one time if you think about it.
all in all there are about 40 items that think every server frame, or hyperthink. 40 items with a vector distance math check to close to 400 world entities (with players, not counting dynamic ents like gibs, deployables, rockets, etc) before it gets to the 20 players before it gets to the 10 enemy teammates is still allot of thinking.
And if a player passes within that sweet-range the player might get a allot of process calls into the area before the entity gets a chance to do it's thing in the process order and react.
that's why wf/wfa is the mod it is; and why its such a bitch to code on the low-level side when you have to decide what to do for each process cycle.
oh the server rate in processing frames; I'm working on adding a sv_fps equivalent for networking reasons. I will boost it during testing; to the point where my upstream just can't handle it anymore and prediction errors occur out the wazoo.
the game and the client are pretty much done at this point except for some of the AI; its running stable. I am cleaning up code, cvars and putting off the ui as much as I can at this point... and happened upon something I created when starting the cgame/game split in order to consolodate thinking for the turrets, proxies, and goodyears.
right now it's ent->nextthink = leveltime + DynThink(ent);
DynThink ent is a float return. I can just go to each hyperthinking ent and copy/paste it and any other passing bits if it works as intended. So far i have the prediction down pat, its the possible 'enemy' that I wish to check.
To be honest (and you read it here first) I 'un-unlagged' the clients. The way I approached it is exactly the way I approached the kami's "matrix" shell, and after I put my code in I decided to look at unlagged source. unlagged is nothing other then storing past origins and figuring out where they were; I figure out where they probably are going to be. It's based on the same concept of storage but I use patterned vectors, a weight system, and velocity.
I don't mind err on the side of caution because there are no visual effects. If it does err, it will correct itself just that much more quickly. Call it Bizarro Unlagged.
if it works, it works. if it doesn't its a cvar that can change it to just default to a return of .1, thats why this thread.