question about antilag


(SCDS_reyalP) #1

How is the head position calculated ?

If I understand correctly, the origin and bounds of the player are recorded in the history. Then, when a historical trace is done, all the potential victims are set back to their historical positions and G_BuildHead is called. So the head position (relative to the historical origin) would be based on the most recent look angles and crouch/prone state, rather than those that existed when the origin was stored. The head and leg entities are used here to make sure hits to these (which might be outside the main bbox) are counted against the target.

But that (while a bit questionable) isn’t the end of the story, because IsHeadShot (where actual damage is given out) doesn’t even do a historical trace :???:

What am I missing here ?


(Lanz) #2

Hmm, it seems like you are right. The historical data only store max, mins and origin of the player and not the eflag or pm_flag etc. So teoretically if you run forward under fire from a lagged player and then crouch or prone, the antilag would calculate a headshot as a miss. I didn’t look that close at the code but it sure looks like that.

Second question I’m not sure what you mean because the historical trace is already done before entering g_damage thus already using the old origin. Might have misunderstod the question though.


(SCDS_reyalP) #3

I don’t think so, because G_HistoricalTrace restores the client positions before it completes. G_Damage then it’s own G_BuildHead, and a plain old trap_Trace (via IsHeadShot). But I admit that I haven’t fully groked all that code, so I might well be missing something. :moo:


(Lanz) #4

Yeah I took another look and you’re right.


(SCDS_reyalP) #5

:bump:

Actually, I’m wrong. Under most circumstances, it looks like G_ReAdjustSingleClientPosition will never restore the position.


	if( ent->client->backupMarker.time == level.time) {
		VectorCopy( ent->client->backupMarker.origin,		ent->r.currentOrigin );
		VectorCopy( ent->client->backupMarker.mins,			ent->r.mins );
		VectorCopy( ent->client->backupMarker.maxs,			ent->r.maxs );
					ent->client->backupMarker.servertime =	0;

		trap_LinkEntity( ent );
	}


A cookie for anyone who can show me where ent->client->backupMarker.time is set.

As far as I can tell, this means that IsHeadShot does use the the ‘re-wound’ position (verified by a bit of good ol printf debugging). I’m not sure what the implication of the backup (i.e most recent) info never getting restored is.

Comparing to the the RTCW code is, erm, informatative. In RTCW, the test for backupMarker.time is commented out (along with the lines which set it), so it most likely does use the wrong time for IsHeadshot.

Finally, POSITION_READJUST is a truely fine example of how to use macros :banghead: Expand it inline, and you will see what i mean. :moo:


(bani) #6

:moo: :moo: :moo: :moo: :moo:

its not set anywhere… :eek:

:moo: :moo: :moo: :moo: :moo:


(SCDS_reyalP) #7

:moo: :moo: :moo: :moo: :moo:

its not set anywhere… :eek:

:moo: :moo: :moo: :moo: :moo:[/quote]
You didn’t think I would actually risk having to give out a cookie did you ?

Mmmmm cookie!!! Almost as good a pai!


(pgh) #8

Its not the cookie… its cos its Bani innit… INNIT ADMIT IT!!

cookies2good4bani.


(Rain) #9

After additional poking, we found even more fun bits about antilag…

[ul][li]The knife isn’t antilagged (fix: use G_HistoricalTrace in Weapon_Knife)[]bani noticed that emplaced MG42s aren’t antilagged (fix: use activator as the entity for G_HistoricalTrace in Fire_Lead_Ext instead of ent)[]And my favorite: The maximum amount of latency reduction that will be performed by antilag is dependent on the framerate of your target.
[/li]
Markers are added every ClientThink (so, once per cmd), and only 10 markers are stored, therefore (assuming cl_maxpackets is high enough), if your target is running at 100 fps, you will get no more than 100ms of lag compensation ((1000ms / 100 fps) * 10 markers.) cl_maxpackets is capped at 100. Quick solution: store more markers (e.g. 100) and cap the maximum amount of lag compensation done. Better solution: Use the entitystate origins in the markers (because these are what get sent to clients) and add the markers on server frames and lerp between them when backing up the client position.

EDIT: While the markers are updated every ClientFrame (and this is still silly), the marker isn’t incremented until the next server frame, so it’s not as bad as originally thought. ET’s antilag is still about 60ms behind, though. :eek2:
[/ul]
FWIW, the failure to set backuptime should be Mostly Harmless in the antilag code as-is, since it will likely get clobbered again with the real origin before anything else interesting happens using that origin. If you decide to let clients enable/disable antilag on their own, though (i.e. the antilag configuration won’t be the same for all clients), it’s definitely something you’ll want to fix. :zzz:


(SCDS_reyalP) #10

Are you sure about that ? void G_StoreClientPosition is run once per client think, but


		// new frame, mark the old marker's time as the end of the last frame
	if( ent->client->clientMarkers[top].time < level.time) {
		ent->client->clientMarkers[top].time = level.previousTime;
		top = ent->client->topMarker = ent->client->topMarker == MAX_CLIENT_MARKERS - 1 ? 0 : ent->client->topMarker + 1;
	}


should make sure top only advances when there is a new server frame (since level.time only gets updated once per frame). Or is there some reason that doesn’t work ?

edit:
No, it doesn’t. It might be supposed to, but it doesn’t.
:moo:

edit:
because of this


currentTime = level.previousTime + trap_Milliseconds() - level.frameTime;

