123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518 |
- /*
- 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);
- }
|