SV_Invisible_To_Client (Anti-Wallhack)

Post tutorials on how to do certain tasks within game or engine code here.
Team Xlink
Posts: 368
Joined: Thu Jun 25, 2009 4:45 am
Location: Michigan

Post by Team Xlink »

Yeah, your right Downsider.


The Server/s I will be hosting our going to have professional Quality Connection, but most of them will be running our official stuff.

The Fans who want to run modified servers are who I am worried about, some people still try to host on Dial-Up. :(
r00k
Posts: 1111
Joined: Sat Nov 13, 2004 10:39 pm

Post by r00k »

the 64 can be set as a cvar i used it cause on dm3 certain areas had flashing players, increased to 64 fixed it. A timer would atleast create a base time to draw so all servers update at the same rate.
LordHavoc
Posts: 322
Joined: Fri Nov 05, 2004 3:12 am
Location: western Oregon, USA
Contact:

Post by LordHavoc »

r00k wrote:the 64 can be set as a cvar i used it cause on dm3 certain areas had flashing players, increased to 64 fixed it. A timer would atleast create a base time to draw so all servers update at the same rate.
The timer isn't to make things consistent, it makes players flicker less than they would otherwise.

Each time a trace succeeds, it renews the timer, it still does the trace even if the timer is in the future, constantly renewing it.
mh
Posts: 2292
Joined: Sat Jan 12, 2008 1:38 am

Post by mh »

LordHavoc wrote:
r00k wrote:the 64 can be set as a cvar i used it cause on dm3 certain areas had flashing players, increased to 64 fixed it. A timer would atleast create a base time to draw so all servers update at the same rate.
The timer isn't to make things consistent, it makes players flicker less than they would otherwise.

Each time a trace succeeds, it renews the timer, it still does the trace even if the timer is in the future, constantly renewing it.
OK, if I'm getting this straight the logic seems to be:

Trace is always done irrespective of timer value, but a lower number (I'm thinking 8 or even as low as 4) of traces can be done.

If the trace hits the entity, the timer is incremented by 0.2; the result of the trace has no other purpose.

If the timer is in the future the entity is sent.

So in other words what we're really doing here is splitting a large number of tests across a number of frames, and reusing recent results (up to a certain limit). :D

Yup, that seems to make sense to me.

_________________________________________

Edit: yeah, it works. :D

I got the number of traces down to 4 (my own tests indicated that the vast majority of entities will get a successful hit in the first 1 or 2 traces, so 4 seems reasonable). No visible flicker, the only artefact is that an entity which should be culled will remain visible for a very brief time period after it goes behind a wall, which I don't consider a big deal as you will have already seen it before it went behind the wall and will therefore know where it is anyway.

Here's the new code for the relevant part of the function:

Code: Select all

	for (i = 0; i < 4; i++)
	{
		end[0] = seen->v.origin[0] + offsetrandom (seen->v.mins[0], seen->v.maxs[0]);
		end[1] = seen->v.origin[1] + offsetrandom (seen->v.mins[1], seen->v.maxs[1]);
		end[2] = seen->v.origin[2] + offsetrandom (seen->v.mins[2], seen->v.maxs[2]);

		tr = SV_ClipMoveToEntity (sv.edicts, start, vec3_origin, vec3_origin, end);

		if (tr.fraction == 1)
		{
			seen->tracetimer = sv.time + 0.2f;
			break;
		}
	}

	return (seen->tracetimer > sv.time);
tracetimer is a float member of the edict_t struct, and gets initialized to -1 in the ED_ClearEdict function.
We had the power, we had the space, we had a sense of time and place
We knew the words, we knew the score, we knew what we were fighting for
Team Xlink
Posts: 368
Joined: Thu Jun 25, 2009 4:45 am
Location: Michigan

Post by Team Xlink »

Alright I have noticed some odd things.

If I set sv_cullentities to 0 the FPS is really fast. If If I leave it at 1 or set it to 2 it is a lot slower.

So, is that supposed to happen?

Also one more thing.

Is it possible to edit this so it works on brush's as well?

Like in this Five Minute paint drawing.

Image
LordHavoc
Posts: 322
Joined: Fri Nov 05, 2004 3:12 am
Location: western Oregon, USA
Contact:

Post by LordHavoc »

Team Xlink wrote:Alright I have noticed some odd things.

If I set sv_cullentities to 0 the FPS is really fast. If If I leave it at 1 or set it to 2 it is a lot slower.

So, is that supposed to happen?

Also one more thing.

Is it possible to edit this so it works on brush's as well?

Like in this Five Minute paint drawing.

Image
You can trace against bsp models (use SV_Move) so that a closed door blocks view, but it's slower (because it has to check for entities along the ray, not just the single world model).

This is a general purpose visibility solution that is a complete alternative to pvs (potentially visible set) tests that Quake does on entities, and is surprisingly not much slower than them (at least for one trace - for multiple traces it can be quite a bit slower).

But bsp models tend to be large and players really notice when they disappear, so I disabled trace tests on them in my code, but you can use trace tests on them, you simply need more traces, I simply did not care because I use it solely as an anti-cheat / network bandwidth reducer, and the bsp models are pretty cheap to render.

Yes fps is lower with trace culling, but how much lower depends how many traces you use (64 is way too many to justify).

However what you are illustrating in that drawing is culling of world geometry, not entities, which would be far too expensive with trace culling, pvs works well for that and that is why Quake uses pvs.
r00k
Posts: 1111
Joined: Sat Nov 13, 2004 10:39 pm

Post by r00k »

is there a discrepancy for latency?
mh
Posts: 2292
Joined: Sat Jan 12, 2008 1:38 am

Post by mh »

LordHavoc wrote:Yes fps is lower with trace culling, but how much lower depends how many traces you use (64 is way too many to justify).
There is a trade-off though as it reduces the number of entities you render, so what you lose on doing traces you can potentially gain back by rendering less. A lot of entities will actually "early-out" after only 1 or 2 traces, whereas the full 64 traces will only be performed for an entity that is occluded by geometry. In a scene with lots of entities occluded it's gonna hurt, otherwise it's probably 50/50.

For occlusion by brush models one potential approach might be to (1) only perform it on entities that pass the above test, and (2) use pre-transformed bounding boxes rather than traces for the occlusion test. It's not perfect (it won't deal with a case where a brush model has a great big hole in the middle, for example). Overall I'm of the same opinion as LH - it ain't that big a deal.
We had the power, we had the space, we had a sense of time and place
We knew the words, we knew the score, we knew what we were fighting for
r00k
Posts: 1111
Joined: Sat Nov 13, 2004 10:39 pm

Post by r00k »

LordHavoc wrote:
r00k wrote:the 64 can be set as a cvar i used it cause on dm3 certain areas had flashing players, increased to 64 fixed it. A timer would atleast create a base time to draw so all servers update at the same rate.
The timer isn't to make things consistent, it makes players flicker less than they would otherwise.

Each time a trace succeeds, it renews the timer, it still does the trace even if the timer is in the future, constantly renewing it.
Ya I see what you mean. SV_ClipMoveToEntity is the bottleneck and adding a trace timer throttles the call. The flicker is inevitable, the timer just skips the culling. I still get >50 hits on start map, zombies if facing the pillar to lava.
LordHavoc
Posts: 322
Joined: Fri Nov 05, 2004 3:12 am
Location: western Oregon, USA
Contact:

Post by LordHavoc »

mh wrote:For occlusion by brush models one potential approach might be to (1) only perform it on entities that pass the above test, and (2) use pre-transformed bounding boxes rather than traces for the occlusion test. It's not perfect (it won't deal with a case where a brush model has a great big hole in the middle, for example). Overall I'm of the same opinion as LH - it ain't that big a deal.
It's a routine that culls more the worse your testing is - a pretty backwards scaling behavior :)

