SV_Invisible_To_Client (Anti-Wallhack)
-
- Posts: 368
- Joined: Thu Jun 25, 2009 4:45 am
- Location: Michigan
The timer isn't to make things consistent, it makes players flicker less than they would otherwise.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.
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:LordHavoc wrote:The timer isn't to make things consistent, it makes players flicker less than they would otherwise.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.
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.
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).
Yup, that seems to make sense to me.
_________________________________________
Edit: yeah, it works.
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);
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
We knew the words, we knew the score, we knew what we were fighting for
-
- Posts: 368
- Joined: Thu Jun 25, 2009 4:45 am
- Location: Michigan
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.
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.
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).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.
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.
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.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).
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
We knew the words, we knew the score, we knew what we were fighting for
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 wrote:The timer isn't to make things consistent, it makes players flicker less than they would otherwise.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.
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.
It's a routine that culls more the worse your testing is - a pretty backwards scaling behaviormh 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.
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.
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;
}
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.
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? Inquisitive minds want to know ! And if they don't -- well like that ever has stopped me before ..
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.
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
We knew the words, we knew the score, we knew what we were fighting for
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.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
The old gripe about particles is that players using r_wateralpha can see particles underwater they shouldn't know about.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.
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? Inquisitive minds want to know ! And if they don't -- well like that ever has stopped me before ..
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.
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.