level.previous is always 50ms less than the current level.time (for sv_fps 20). The other bit just gets us the number of MS that have elapsed since the start of the frame (although the comment for trap_miliseconds says it should only be used for benchmarking, not game related code… Since we just using the difference, it might be OK). So ‘currenTime’ is 50 ms in the past, and so will always be less than level.time when we go to check it (barring exceptional circumstances, like maybe an overloaded server). :banghead:


(bani) #11

can it get worse?

yes. yes it can.

in G_HistoricalTrace() it does a trace vs a client’s backward reconciled position.

then in order to prevent the perception of ‘being shot around corners’, it does a trace to the player’s non-reconciled position.

but – it traces to the non-reconciled ps.origin

why is this bad?

say you hit a moving player. with your backwards reconciled hit, you hit them in the left shoulder. the player was moving, and their non reconciled position has their ps.origin now blocked by an obstacle (say something like a waist high box) but their shoulder is still unblocked and hittable.

with the current etmain antilag code that will be counted as a miss! :moo:


(SCDS_reyalP) #12

Yes the ‘anti-BS’ code is BS. In many ways…


		trap_Trace( &tr, start, mins, maxs, other->client->ps.origin, passEntityNum, contentmask );
		res = G_SwitchBodyPartEntity(&g_entities[results->entityNum]);
		POSITION_READJUST

That trace doesn’t put its results into ‘results’, so the SwitchBodyPartEntity is pointless. Res already got set above. POSITION_READJUST is similarly pointless…
GG cut & paste.

Never mind that POSITION_READJUST repeatedly calculates ‘dir’ from fixed inputs…

BTW (for anyone following from the sidelines), all the stuff in this thread except for the backumarker thing exist in RTCW too.


(Rain) #13

I should add that if you fix backupMarker.serverTime so that the original position is restored, you’ll need to re-antilag the shot for the headshot check, or the head will be attached onto the non-reconciled position. We overlooked this at first. :angry:


(TwentySeven) #14

Aight. We’ve been there, done that with the UrT antilag.
How ET is doing it now, is how UrT was doing it during the 2.x era. Its bad.

Four Things:

  1. Get rid of the anti BS code. It creates more problems then it fixes.
  2. Store the client markers in ClientEndFrame() - this is their position right before the snapshot is generated, therefore it is where the clients are seeing players.
  3. Store the client markers with level.time as the timestamp. NOT some weird gettime timer thingy. Level.time is the time of the position in the snapshot. which is what we want.
  4. use cmd.servertime for the lookup of the shots (probably already is)

there are no +50ms -50ms tweaks needed.
Anyway, storing the position each client cmd is about the worst thing you can do. it makes hitting hpb’s harder, and it makes hitting people with differeing ping a different experience.

IF you want any more info on this I can be contacted at TwentySeven@urbanterror.net or just post your questions here.

I might even cough up how to do antiwarp. (and no, not that insanely complex stuff in neils unlagged mod, either)


(bani) #15

zinx already worked out antiwarp for etpro… curious to know how you implemented it though.


(bani) #16

this is basically a 1:1 description of neil’s original unlagged1.0 / 1.1 code from way back when (and what I used in banimod wayyyy before it was ever introduced into rtcw).

has UrT diverged from neil’s unlagged code in any significant way?

i’ve got unreleased unlagged2 code from neil i should dust off and look at putting in ET…


(TwentySeven) #17

Neils code in unlagged 1 worked the same way as ET’s does. Stores it on the incoming cmd’s.

I think neil might have fixed it for unlagged 2 but we went over to a fresh implementation.

As for it being different… I’d have to check. The biggest fixes from unlagged 1.1 is using level.time as the marker, and storing only at the EndFrame.

Our antiwarp works differently, yes.

How ours works is each server think, if a client is “late” with cmd’s, we generate an empty one (sans buttons that need holding down like priming a grenade or climbing a ledge), and feed the cmd in with a timestamp that’d keep things reasonable. So clients are forced to run at least one cmd per snapshot, thus, the warping client will feel a tiny bit of “ropeyness” as the difference in prediction kicks in, but to everyone else he doesn’t warp.

Its benefits are that
A) it moves the onus of a client warping to the warping client’s side of the connection- it doesnt affect other users.
B) there is never a “pause” like in the etpro stuff, a client can’t just freeze in mid-air waiting for new cmd’s.
C) it has no “ping buildup” like the current etpro stuff describes.


(TwentySeven) #18

Also, just a quick bit of history

UrT had its own unlagged stuff written by apoxol in beta 2.0, predating neils work by almost a year.
during 2.4, dok8 switched out the urt stuff for a version of neils 1.1 code, which worked better for hpbs but was broken for lpb’s shooting hpbs and lots of other issues that plagued us all the way through 2.4 through to 2.6a.

During 3.0 dev I tossed the whole lot and wrote a fresh implementation, also implementing a debugger (g_antilagvis 1) - it places a marker clientside every time you fire a shot for rendered clients, and then sends down an ent of the history lookup during the shot check on the server.

It’s never off by more then a couple of game units, even at our zippy player speeds/model sizes.


(SCDS_reyalP) #19

FWIW, the unlagged 2.x source is available from http://www.planetquake.com/alternatefire/

Although I have not gone through it in detail, it seems a lot more solid than the ET/RTCW code, and includes various debugging stuff as well.

It also has some documentation which I highly recommend any would be ET modder read.


(bani) #20

we tried this approach the first time around and it didn’t work very well at all. too many clients are too often late with cmds and find it too difficult to play with all the prediction error. most people have crappier connections than you would think. basically forced server thinks made the game completely unplayable for an entire class of players. we couldnt simply tell them to go away.

zinx came up with the current alternative when it became obvious the forcing server thinks didn’t work so well.