More importantly, DarkPlaces does one trace to the nearest point on the bbox (just take the eye position and clamp it to the absmins/absmaxs of the entity), this deals with a lot of "looking around a corner" cases where the leading edge of a bbox is visible but the rest isn't, reducing flicker - of course it doesn't always help.

Then it does another trace to a random point on the bbox, from a FUTURE eye point (trace ahead the velocity of the player for 0.2 seconds), if that sees something it also renews the timer.

So two traces are done per frame, one using the most direct approach, and one using a statistical approach that also considers momentum (this usually gets rid of the "items popping up" bug as you come up a ramp or go around a corner).

It only does two.

P.S. if you want a test map to see how much bandwidth savings you can get, try dpdm2 on the DP site (or get it out of dpmod), it's a fully quake compatible map and has that rarest of properties - an outdoor environment - this map usually has most stuff visible according to pvs, but only 9% of entities in real gameplay are visible (according to trace culling)... so depending on your network protocol (QuakeWorld for example has delta compression, normal Quake does not) this can be a major bandwidth savings.
r00k
Posts: 1111
Joined: Sat Nov 13, 2004 10:39 pm

Post by r00k »

After testing more this is working better. I've added a visual cue in developer mode to show where the traceline goes and red is the fastest, yellow is more labor intense. I get more than 50% of the lines are red.

