#define offsetrandom(MIN,MAX) ((rand() & 32767) * (((MAX)-(MIN)) * (1.0f / 32767.0f)) + (MIN))
extern cvar_t sv_cullentities;
extern trace_t SV_ClipMoveToEntity (edict_t *ent, vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end);
qbool SV_InvisibleToClient(edict_t *viewer, edict_t *seen)
{
int i;
trace_t tr;
vec3_t start;
vec3_t end;
qbool player;
if (seen->v.movetype == MOVETYPE_PUSH ) //dont cull doors and plats
return false;
i = NUM_FOR_EDICT(seen);
player = (i >= 1 && i <= MAX_CLIENTS);
//1 = only check player models, 2 = check all ents
if (sv_cullentities.value == 1 && !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] = 0.5 * (seen->v.mins[0] + seen->v.maxs[0]);
end[1] = 0.5 * (seen->v.mins[1] + seen->v.maxs[1]);
end[2] = 0.5 * (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
return false;
//last attempt to eliminate any flaws...
if (player || sv_cullentities.value != 1)
{
for (i = 0; i < 64; 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)// line hit the ent
{
// Com_DPrintf (va("found ent in %i hits\n", i));
return false;
}
}
}
return true;
}
/*
=============
SV_WriteEntitiesToClient
Encodes the current state of the world as
a svc_packetentities messages and possibly
a svc_nails message and
svc_playerinfo messages
=============
*/
void SV_WriteEntitiesToClient (client_t *client, sizebuf_t *msg, qbool recorder)
{
int e, i, max_packet_entities;
packet_entities_t *pack;
client_frame_t *frame;
entity_state_t *state;
edict_t *clent;
client_t *cl;
edict_t *ent;
vec3_t org;
byte *pvs;
int hideent;
// this is the frame we are creating
frame = &client->frames[client->netchan.incoming_sequence & UPDATE_MASK];
// find the client's PVS
clent = client->edict;
pvs = NULL;
if (!recorder)
{
VectorAdd (clent->v.origin, clent->v.view_ofs, org);
pvs = CM_FatPVS (org);
if (client->fteprotocolextensions & FTE_PEXT_256PACKETENTITIES)
max_packet_entities = 256;
else
max_packet_entities = MAX_PACKET_ENTITIES;
}
else
{
max_packet_entities = MAX_MVD_PACKET_ENTITIES;
for (i=0, cl=svs.clients ; i<MAX_CLIENTS ; i++,cl++)
{
if (cl->state != cs_spawned)
continue;
if (cl->spectator)
continue;
VectorAdd (cl->edict->v.origin, cl->edict->v.view_ofs, org);
// disconnect --> "is it correct?"
//if (pvs == NULL)
pvs = CM_FatPVS (org);
//else
// SV_AddToFatPVS (org, sv.worldmodel->nodes, false);
// <-- disconnect
}
}
if (clent && client->disable_updates_stop > realtime)
{ // Vladis
int where = TruePointContents(clent->v.origin); // server flash should not work underwater
disable_updates = !ISUNDERWATER(where);
}
else
{
disable_updates = false;
}
// send over the players in the PVS
SV_WritePlayersToClient (client, clent, pvs, msg);
// put other visible entities into either a packet_entities or a nails message
pack = &frame->entities;
pack->num_entities = 0;
numnails = 0;
if (fofs_hideentity)
hideent = ((eval_t *)((byte *)&(clent)->v + fofs_hideentity))->_int / pr_edict_size;
else
hideent = 0;
if (!disable_updates)
{// Vladis, server flash
// QW protocol can only handle 512 entities. Any entity with number >= 512 will be invisible
// From ZQuake.
// max_edicts = min(sv.num_edicts, MAX_EDICTS);
for (e = pr_nqprogs ? 1 : MAX_CLIENTS+1, ent=EDICT_NUM(e);
e < sv.num_edicts/*max_edicts*/;
e++, ent = NEXT_EDICT(ent))
{
if (pr_nqprogs) {
// don't send the player's model to himself
if (e < MAX_CLIENTS + 1 && svs.clients[e-1].state != cs_free)
continue;
}
// ignore ents without visible models
if (!ent->v.modelindex || !*
#ifdef USE_PR2
PR2_GetString(ent->v.model)
#else
PR_GetString(ent->v.model)
#endif
)
continue;
if (e == hideent)
continue;
if (!(int)sv_demoNoVis.value || !recorder)
{
// ignore if not touching a PV leaf
for (i=0 ; i < ent->e->num_leafs ; i++)
if (pvs[ent->e->leafnums[i] >> 3] & (1 << (ent->e->leafnums[i]&7) ))
break;
if (i == ent->e->num_leafs)
continue; // not visible
if (sv_cullentities.value && SV_InvisibleToClient(clent, ent))
continue;
}
if (SV_AddNailUpdate (ent))
continue; // added to the special update list
// add to the packetentities
if (pack->num_entities == max_packet_entities)
continue; // all full
state = &pack->entities[pack->num_entities];
pack->num_entities++;
state->number = e;
state->flags = 0;
VectorCopy (ent->v.origin, state->origin);
VectorCopy (ent->v.angles, state->angles);
state->modelindex = ent->v.modelindex;
state->frame = ent->v.frame;
state->colormap = ent->v.colormap;
state->skinnum = ent->v.skin;
state->effects = TranslateEffects(ent);
}
} // server flash
// encode the packet entities as a delta from the
// last packetentities acknowledged by the client
SV_EmitPacketEntities (client, pack, msg);
// now add the specialized nail update
SV_EmitNailUpdate (msg, recorder);
// Translate NQ progs' EF_MUZZLEFLASH to svc_muzzleflash
if (pr_nqprogs)
for (e=1, ent=EDICT_NUM(e) ; e < sv.num_edicts ; e++, ent = NEXT_EDICT(ent))
{
// ignore ents without visible models
if (!ent->v.modelindex || !*PR_GetString(ent->v.model))
continue;
// ignore if not touching a PV leaf
for (i=0 ; i < ent->e->num_leafs ; i++)
if (pvs[ent->e->leafnums[i] >> 3] & (1 << (ent->e->leafnums[i]&7) ))
break;
if ((int)ent->v.effects & EF_MUZZLEFLASH) {
ent->v.effects = (int)ent->v.effects & ~EF_MUZZLEFLASH;
MSG_WriteByte (msg, svc_muzzleflash);
MSG_WriteShort (msg, e);
}
}
}
Actually thats ezQuake but it can be ported fairly easy.
All it does is scan from the players pov all visible entities. If the entity is culled by a wall then the information about that entity is never sent to the player.
So EVEN if u had transparent walls, you wouldnt see anything behind it.