2007-06-21 22:00:00 +02:00
|
|
|
/*
|
|
|
|
Copyright (C) 1997-2001 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 "engine.h"
|
|
|
|
#include "server.h"
|
|
|
|
|
|
|
|
/*
|
|
|
|
=============================================================================
|
|
|
|
|
2007-09-18 22:00:00 +02:00
|
|
|
Copy PRVM values into entity state
|
|
|
|
|
|
|
|
=============================================================================
|
|
|
|
*/
|
|
|
|
void SV_UpdateEntityState( edict_t *ent)
|
|
|
|
{
|
|
|
|
// copy progs values to state
|
|
|
|
ent->priv.sv->s.number = ent->priv.sv->serialnumber;
|
|
|
|
ent->priv.sv->s.solid = ent->priv.sv->solid;
|
|
|
|
ent->priv.sv->s.event = ent->priv.sv->event;
|
|
|
|
|
|
|
|
VectorCopy (ent->progs.sv->origin, ent->priv.sv->s.origin);
|
|
|
|
VectorCopy (ent->progs.sv->angles, ent->priv.sv->s.angles);
|
|
|
|
VectorCopy (ent->progs.sv->old_origin, ent->priv.sv->s.old_origin);
|
|
|
|
|
|
|
|
ent->priv.sv->s.modelindex = (int)ent->progs.sv->modelindex;
|
2007-09-28 22:00:00 +02:00
|
|
|
ent->priv.sv->s.weaponmodel = 0; // attached weaponmodel
|
2007-09-18 22:00:00 +02:00
|
|
|
|
|
|
|
ent->priv.sv->s.skin = (short)ent->progs.sv->skin; // studio model skin
|
|
|
|
ent->priv.sv->s.body = (byte)ent->progs.sv->body; // studio model submodel
|
|
|
|
ent->priv.sv->s.frame = (short)ent->progs.sv->frame; // any model current frame
|
|
|
|
ent->priv.sv->s.sequence = (byte)ent->progs.sv->sequence; // studio model sequence
|
|
|
|
ent->priv.sv->s.effects = (uint)ent->progs.sv->effects; // shared client and render flags
|
|
|
|
ent->priv.sv->s.renderfx = (int)ent->progs.sv->renderfx; // renderer flags
|
|
|
|
ent->priv.sv->s.alpha = ent->progs.sv->alpha; // alpha value
|
2007-10-03 22:00:00 +02:00
|
|
|
ent->priv.sv->s.soundindex = SV_SoundIndex(PRVM_GetString(ent->progs.sv->noise3));
|
2007-09-18 22:00:00 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
=============================================================================
|
|
|
|
|
2007-06-21 22:00:00 +02:00
|
|
|
Encode a client frame onto the network channel
|
|
|
|
|
|
|
|
=============================================================================
|
|
|
|
*/
|
|
|
|
/*
|
|
|
|
=============
|
|
|
|
SV_EmitPacketEntities
|
|
|
|
|
|
|
|
Writes a delta update of an entity_state_t list to the message->
|
|
|
|
=============
|
|
|
|
*/
|
|
|
|
void SV_EmitPacketEntities (client_frame_t *from, client_frame_t *to, sizebuf_t *msg)
|
|
|
|
{
|
|
|
|
entity_state_t *oldent, *newent;
|
|
|
|
int oldindex, newindex;
|
|
|
|
int oldnum, newnum;
|
|
|
|
int from_num_entities;
|
|
|
|
int bits;
|
|
|
|
|
2007-08-19 22:00:00 +02:00
|
|
|
MSG_WriteByte (msg, svc_packetentities);
|
2007-06-21 22:00:00 +02:00
|
|
|
|
2007-08-19 22:00:00 +02:00
|
|
|
if (!from) from_num_entities = 0;
|
|
|
|
else from_num_entities = from->num_entities;
|
2007-06-21 22:00:00 +02:00
|
|
|
|
|
|
|
newindex = 0;
|
|
|
|
oldindex = 0;
|
|
|
|
while (newindex < to->num_entities || oldindex < from_num_entities)
|
|
|
|
{
|
|
|
|
if (newindex >= to->num_entities)
|
|
|
|
newnum = 9999;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
newent = &svs.client_entities[(to->first_entity+newindex)%svs.num_client_entities];
|
|
|
|
newnum = newent->number;
|
|
|
|
}
|
|
|
|
|
2008-01-17 22:00:00 +01:00
|
|
|
if (oldindex >= from_num_entities) oldnum = 9999;
|
2007-06-21 22:00:00 +02:00
|
|
|
else
|
|
|
|
{
|
|
|
|
oldent = &svs.client_entities[(from->first_entity+oldindex)%svs.num_client_entities];
|
|
|
|
oldnum = oldent->number;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (newnum == oldnum)
|
2007-09-06 22:00:00 +02:00
|
|
|
{ // delta update from old position
|
2007-06-21 22:00:00 +02:00
|
|
|
// because the force parm is false, this will not result
|
|
|
|
// in any bytes being emited if the entity has not changed at all
|
|
|
|
// note that players are always 'newentities', this updates their oldorigin always
|
|
|
|
// and prevents warping
|
2007-09-06 22:00:00 +02:00
|
|
|
MSG_WriteDeltaEntity (oldent, newent, msg, false, newent->number <= maxclients->value);
|
2007-06-21 22:00:00 +02:00
|
|
|
oldindex++;
|
|
|
|
newindex++;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (newnum < oldnum)
|
2007-09-06 22:00:00 +02:00
|
|
|
{ // this is a new entity, send it from the baseline
|
2007-06-21 22:00:00 +02:00
|
|
|
MSG_WriteDeltaEntity (&sv.baselines[newnum], newent, msg, true, true);
|
|
|
|
newindex++;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (newnum > oldnum)
|
2007-09-17 22:00:00 +02:00
|
|
|
{
|
|
|
|
// the old entity isn't present in the new message
|
2007-06-21 22:00:00 +02:00
|
|
|
bits = U_REMOVE;
|
2007-09-17 22:00:00 +02:00
|
|
|
if (oldnum >= 256) bits |= U_NUMBER16 | U_MOREBITS1;
|
2007-06-21 22:00:00 +02:00
|
|
|
|
|
|
|
MSG_WriteByte (msg, bits&255 );
|
2007-09-17 22:00:00 +02:00
|
|
|
if (bits & 0x0000ff00) MSG_WriteByte (msg, (bits>>8)&255 );
|
2007-06-21 22:00:00 +02:00
|
|
|
|
|
|
|
if (bits & U_NUMBER16)
|
2007-08-01 22:00:00 +02:00
|
|
|
{
|
2007-06-21 22:00:00 +02:00
|
|
|
MSG_WriteShort (msg, oldnum);
|
2007-08-01 22:00:00 +02:00
|
|
|
}
|
2007-06-21 22:00:00 +02:00
|
|
|
else
|
2007-08-01 22:00:00 +02:00
|
|
|
{
|
2007-06-21 22:00:00 +02:00
|
|
|
MSG_WriteByte (msg, oldnum);
|
2007-08-01 22:00:00 +02:00
|
|
|
}
|
2007-06-21 22:00:00 +02:00
|
|
|
oldindex++;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
MSG_WriteShort (msg, 0); // end of packetentities
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
=============
|
|
|
|
SV_WritePlayerstateToClient
|
|
|
|
|
|
|
|
=============
|
|
|
|
*/
|
|
|
|
void SV_WritePlayerstateToClient (client_frame_t *from, client_frame_t *to, sizebuf_t *msg)
|
|
|
|
{
|
|
|
|
int i;
|
2007-08-01 22:00:00 +02:00
|
|
|
int pflags = 0;
|
2007-06-25 22:00:00 +02:00
|
|
|
player_state_t *ps, *ops;
|
|
|
|
player_state_t dummy;
|
2007-06-21 22:00:00 +02:00
|
|
|
int statbits;
|
|
|
|
|
|
|
|
ps = &to->ps;
|
|
|
|
if (!from)
|
|
|
|
{
|
|
|
|
memset (&dummy, 0, sizeof(dummy));
|
|
|
|
ops = &dummy;
|
|
|
|
}
|
2007-06-25 22:00:00 +02:00
|
|
|
else ops = &from->ps;
|
2007-06-21 22:00:00 +02:00
|
|
|
|
|
|
|
// determine what needs to be sent
|
2008-01-19 22:00:00 +01:00
|
|
|
if (ps->pm_type != ops->pm_type) pflags |= PS_M_TYPE;
|
|
|
|
if(!VectorCompare(ps->origin, ops->origin)) pflags |= PS_M_ORIGIN;
|
|
|
|
if(!VectorCompare(ps->velocity, ops->velocity)) pflags |= PS_M_VELOCITY;
|
|
|
|
if (ps->pm_time != ops->pm_time) pflags |= PS_M_TIME;
|
|
|
|
if (ps->pm_flags != ops->pm_flags) pflags |= PS_M_FLAGS;
|
|
|
|
if (ps->gravity != ops->gravity) pflags |= PS_M_GRAVITY;
|
|
|
|
if(!VectorCompare(ps->delta_angles, ops->delta_angles)) pflags |= PS_M_DELTA_ANGLES;
|
2007-10-29 22:00:00 +01:00
|
|
|
if(!VectorCompare(ps->viewoffset, ops->viewoffset)) pflags |= PS_VIEWOFFSET;
|
2007-10-19 22:00:00 +02:00
|
|
|
if(!VectorCompare(ps->viewangles, ops->viewangles)) pflags |= PS_VIEWANGLES;
|
2007-10-29 22:00:00 +01:00
|
|
|
if(!VectorCompare(ps->kick_angles, ops->kick_angles)) pflags |= PS_KICKANGLES;
|
|
|
|
|
|
|
|
if (ps->blend[0] != ops->blend[0] || ps->blend[1] != ops->blend[1] || ps->blend[2] != ops->blend[2] || ps->blend[3] != ops->blend[3] )
|
2007-09-06 22:00:00 +02:00
|
|
|
pflags |= PS_BLEND;
|
|
|
|
|
2007-10-19 22:00:00 +02:00
|
|
|
if (ps->fov != ops->fov) pflags |= PS_FOV;
|
2008-01-19 22:00:00 +01:00
|
|
|
if (ps->effects != ops->effects) pflags |= PS_RDFLAGS;
|
|
|
|
if (ps->vmodel.frame != ops->vmodel.frame) pflags |= PS_WEAPONFRAME;
|
|
|
|
if (ps->vmodel.sequence != ops->vmodel.sequence) pflags |= PS_WEAPONSEQUENCE;
|
|
|
|
if (ps->vmodel.body != ops->vmodel.body) pflags |= PS_WEAPONBODY;
|
|
|
|
if (ps->vmodel.skin != ops->vmodel.skin) pflags |= PS_WEAPONSKIN;
|
2007-06-25 22:00:00 +02:00
|
|
|
|
2007-06-21 22:00:00 +02:00
|
|
|
pflags |= PS_WEAPONINDEX;
|
|
|
|
|
|
|
|
// write it
|
|
|
|
MSG_WriteByte (msg, svc_playerinfo);
|
2007-06-25 22:00:00 +02:00
|
|
|
MSG_WriteLong (msg, pflags);
|
2007-06-21 22:00:00 +02:00
|
|
|
|
|
|
|
// write the pmove_state_t
|
2008-01-19 22:00:00 +01:00
|
|
|
if (pflags & PS_M_TYPE) MSG_WriteByte (msg, ps->pm_type);
|
2007-10-29 22:00:00 +01:00
|
|
|
|
2008-01-19 22:00:00 +01:00
|
|
|
if (pflags & PS_M_ORIGIN) MSG_WritePos32(msg, ps->origin);
|
|
|
|
if (pflags & PS_M_VELOCITY) MSG_WritePos32(msg, ps->velocity);
|
|
|
|
if (pflags & PS_M_TIME) MSG_WriteByte (msg, ps->pm_time);
|
|
|
|
if (pflags & PS_M_FLAGS) MSG_WriteByte (msg, ps->pm_flags);
|
|
|
|
if (pflags & PS_M_GRAVITY) MSG_WriteShort (msg, ps->gravity);
|
|
|
|
if (pflags & PS_M_DELTA_ANGLES) MSG_WritePos32(msg, ps->delta_angles);
|
2007-06-21 22:00:00 +02:00
|
|
|
|
2007-09-06 22:00:00 +02:00
|
|
|
//
|
2007-06-21 22:00:00 +02:00
|
|
|
// write the rest of the player_state_t
|
2007-09-06 22:00:00 +02:00
|
|
|
//
|
2007-06-21 22:00:00 +02:00
|
|
|
if (pflags & PS_VIEWOFFSET)
|
|
|
|
{
|
2007-06-25 22:00:00 +02:00
|
|
|
MSG_WriteChar (msg, ps->viewoffset[0] * 4);
|
|
|
|
MSG_WriteChar (msg, ps->viewoffset[1] * 4);
|
|
|
|
MSG_WriteChar (msg, ps->viewoffset[2] * 4);
|
2007-06-21 22:00:00 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (pflags & PS_VIEWANGLES)
|
|
|
|
{
|
2008-01-12 22:00:00 +01:00
|
|
|
MSG_WriteAngle32 (msg, ps->viewangles[0]);
|
|
|
|
MSG_WriteAngle32 (msg, ps->viewangles[1]);
|
|
|
|
MSG_WriteAngle32 (msg, ps->viewangles[2]);
|
2007-06-21 22:00:00 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (pflags & PS_KICKANGLES)
|
|
|
|
{
|
2007-06-25 22:00:00 +02:00
|
|
|
MSG_WriteChar (msg, ps->kick_angles[0] * 4);
|
|
|
|
MSG_WriteChar (msg, ps->kick_angles[1] * 4);
|
|
|
|
MSG_WriteChar (msg, ps->kick_angles[2] * 4);
|
2007-06-21 22:00:00 +02:00
|
|
|
}
|
|
|
|
|
2007-09-06 22:00:00 +02:00
|
|
|
if (pflags & PS_WEAPONINDEX)
|
|
|
|
{
|
2008-01-19 22:00:00 +01:00
|
|
|
MSG_WriteByte (msg, ps->vmodel.index);
|
2007-09-06 22:00:00 +02:00
|
|
|
}
|
|
|
|
|
2007-06-21 22:00:00 +02:00
|
|
|
if (pflags & PS_WEAPONFRAME)
|
|
|
|
{
|
2008-01-19 22:00:00 +01:00
|
|
|
MSG_WriteByte (msg, ps->vmodel.frame);
|
|
|
|
MSG_WriteChar (msg, ps->vmodel.offset[0]*4);
|
|
|
|
MSG_WriteChar (msg, ps->vmodel.offset[1]*4);
|
|
|
|
MSG_WriteChar (msg, ps->vmodel.offset[2]*4);
|
|
|
|
MSG_WriteChar (msg, ps->vmodel.angles[0]*4);
|
|
|
|
MSG_WriteChar (msg, ps->vmodel.angles[1]*4);
|
|
|
|
MSG_WriteChar (msg, ps->vmodel.angles[2]*4);
|
2007-06-21 22:00:00 +02:00
|
|
|
}
|
|
|
|
|
2007-09-06 22:00:00 +02:00
|
|
|
if (pflags & PS_WEAPONSEQUENCE)
|
|
|
|
{
|
2008-01-19 22:00:00 +01:00
|
|
|
MSG_WriteByte (msg, ps->vmodel.sequence);
|
2007-09-06 22:00:00 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (pflags & PS_WEAPONBODY)
|
|
|
|
{
|
2008-01-19 22:00:00 +01:00
|
|
|
MSG_WriteByte (msg, ps->vmodel.body);
|
2007-09-06 22:00:00 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (pflags & PS_WEAPONSKIN)
|
|
|
|
{
|
2008-01-19 22:00:00 +01:00
|
|
|
MSG_WriteByte (msg, ps->vmodel.skin);
|
2007-09-06 22:00:00 +02:00
|
|
|
}
|
2007-06-25 22:00:00 +02:00
|
|
|
|
2007-06-21 22:00:00 +02:00
|
|
|
if (pflags & PS_BLEND)
|
|
|
|
{
|
2007-09-06 22:00:00 +02:00
|
|
|
MSG_WriteByte (msg, ps->blend[0]*255);
|
|
|
|
MSG_WriteByte (msg, ps->blend[1]*255);
|
|
|
|
MSG_WriteByte (msg, ps->blend[2]*255);
|
|
|
|
MSG_WriteByte (msg, ps->blend[3]*255);
|
2007-06-21 22:00:00 +02:00
|
|
|
}
|
2007-09-06 22:00:00 +02:00
|
|
|
if (pflags & PS_FOV)
|
|
|
|
MSG_WriteByte (msg, ps->fov);
|
|
|
|
if (pflags & PS_RDFLAGS)
|
2008-01-19 22:00:00 +01:00
|
|
|
MSG_WriteByte (msg, ps->effects);
|
2007-06-21 22:00:00 +02:00
|
|
|
|
|
|
|
// send stats
|
|
|
|
statbits = 0;
|
2007-09-06 22:00:00 +02:00
|
|
|
for (i=0 ; i<MAX_STATS ; i++)
|
2007-06-21 22:00:00 +02:00
|
|
|
if (ps->stats[i] != ops->stats[i])
|
|
|
|
statbits |= 1<<i;
|
|
|
|
MSG_WriteLong (msg, statbits);
|
2007-09-06 22:00:00 +02:00
|
|
|
for (i=0 ; i<MAX_STATS ; i++)
|
|
|
|
if (statbits & (1<<i) )
|
2007-06-21 22:00:00 +02:00
|
|
|
MSG_WriteShort (msg, ps->stats[i]);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
==================
|
|
|
|
SV_WriteFrameToClient
|
|
|
|
==================
|
|
|
|
*/
|
2007-11-04 22:00:00 +01:00
|
|
|
void SV_WriteFrameToClient (client_state_t *client, sizebuf_t *msg)
|
2007-06-21 22:00:00 +02:00
|
|
|
{
|
|
|
|
client_frame_t *frame, *oldframe;
|
|
|
|
int lastframe;
|
|
|
|
|
2007-07-28 22:00:00 +02:00
|
|
|
//Msg ("%i -> %i\n", client->lastframe, sv.framenum);
|
2007-06-21 22:00:00 +02:00
|
|
|
// this is the frame we are creating
|
|
|
|
frame = &client->frames[sv.framenum & UPDATE_MASK];
|
|
|
|
|
|
|
|
if (client->lastframe <= 0)
|
2007-09-06 22:00:00 +02:00
|
|
|
{ // client is asking for a retransmit
|
2007-06-21 22:00:00 +02:00
|
|
|
oldframe = NULL;
|
|
|
|
lastframe = -1;
|
|
|
|
}
|
|
|
|
else if (sv.framenum - client->lastframe >= (UPDATE_BACKUP - 3) )
|
2007-09-06 22:00:00 +02:00
|
|
|
{ // client hasn't gotten a good message through in a long time
|
2007-07-28 22:00:00 +02:00
|
|
|
// Msg ("%s: Delta request from out-of-date packet.\n", client->name);
|
2007-06-21 22:00:00 +02:00
|
|
|
oldframe = NULL;
|
|
|
|
lastframe = -1;
|
|
|
|
}
|
|
|
|
else
|
2007-09-06 22:00:00 +02:00
|
|
|
{ // we have a valid message to delta from
|
2007-06-21 22:00:00 +02:00
|
|
|
oldframe = &client->frames[client->lastframe & UPDATE_MASK];
|
|
|
|
lastframe = client->lastframe;
|
|
|
|
}
|
|
|
|
|
|
|
|
MSG_WriteByte (msg, svc_frame);
|
|
|
|
MSG_WriteLong (msg, sv.framenum);
|
|
|
|
MSG_WriteLong (msg, lastframe); // what we are delta'ing from
|
|
|
|
MSG_WriteByte (msg, client->surpressCount); // rate dropped packets
|
|
|
|
client->surpressCount = 0;
|
|
|
|
|
|
|
|
// send over the areabits
|
|
|
|
MSG_WriteByte (msg, frame->areabytes);
|
|
|
|
SZ_Write (msg, frame->areabits, frame->areabytes);
|
|
|
|
|
|
|
|
// delta encode the playerstate
|
|
|
|
SV_WritePlayerstateToClient (oldframe, frame, msg);
|
|
|
|
|
|
|
|
// delta encode the entities
|
|
|
|
SV_EmitPacketEntities (oldframe, frame, msg);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
=============================================================================
|
|
|
|
|
|
|
|
Build a client frame structure
|
|
|
|
|
|
|
|
=============================================================================
|
|
|
|
*/
|
|
|
|
/*
|
|
|
|
=============
|
|
|
|
SV_BuildClientFrame
|
|
|
|
|
|
|
|
Decides which entities are going to be visible to the client, and
|
|
|
|
copies off the playerstat and areabits.
|
|
|
|
=============
|
|
|
|
*/
|
2007-11-04 22:00:00 +01:00
|
|
|
void SV_BuildClientFrame (client_state_t *client)
|
2007-06-21 22:00:00 +02:00
|
|
|
{
|
|
|
|
int e, i;
|
2007-09-17 22:00:00 +02:00
|
|
|
vec3_t org;
|
|
|
|
edict_t *ent;
|
|
|
|
edict_t *clent;
|
2007-06-21 22:00:00 +02:00
|
|
|
client_frame_t *frame;
|
|
|
|
entity_state_t *state;
|
|
|
|
int l;
|
|
|
|
int clientarea, clientcluster;
|
|
|
|
int leafnum;
|
|
|
|
int c_fullsend;
|
2008-01-17 22:00:00 +01:00
|
|
|
byte *clientpvs;
|
2007-09-17 22:00:00 +02:00
|
|
|
byte *clientphs;
|
|
|
|
byte *bitvector;
|
2007-06-21 22:00:00 +02:00
|
|
|
|
|
|
|
clent = client->edict;
|
2007-09-16 22:00:00 +02:00
|
|
|
if (!clent->priv.sv->client) return;// not in game yet
|
2007-09-04 22:00:00 +02:00
|
|
|
|
2007-06-21 22:00:00 +02:00
|
|
|
// this is the frame we are creating
|
|
|
|
frame = &client->frames[sv.framenum & UPDATE_MASK];
|
2007-09-06 22:00:00 +02:00
|
|
|
|
2007-06-21 22:00:00 +02:00
|
|
|
frame->senttime = svs.realtime; // save it for ping calc later
|
|
|
|
|
|
|
|
// find the client's PVS
|
2008-01-19 22:00:00 +01:00
|
|
|
VectorCopy( clent->priv.sv->client->ps.origin, org );
|
2008-01-12 22:00:00 +01:00
|
|
|
VectorAdd( org, clent->priv.sv->client->ps.viewoffset, org );
|
2007-06-21 22:00:00 +02:00
|
|
|
|
2008-01-15 22:00:00 +01:00
|
|
|
leafnum = pe->PointLeafnum (org);
|
|
|
|
clientarea = pe->LeafArea (leafnum);
|
|
|
|
clientcluster = pe->LeafCluster (leafnum);
|
2007-06-21 22:00:00 +02:00
|
|
|
|
|
|
|
// calculate the visible areas
|
2008-01-15 22:00:00 +01:00
|
|
|
frame->areabytes = pe->WriteAreaBits (frame->areabits, clientarea);
|
2007-06-21 22:00:00 +02:00
|
|
|
|
|
|
|
// grab the current player_state_t
|
2007-09-16 22:00:00 +02:00
|
|
|
frame->ps = clent->priv.sv->client->ps;
|
2007-09-06 22:00:00 +02:00
|
|
|
|
2008-01-17 22:00:00 +01:00
|
|
|
clientpvs = pe->ClusterPVS( clientcluster );
|
|
|
|
clientphs = pe->ClusterPHS( clientcluster );
|
2007-06-21 22:00:00 +02:00
|
|
|
|
|
|
|
// build up the list of visible entities
|
|
|
|
frame->num_entities = 0;
|
|
|
|
frame->first_entity = svs.next_client_entities;
|
|
|
|
|
|
|
|
c_fullsend = 0;
|
|
|
|
|
2007-09-16 22:00:00 +02:00
|
|
|
for (e = 1; e < prog->num_edicts; e++)
|
2007-06-21 22:00:00 +02:00
|
|
|
{
|
2007-09-16 22:00:00 +02:00
|
|
|
ent = PRVM_EDICT_NUM(e);
|
2007-06-21 22:00:00 +02:00
|
|
|
|
|
|
|
// ignore ents without visible models unless they have an effect
|
2007-10-03 22:00:00 +02:00
|
|
|
if (!ent->progs.sv->modelindex && !ent->progs.sv->effects && !ent->progs.sv->noise3 && !ent->priv.sv->event)
|
2007-06-21 22:00:00 +02:00
|
|
|
continue;
|
|
|
|
|
|
|
|
// ignore if not touching a PV leaf
|
|
|
|
if (ent != clent)
|
|
|
|
{
|
|
|
|
// check area
|
2008-01-15 22:00:00 +01:00
|
|
|
if (!pe->AreasConnected (clientarea, ent->priv.sv->areanum))
|
2007-09-17 22:00:00 +02:00
|
|
|
{
|
|
|
|
// doors can legally straddle two areas, so
|
2007-06-21 22:00:00 +02:00
|
|
|
// we may need to check another one
|
2008-01-15 22:00:00 +01:00
|
|
|
if (!ent->priv.sv->areanum2 || !pe->AreasConnected (clientarea, ent->priv.sv->areanum2))
|
2007-09-17 22:00:00 +02:00
|
|
|
continue; // blocked by a door
|
2007-06-21 22:00:00 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// beams just check one point for PHS
|
2007-09-18 22:00:00 +02:00
|
|
|
if ((int)ent->progs.sv->renderfx & RF_BEAM)
|
2007-06-21 22:00:00 +02:00
|
|
|
{
|
2007-09-16 22:00:00 +02:00
|
|
|
l = ent->priv.sv->clusternums[0];
|
2007-06-21 22:00:00 +02:00
|
|
|
if ( !(clientphs[l >> 3] & (1 << (l&7) )) )
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// FIXME: if an ent has a model and a sound, but isn't
|
|
|
|
// in the PVS, only the PHS, clear the model
|
2008-01-17 22:00:00 +01:00
|
|
|
if (ent->progs.sv->noise3) bitvector = clientphs;
|
|
|
|
else bitvector = clientpvs;
|
2007-06-21 22:00:00 +02:00
|
|
|
|
2008-01-16 22:00:00 +01:00
|
|
|
// check individual leafs
|
2008-01-17 22:00:00 +01:00
|
|
|
if( !ent->priv.sv->num_clusters )
|
2008-01-16 22:00:00 +01:00
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
for( i = 0, l = 0; i < ent->priv.sv->num_clusters; i++ )
|
|
|
|
{
|
|
|
|
l = ent->priv.sv->clusternums[i];
|
|
|
|
if( bitvector[l>>3] & (1<<(l&7)))
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
// if we haven't found it to be visible,
|
|
|
|
// check overflow clusters that coudln't be stored
|
|
|
|
if( i == ent->priv.sv->num_clusters )
|
|
|
|
{
|
2008-01-17 22:00:00 +01:00
|
|
|
if( ent->priv.sv->lastcluster )
|
2008-01-16 22:00:00 +01:00
|
|
|
{
|
2008-01-17 22:00:00 +01:00
|
|
|
for( ; l <= ent->priv.sv->lastcluster; l++ )
|
2008-01-16 22:00:00 +01:00
|
|
|
{
|
|
|
|
if( bitvector[l>>3] & (1<<(l&7)))
|
|
|
|
break;
|
|
|
|
}
|
2008-01-17 22:00:00 +01:00
|
|
|
if( l == ent->priv.sv->lastcluster )
|
2008-01-16 22:00:00 +01:00
|
|
|
continue; // not visible
|
|
|
|
}
|
|
|
|
else continue;
|
2007-06-21 22:00:00 +02:00
|
|
|
}
|
2007-09-18 22:00:00 +02:00
|
|
|
if (!ent->progs.sv->modelindex)
|
2007-09-17 22:00:00 +02:00
|
|
|
{
|
|
|
|
// don't send sounds if they will be attenuated away
|
2007-06-21 22:00:00 +02:00
|
|
|
vec3_t delta;
|
|
|
|
float len;
|
|
|
|
|
2007-09-18 22:00:00 +02:00
|
|
|
VectorSubtract (org, ent->progs.sv->origin, delta);
|
2007-06-21 22:00:00 +02:00
|
|
|
len = VectorLength (delta);
|
2007-09-17 22:00:00 +02:00
|
|
|
if (len > 400) continue;
|
2007-06-21 22:00:00 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// add it to the circular client_entities array
|
2007-08-17 22:00:00 +02:00
|
|
|
state = &svs.client_entities[svs.next_client_entities % svs.num_client_entities];
|
2007-09-18 22:00:00 +02:00
|
|
|
if (ent->priv.sv->serialnumber != e)
|
2007-06-21 22:00:00 +02:00
|
|
|
{
|
2007-09-18 22:00:00 +02:00
|
|
|
MsgWarn ("SV_BuildClientFrame: invalid ent->priv.sv->serialnumber %d\n", ent->priv.sv->serialnumber );
|
|
|
|
ent->priv.sv->serialnumber = e; // ptr to current entity such as entnumber
|
2007-06-21 22:00:00 +02:00
|
|
|
}
|
2007-09-17 22:00:00 +02:00
|
|
|
|
2007-09-18 22:00:00 +02:00
|
|
|
SV_UpdateEntityState( ent );
|
2007-09-16 22:00:00 +02:00
|
|
|
*state = ent->priv.sv->s;
|
2007-06-21 22:00:00 +02:00
|
|
|
|
|
|
|
// don't mark players missiles as solid
|
2007-09-16 22:00:00 +02:00
|
|
|
if (PRVM_PROG_TO_EDICT(ent->progs.sv->owner) == client->edict) state->solid = 0;
|
2007-06-21 22:00:00 +02:00
|
|
|
|
|
|
|
svs.next_client_entities++;
|
|
|
|
frame->num_entities++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
==================
|
|
|
|
SV_RecordDemoMessage
|
|
|
|
|
|
|
|
Save everything in the world out without deltas.
|
|
|
|
Used for recording footage for merged or assembled demos
|
|
|
|
==================
|
|
|
|
*/
|
|
|
|
void SV_RecordDemoMessage (void)
|
|
|
|
{
|
2007-10-19 22:00:00 +02:00
|
|
|
int e;
|
2007-09-06 22:00:00 +02:00
|
|
|
edict_t *ent;
|
2007-06-21 22:00:00 +02:00
|
|
|
entity_state_t nostate;
|
|
|
|
sizebuf_t buf;
|
|
|
|
byte buf_data[32768];
|
2007-10-19 22:00:00 +02:00
|
|
|
int len;
|
2007-06-21 22:00:00 +02:00
|
|
|
|
2007-10-19 22:00:00 +02:00
|
|
|
if (!svs.demofile) return;
|
2007-06-21 22:00:00 +02:00
|
|
|
|
|
|
|
memset (&nostate, 0, sizeof(nostate));
|
|
|
|
SZ_Init (&buf, buf_data, sizeof(buf_data));
|
|
|
|
|
|
|
|
// write a frame message that doesn't contain a player_state_t
|
|
|
|
MSG_WriteByte (&buf, svc_frame);
|
|
|
|
MSG_WriteLong (&buf, sv.framenum);
|
|
|
|
MSG_WriteByte (&buf, svc_packetentities);
|
|
|
|
|
|
|
|
e = 1;
|
2007-09-16 22:00:00 +02:00
|
|
|
ent = PRVM_EDICT_NUM(e);
|
|
|
|
while (e < prog->num_edicts)
|
2007-06-21 22:00:00 +02:00
|
|
|
{
|
|
|
|
// ignore ents without visible models unless they have an effect
|
2007-10-19 22:00:00 +02:00
|
|
|
if (!ent->priv.sv->free && ent->priv.sv->serialnumber && (ent->priv.sv->s.modelindex || ent->progs.sv->effects || ent->progs.sv->noise3 || ent->priv.sv->event))
|
|
|
|
{
|
|
|
|
SV_UpdateEntityState( ent );
|
2007-09-16 22:00:00 +02:00
|
|
|
MSG_WriteDeltaEntity (&nostate, &ent->priv.sv->s, &buf, false, true);
|
2007-10-19 22:00:00 +02:00
|
|
|
}
|
2007-06-21 22:00:00 +02:00
|
|
|
e++;
|
2007-09-16 22:00:00 +02:00
|
|
|
ent = PRVM_EDICT_NUM(e);
|
2007-06-21 22:00:00 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
MSG_WriteShort (&buf, 0); // end of packetentities
|
|
|
|
|
|
|
|
// now add the accumulated multicast information
|
|
|
|
SZ_Write (&buf, svs.demo_multicast.data, svs.demo_multicast.cursize);
|
|
|
|
SZ_Clear (&svs.demo_multicast);
|
|
|
|
|
|
|
|
// now write the entire message to the file, prefixed by the length
|
|
|
|
len = LittleLong (buf.cursize);
|
|
|
|
FS_Write (svs.demofile, &len, 4);
|
|
|
|
FS_Write (svs.demofile, buf.data, buf.cursize);
|
|
|
|
}
|
|
|
|
|