Code: Select all

qboolean SV_InvisibleToClient(edict_t *viewer, edict_t *seen)
{
//coding by LordHavoc, Spike, MH, and someone else...
    trace_t	tr;
    vec3_t	start;
    vec3_t	end;

	extern void QMB_CullTraceHightlight (vec3_t start, vec3_t end, int color);

	if (seen->v.movetype == MOVETYPE_PUSH )//dont cull doors and plats :(
    {
        return false;
    }

	if (seen->tracetimer > sv.time)
		return false;

    if (sv_cullentities.value == 1)    //1 only check player models, 2 = check all ents
    if (strcmp(pr_strings + seen->v.classname, "player"))    
        return false;

    memset (&tr, 0, sizeof(tr));                
    tr.fraction = 1;

	start[0] = viewer->v.origin[0];
    start[1] = viewer->v.origin[1];
	start[2] = viewer->v.origin[2]+viewer->v.view_ofs[2];
	
    //aim straight at the center of "seen" from our eyes
	end[0] = seen->v.origin[0];
    end[1] = seen->v.origin[1];
    end[2] = seen->v.origin[2];

	if (SV_RecursiveHullCheck(cl.worldmodel->hulls, 0, 0, 1, start, end, &tr))
	{
		seen->tracetimer = sv.time + 0.2;
		if (developer.value == 1)
			QMB_CullTraceHightlight (start, end, 4);//Draw a RED line to the ent
		return false;
	}

    if ((!strcmp(pr_strings + seen->v.classname, "player")) || (sv_cullentities.value > 1))
	{
            end[0] = seen->v.origin[0] + offsetrandom(seen->v.mins[0], seen->v.maxs[0]);
            end[1] = seen->v.origin[1] + offsetrandom(seen->v.mins[1], seen->v.maxs[1]);
            end[2] = seen->v.origin[2] + offsetrandom(seen->v.mins[2], seen->v.maxs[2]);

            tr = SV_ClipMoveToEntity (sv.edicts, start, vec3_origin, vec3_origin, end);
         if (tr.fraction == 1)// line hit the ent
			{
					seen->tracetimer = sv.time + 0.2;
					if (developer.value == 1)			
						QMB_CullTraceHightlight (start, end, 12);//Draw a yellow line to the ent.
                    return false;
			}
    }
 return true;
}
Baker
Posts: 3666
Joined: Tue Mar 14, 2006 5:15 am

Post by Baker »

Throwing random idea in here:

Dedicated server using R_CullSphere or R_Cullbox versus player frustum incrementally improve antiwallhack so players behind you cannot be detected.

As far as I know, R_SetFrustum and R_Cullbox and anything they depend on are not locked to OpenGL and don't depend on rendering so a dedicated server could do them.

The obvious potential downside could be a slight delay in seeing an enemy if you quickly turn.

Note: outstanding issue ---> how to prevent particles from getting to a client using antiwallhack.
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 ..
mh
Posts: 2292
Joined: Sat Jan 12, 2008 1:38 am

Post by mh »

