diff options
| author | Travis Bradshaw <travis.bradshaw@idsoftware.com> | 2012-01-31 14:32:09 -0600 |
|---|---|---|
| committer | Travis Bradshaw <travis.bradshaw@idsoftware.com> | 2012-01-31 14:32:09 -0600 |
| commit | 0023db327bc1db00068284b70e1db45857aeee35 (patch) | |
| tree | 01dd8366d20bd674741cfe8ceb069d82a2e33973 /QW/server/sv_ents.c | |
| download | quake-pum-0023db327bc1db00068284b70e1db45857aeee35.tar.gz | |
The Quake sources as originally release under the GPL license on December 21, 1999
Diffstat (limited to 'QW/server/sv_ents.c')
| -rw-r--r-- | QW/server/sv_ents.c | 517 |
1 files changed, 517 insertions, 0 deletions
diff --git a/QW/server/sv_ents.c b/QW/server/sv_ents.c new file mode 100644 index 0000000..055a9a9 --- /dev/null +++ b/QW/server/sv_ents.c @@ -0,0 +1,517 @@ +/* +Copyright (C) 1996-1997 Id Software, Inc. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include "qwsvdef.h" + +/* +============================================================================= + +The PVS must include a small area around the client to allow head bobbing +or other small motion on the client side. Otherwise, a bob might cause an +entity that should be visible to not show up, especially when the bob +crosses a waterline. + +============================================================================= +*/ + +int fatbytes; +byte fatpvs[MAX_MAP_LEAFS/8]; + +void SV_AddToFatPVS (vec3_t org, mnode_t *node) +{ + int i; + byte *pvs; + mplane_t *plane; + float d; + + while (1) + { + // if this is a leaf, accumulate the pvs bits + if (node->contents < 0) + { + if (node->contents != CONTENTS_SOLID) + { + pvs = Mod_LeafPVS ( (mleaf_t *)node, sv.worldmodel); + for (i=0 ; i<fatbytes ; i++) + fatpvs[i] |= pvs[i]; + } + return; + } + + plane = node->plane; + d = DotProduct (org, plane->normal) - plane->dist; + if (d > 8) + node = node->children[0]; + else if (d < -8) + node = node->children[1]; + else + { // go down both + SV_AddToFatPVS (org, node->children[0]); + node = node->children[1]; + } + } +} + +/* +============= +SV_FatPVS + +Calculates a PVS that is the inclusive or of all leafs within 8 pixels of the +given point. +============= +*/ +byte *SV_FatPVS (vec3_t org) +{ + fatbytes = (sv.worldmodel->numleafs+31)>>3; + Q_memset (fatpvs, 0, fatbytes); + SV_AddToFatPVS (org, sv.worldmodel->nodes); + return fatpvs; +} + +//============================================================================= + +// because there can be a lot of nails, there is a special +// network protocol for them +#define MAX_NAILS 32 +edict_t *nails[MAX_NAILS]; +int numnails; + +extern int sv_nailmodel, sv_supernailmodel, sv_playermodel; + +qboolean SV_AddNailUpdate (edict_t *ent) +{ + if (ent->v.modelindex != sv_nailmodel + && ent->v.modelindex != sv_supernailmodel) + return false; + if (numnails == MAX_NAILS) + return true; + nails[numnails] = ent; + numnails++; + return true; +} + +void SV_EmitNailUpdate (sizebuf_t *msg) +{ + byte bits[6]; // [48 bits] xyzpy 12 12 12 4 8 + int n, i; + edict_t *ent; + int x, y, z, p, yaw; + + if (!numnails) + return; + + MSG_WriteByte (msg, svc_nails); + MSG_WriteByte (msg, numnails); + + for (n=0 ; n<numnails ; n++) + { + ent = nails[n]; + x = (int)(ent->v.origin[0]+4096)>>1; + y = (int)(ent->v.origin[1]+4096)>>1; + z = (int)(ent->v.origin[2]+4096)>>1; + p = (int)(16*ent->v.angles[0]/360)&15; + yaw = (int)(256*ent->v.angles[1]/360)&255; + + bits[0] = x; + bits[1] = (x>>8) | (y<<4); + bits[2] = (y>>4); + bits[3] = z; + bits[4] = (z>>8) | (p<<4); + bits[5] = yaw; + + for (i=0 ; i<6 ; i++) + MSG_WriteByte (msg, bits[i]); + } +} + +//============================================================================= + + +/* +================== +SV_WriteDelta + +Writes part of a packetentities message. +Can delta from either a baseline or a previous packet_entity +================== +*/ +void SV_WriteDelta (entity_state_t *from, entity_state_t *to, sizebuf_t *msg, qboolean force) +{ + int bits; + int i; + float miss; + +// send an update + bits = 0; + + for (i=0 ; i<3 ; i++) + { + miss = to->origin[i] - from->origin[i]; + if ( miss < -0.1 || miss > 0.1 ) + bits |= U_ORIGIN1<<i; + } + + if ( to->angles[0] != from->angles[0] ) + bits |= U_ANGLE1; + + if ( to->angles[1] != from->angles[1] ) + bits |= U_ANGLE2; + + if ( to->angles[2] != from->angles[2] ) + bits |= U_ANGLE3; + + if ( to->colormap != from->colormap ) + bits |= U_COLORMAP; + + if ( to->skinnum != from->skinnum ) + bits |= U_SKIN; + + if ( to->frame != from->frame ) + bits |= U_FRAME; + + if ( to->effects != from->effects ) + bits |= U_EFFECTS; + + if ( to->modelindex != from->modelindex ) + bits |= U_MODEL; + + if (bits & 511) + bits |= U_MOREBITS; + + if (to->flags & U_SOLID) + bits |= U_SOLID; + + // + // write the message + // + if (!to->number) + SV_Error ("Unset entity number"); + if (to->number >= 512) + SV_Error ("Entity number >= 512"); + + if (!bits && !force) + return; // nothing to send! + i = to->number | (bits&~511); + if (i & U_REMOVE) + Sys_Error ("U_REMOVE"); + MSG_WriteShort (msg, i); + + if (bits & U_MOREBITS) + MSG_WriteByte (msg, bits&255); + if (bits & U_MODEL) + MSG_WriteByte (msg, to->modelindex); + if (bits & U_FRAME) + MSG_WriteByte (msg, to->frame); + if (bits & U_COLORMAP) + MSG_WriteByte (msg, to->colormap); + if (bits & U_SKIN) + MSG_WriteByte (msg, to->skinnum); + if (bits & U_EFFECTS) + MSG_WriteByte (msg, to->effects); + if (bits & U_ORIGIN1) + MSG_WriteCoord (msg, to->origin[0]); + if (bits & U_ANGLE1) + MSG_WriteAngle(msg, to->angles[0]); + if (bits & U_ORIGIN2) + MSG_WriteCoord (msg, to->origin[1]); + if (bits & U_ANGLE2) + MSG_WriteAngle(msg, to->angles[1]); + if (bits & U_ORIGIN3) + MSG_WriteCoord (msg, to->origin[2]); + if (bits & U_ANGLE3) + MSG_WriteAngle(msg, to->angles[2]); +} + +/* +============= +SV_EmitPacketEntities + +Writes a delta update of a packet_entities_t to the message. + +============= +*/ +void SV_EmitPacketEntities (client_t *client, packet_entities_t *to, sizebuf_t *msg) +{ + edict_t *ent; + client_frame_t *fromframe; + packet_entities_t *from; + int oldindex, newindex; + int oldnum, newnum; + int oldmax; + + // this is the frame that we are going to delta update from + if (client->delta_sequence != -1) + { + fromframe = &client->frames[client->delta_sequence & UPDATE_MASK]; + from = &fromframe->entities; + oldmax = from->num_entities; + + MSG_WriteByte (msg, svc_deltapacketentities); + MSG_WriteByte (msg, client->delta_sequence); + } + else + { + oldmax = 0; // no delta update + from = NULL; + + MSG_WriteByte (msg, svc_packetentities); + } + + newindex = 0; + oldindex = 0; +//Con_Printf ("---%i to %i ----\n", client->delta_sequence & UPDATE_MASK +// , client->netchan.outgoing_sequence & UPDATE_MASK); + while (newindex < to->num_entities || oldindex < oldmax) + { + newnum = newindex >= to->num_entities ? 9999 : to->entities[newindex].number; + oldnum = oldindex >= oldmax ? 9999 : from->entities[oldindex].number; + + if (newnum == oldnum) + { // delta update from old position +//Con_Printf ("delta %i\n", newnum); + SV_WriteDelta (&from->entities[oldindex], &to->entities[newindex], msg, false); + oldindex++; + newindex++; + continue; + } + + if (newnum < oldnum) + { // this is a new entity, send it from the baseline + ent = EDICT_NUM(newnum); +//Con_Printf ("baseline %i\n", newnum); + SV_WriteDelta (&ent->baseline, &to->entities[newindex], msg, true); + newindex++; + continue; + } + + if (newnum > oldnum) + { // the old entity isn't present in the new message +//Con_Printf ("remove %i\n", oldnum); + MSG_WriteShort (msg, oldnum | U_REMOVE); + oldindex++; + continue; + } + } + + MSG_WriteShort (msg, 0); // end of packetentities +} + +/* +============= +SV_WritePlayersToClient + +============= +*/ +void SV_WritePlayersToClient (client_t *client, edict_t *clent, byte *pvs, sizebuf_t *msg) +{ + int i, j; + client_t *cl; + edict_t *ent; + int msec; + usercmd_t cmd; + int pflags; + + for (j=0,cl=svs.clients ; j<MAX_CLIENTS ; j++,cl++) + { + if (cl->state != cs_spawned) + continue; + + ent = cl->edict; + + // ZOID visibility tracking + if (ent != clent && + !(client->spec_track && client->spec_track - 1 == j)) + { + if (cl->spectator) + continue; + + // ignore if not touching a PV leaf + for (i=0 ; i < ent->num_leafs ; i++) + if (pvs[ent->leafnums[i] >> 3] & (1 << (ent->leafnums[i]&7) )) + break; + if (i == ent->num_leafs) + continue; // not visible + } + + pflags = PF_MSEC | PF_COMMAND; + + if (ent->v.modelindex != sv_playermodel) + pflags |= PF_MODEL; + for (i=0 ; i<3 ; i++) + if (ent->v.velocity[i]) + pflags |= PF_VELOCITY1<<i; + if (ent->v.effects) + pflags |= PF_EFFECTS; + if (ent->v.skin) + pflags |= PF_SKINNUM; + if (ent->v.health <= 0) + pflags |= PF_DEAD; + if (ent->v.mins[2] != -24) + pflags |= PF_GIB; + + if (cl->spectator) + { // only sent origin and velocity to spectators + pflags &= PF_VELOCITY1 | PF_VELOCITY2 | PF_VELOCITY3; + } + else if (ent == clent) + { // don't send a lot of data on personal entity + pflags &= ~(PF_MSEC|PF_COMMAND); + if (ent->v.weaponframe) + pflags |= PF_WEAPONFRAME; + } + + if (client->spec_track && client->spec_track - 1 == j && + ent->v.weaponframe) + pflags |= PF_WEAPONFRAME; + + MSG_WriteByte (msg, svc_playerinfo); + MSG_WriteByte (msg, j); + MSG_WriteShort (msg, pflags); + + for (i=0 ; i<3 ; i++) + MSG_WriteCoord (msg, ent->v.origin[i]); + + MSG_WriteByte (msg, ent->v.frame); + + if (pflags & PF_MSEC) + { + msec = 1000*(sv.time - cl->localtime); + if (msec > 255) + msec = 255; + MSG_WriteByte (msg, msec); + } + + if (pflags & PF_COMMAND) + { + cmd = cl->lastcmd; + + if (ent->v.health <= 0) + { // don't show the corpse looking around... + cmd.angles[0] = 0; + cmd.angles[1] = ent->v.angles[1]; + cmd.angles[0] = 0; + } + + cmd.buttons = 0; // never send buttons + cmd.impulse = 0; // never send impulses + + MSG_WriteDeltaUsercmd (msg, &nullcmd, &cmd); + } + + for (i=0 ; i<3 ; i++) + if (pflags & (PF_VELOCITY1<<i) ) + MSG_WriteShort (msg, ent->v.velocity[i]); + + if (pflags & PF_MODEL) + MSG_WriteByte (msg, ent->v.modelindex); + + if (pflags & PF_SKINNUM) + MSG_WriteByte (msg, ent->v.skin); + + if (pflags & PF_EFFECTS) + MSG_WriteByte (msg, ent->v.effects); + + if (pflags & PF_WEAPONFRAME) + MSG_WriteByte (msg, ent->v.weaponframe); + } +} + + +/* +============= +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) +{ + int e, i; + byte *pvs; + vec3_t org; + edict_t *ent; + packet_entities_t *pack; + edict_t *clent; + client_frame_t *frame; + entity_state_t *state; + + // this is the frame we are creating + frame = &client->frames[client->netchan.incoming_sequence & UPDATE_MASK]; + + // find the client's PVS + clent = client->edict; + VectorAdd (clent->v.origin, clent->v.view_ofs, org); + pvs = SV_FatPVS (org); + + // 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; + + for (e=MAX_CLIENTS+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->num_leafs ; i++) + if (pvs[ent->leafnums[i] >> 3] & (1 << (ent->leafnums[i]&7) )) + break; + + if (i == ent->num_leafs) + continue; // not visible + + 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 = ent->v.effects; + } + + // 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); +} |