One idea I had was that the client could send it's view frustum (or at least enough info to recreate it) to the server, and the server could then use that to perform culling, yeah. It would need a protocol change, and wouldn't be perfectly in sync, but you could sloppily extend it and get most of the way there.

For simplistic cases all you need is FOV and aspect ratio; Quake doesn't frustum cull against the near or far planes so you can assign arbitrary numbers (I'd recommend 4 and 4096 - same as GLQuake which seems a safe default) to these. They're not really needed for the actual culling, but are needed to simplistically recreate the frustum.

More complex cases need different info. The player could be using an engine that properly supports widescreen FOV, for example, so you can't just assume that the same params used for gluPerspective (or glFrustum) will hold valid. So what should really be used is fovx and fovy, add some sloppiness factors to account for time lag on either side, then assuming near and far of 4 and 4096 respectively, and using the player angles and origin (which are already on the server), you can recreate the view frustum correctly by extracting the planes from the view * projection matrixes (or the other way around as appropriate) which can be calculated on the server.

There might be some other edge cases I haven't covered, but that's it in a nutshell.

For particles you can group them by type (which is really just the function that generates them), compute a bbox for each type and update it as particle positions change, then cull based on that bbox. Culling at the individual particle level is overkill. Performance-wise it's faster to just draw the thing (especially Quake's little dot particles). And server-side you have no control, as soon as a rocket explosion is generated it's handed over to the client (via TE_EXPLOSION), and that's the last the server ever sees of it. You'd have to cull or whatever at generation-time, which means sniffing the server packet for svc_temp_entity messages.

If you didn't want them to go through walls on the client, another option that's probably better than culling or any other similar test is to just Mod_PointInLeaf them and set p->die to -1 as soon as they hit solid. They'll still go through doors and plats of course.
We had the power, we had the space, we had a sense of time and place
We knew the words, we knew the score, we knew what we were fighting for
Baker
Posts: 3666
Joined: Tue Mar 14, 2006 5:15 am

Post by Baker »

mh wrote:One idea I had was that the client could send it's view frustum (or at least enough info to recreate it) to the server, and the server could then use that to perform culling, yeah. It would need a protocol change, and wouldn't be perfectly in sync, but you could sloppily extend it and get most of the way there.

For simplistic cases all you need is FOV and aspect ratio
I was thinking of overly optimistic assumptions of FOV with also take into account that a player may turn quickly. Regardless of the FOV, anything above 180 can't happen (yes, I know about PanQuake, hehe ... I mean in practical non-fantastic reality it can't happen). Give or take some degrees of leeway to allow for turning, the player still shouldn't be able to see the 120 degrees directly behind him/her.
For particles you can group them by type (which is really just the function that generates them), compute a bbox for each type and update it as particle positions change, then cull based on that bbox. Culling at the individual particle level is overkill. Performance-wise it's faster to just draw the thing (especially Quake's little dot particles). And server-side you have no control, as soon as a rocket explosion is generated it's handed over to the client (via TE_EXPLOSION), and that's the last the server ever sees of it. You'd have to cull or whatever at generation-time, which means sniffing the server packet for svc_temp_entity messages.

If you didn't want them to go through walls on the client, another option that's probably better than culling or any other similar test is to just Mod_PointInLeaf them and set p->die to -1 as soon as they hit solid. They'll still go through doors and plats of course.
The old gripe about particles is that players using r_wateralpha can see particles underwater they shouldn't know about.

So even if the server doesn't support transparent water, which means the client doesn't get entities ... it still sees things like blood underwater.

Or in the case of antiwallhack, a cheater might not be able to see a player in another room, but might see particles through a wall via the cheat to be able to get a very solid estimation of where a player is. Of limited use, for sure.

Still, both of these things are the basis of the thinking.
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 ..
LordHavoc
Posts: 322
Joined: Fri Nov 05, 2004 3:12 am
Location: western Oregon, USA
Contact:

Post by LordHavoc »

I'd like to point out, as a former clan player in Quake, that flick turns require that the other entities are already networked :)

And that's in a lan environment....

Online, people can turn around 180 degrees in 200ms and still be behind their ping, if their ping is that high.

So as a rule, do not apply FOV culling on the server.
Post Reply