This repository has been archived on 2022-06-27. You can view files and clone it, but cannot push or open issues or pull requests.
Xash3DArchive/engine/server/sv_frame.c

720 lines
18 KiB
C
Raw Normal View History

2008-07-09 22:00:00 +02:00
//=======================================================================
// Copyright XashXT Group 2008 <20>
// sv_frame.c - server world snapshot
//=======================================================================
#include "common.h"
2008-07-16 22:00:00 +02:00
#include "server.h"
2008-11-25 22:00:00 +01:00
#include "const.h"
2010-08-04 22:00:00 +02:00
#include "net_encode.h"
2010-08-15 22:00:00 +02:00
#include "entity_types.h"
2008-07-16 22:00:00 +02:00
2010-08-16 22:00:00 +02:00
#define MAX_VISIBLE_PACKET 512
2008-09-09 22:00:00 +02:00
typedef struct
2008-07-16 22:00:00 +02:00
{
2010-08-16 22:00:00 +02:00
int num_entities;
entity_state_t entities[MAX_VISIBLE_PACKET];
2008-09-09 22:00:00 +02:00
} sv_ents_t;
2008-07-16 22:00:00 +02:00
2008-11-14 22:00:00 +01:00
static byte *clientpvs; // FatPVS
2009-11-25 22:00:00 +01:00
static byte *clientphs; // FatPHS
2008-11-11 22:00:00 +01:00
2008-09-09 22:00:00 +02:00
int c_fullsend;
2008-07-16 22:00:00 +02:00
2008-09-09 22:00:00 +02:00
/*
=======================
SV_EntityNumbers
=======================
*/
static int SV_EntityNumbers( const void *a, const void *b )
{
2010-08-16 22:00:00 +02:00
int ent1, ent2;
ent1 = ((entity_state_t *)a)->number;
ent2 = ((entity_state_t *)b)->number;
2008-07-16 22:00:00 +02:00
2010-08-16 22:00:00 +02:00
if( ent1 == ent2 )
Host_Error( "SV_SortEntities: duplicated entity\n" );
2008-07-16 22:00:00 +02:00
2010-08-16 22:00:00 +02:00
if( ent1 < ent2 )
return -1;
2008-09-09 22:00:00 +02:00
return 1;
2008-07-16 22:00:00 +02:00
}
2010-10-10 22:00:00 +02:00
/*
=======================
SV_ClearPacketEntities
=======================
*/
void SV_ClearPacketEntities( client_frame_t *frame )
{
packet_entities_t *packet;
ASSERT( frame != NULL );
packet = &frame->entities;
if( packet )
{
if( packet->entities != NULL )
Mem_Free( packet->entities );
packet->num_entities = 0;
packet->entities = NULL;
}
}
/*
=======================
SV_AllocPacketEntities
=======================
*/
void SV_AllocPacketEntities( client_frame_t *frame, int count )
{
packet_entities_t *packet;
ASSERT( frame != NULL );
packet = &frame->entities;
if( packet->entities != NULL )
{
SV_ClearPacketEntities( frame );
}
if( count < 1 ) count = 1;
packet->entities = Mem_Alloc( svgame.mempool, sizeof( entity_state_t ) * count );
packet->num_entities = count;
}
/*
================
SV_ClearFrames
free client frames memory
================
*/
void SV_ClearFrames( client_frame_t **frames )
{
client_frame_t *frame;
int i;
if( *frames == NULL )
return;
for( i = 0, frame = *frames; i < SV_UPDATE_BACKUP; i++, frames++ )
{
SV_ClearPacketEntities( frame );
frame->senttime = 0.0f;
frame->ping_time = -1;
}
Mem_Free( *frames );
*frames = NULL;
}
2008-07-16 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->
=============
*/
2010-10-10 22:00:00 +02:00
void SV_EmitPacketEntities( packet_entities_t *from, packet_entities_t *to, sizebuf_t *msg )
2008-07-16 22:00:00 +02:00
{
2010-10-10 22:00:00 +02:00
int oldindex, newindex;
int oldnum, newnum;
int oldmax;
2008-07-16 22:00:00 +02:00
2010-08-04 22:00:00 +02:00
BF_WriteByte( msg, svc_packetentities );
2010-06-22 22:00:00 +02:00
2010-10-10 22:00:00 +02:00
if( !from ) oldmax = 0;
else oldmax = from->num_entities;
2008-07-16 22:00:00 +02:00
newindex = 0;
oldindex = 0;
2010-06-28 22:00:00 +02:00
2010-10-10 22:00:00 +02:00
while( newindex < to->num_entities || oldindex < oldmax )
2008-07-16 22:00:00 +02:00
{
2010-10-10 22:00:00 +02:00
newnum = newindex >= to->num_entities ? MAX_ENTNUMBER : to->entities[newindex].number;
oldnum = oldindex >= oldmax ? MAX_ENTNUMBER : from->entities[oldindex].number;
2008-07-16 22:00:00 +02:00
if( newnum == oldnum )
{
// delta update from old position
// because the force parm is false, this will not result
// in any bytes being emited if the entity has not changed at all
2010-10-10 22:00:00 +02:00
MSG_WriteDeltaEntity( &from->entities[oldindex], &to->entities[newindex], msg, false, sv_time( ));
2008-07-16 22:00:00 +02:00
oldindex++;
newindex++;
continue;
}
2010-06-28 22:00:00 +02:00
2008-07-16 22:00:00 +02:00
if( newnum < oldnum )
{
// this is a new entity, send it from the baseline
2010-10-10 22:00:00 +02:00
MSG_WriteDeltaEntity( &svs.baselines[newnum], &to->entities[newindex], msg, true, sv_time( ));
2008-07-16 22:00:00 +02:00
newindex++;
continue;
}
2010-06-28 22:00:00 +02:00
2008-07-16 22:00:00 +02:00
if( newnum > oldnum )
{
2010-08-25 22:00:00 +02:00
bool force;
2010-10-10 22:00:00 +02:00
if( EDICT_NUM( from->entities[oldindex].number )->free )
2010-08-25 22:00:00 +02:00
force = true; // entity completely removed from server
else force = false; // just removed from delta-message
2008-11-25 22:00:00 +01:00
// remove from message
2010-10-10 22:00:00 +02:00
MSG_WriteDeltaEntity( &from->entities[oldindex], NULL, msg, force, sv_time( ));
2008-07-16 22:00:00 +02:00
oldindex++;
continue;
}
}
2010-08-04 22:00:00 +02:00
BF_WriteWord( msg, 0 ); // end of packetentities
2008-07-16 22:00:00 +02:00
}
2010-08-15 22:00:00 +02:00
static void SV_AddEntitiesToPacket( edict_t *pViewEnt, edict_t *pClient, client_frame_t *frame, sv_ents_t *ents )
2008-09-09 22:00:00 +02:00
{
edict_t *ent;
2009-11-25 22:00:00 +01:00
byte *pset;
2010-05-22 22:00:00 +02:00
bool fullvis = false;
2010-08-15 22:00:00 +02:00
sv_client_t *cl, *netclient;
entity_state_t *state;
2010-10-09 22:00:00 +02:00
int e, player;
2008-09-09 22:00:00 +02:00
// during an error shutdown message we may need to transmit
// the shutdown message after the server has shutdown, so
// specfically check for it
if( !sv.state ) return;
2010-08-15 22:00:00 +02:00
if( pClient && !( sv.hostflags & SVF_PORTALPASS ))
2010-03-14 22:00:00 +01:00
{
// portals can't change hostflags
2010-04-12 22:00:00 +02:00
sv.hostflags &= ~SVF_SKIPLOCALHOST;
2010-03-14 22:00:00 +01:00
cl = SV_ClientFromEdict( pClient, true );
2010-07-29 22:00:00 +02:00
ASSERT( cl );
2010-03-14 22:00:00 +01:00
// setup hostflags
if( com.atoi( Info_ValueForKey( cl->userinfo, "cl_lw" )) == 1 )
sv.hostflags |= SVF_SKIPLOCALHOST;
}
2010-08-15 22:00:00 +02:00
svgame.dllFuncs.pfnSetupVisibility( pViewEnt, pClient, &clientpvs, &clientphs );
2010-05-22 22:00:00 +02:00
if( !clientpvs ) fullvis = true;
2008-09-09 22:00:00 +02:00
2010-08-15 22:00:00 +02:00
for( e = 1; e < svgame.numEntities; e++ )
2008-09-09 22:00:00 +02:00
{
2008-12-15 22:00:00 +01:00
ent = EDICT_NUM( e );
2008-12-17 22:00:00 +01:00
if( ent->free ) continue;
2008-09-09 22:00:00 +02:00
2008-12-15 22:00:00 +01:00
if( ent->serialnumber != e )
2008-09-09 22:00:00 +02:00
{
2009-11-25 22:00:00 +01:00
// this should never happens
MsgDev( D_NOTE, "fixing ent->serialnumber from %i to %i\n", ent->serialnumber, e );
2008-12-15 22:00:00 +01:00
ent->serialnumber = e;
2008-09-09 22:00:00 +02:00
}
2009-11-25 22:00:00 +01:00
// don't double add an entity through portals (already added)
2010-08-18 22:00:00 +02:00
if( ent->framenum == sv.net_framenum )
2009-11-25 22:00:00 +01:00
continue;
2008-11-15 22:00:00 +01:00
2010-08-15 22:00:00 +02:00
if( ent->v.flags & FL_CHECK_PHS )
2009-11-25 22:00:00 +01:00
pset = clientphs;
else pset = clientpvs;
2008-09-09 22:00:00 +02:00
2010-08-16 22:00:00 +02:00
state = &ents->entities[ents->num_entities];
2010-08-15 22:00:00 +02:00
netclient = SV_ClientFromEdict( ent, true );
2010-10-09 22:00:00 +02:00
player = ( netclient != NULL );
2010-08-15 22:00:00 +02:00
2010-06-28 22:00:00 +02:00
// add entity to the net packet
2010-10-09 22:00:00 +02:00
if( svgame.dllFuncs.pfnAddToFullPack( state, e, ent, pClient, sv.hostflags, player, pset ))
2009-11-25 22:00:00 +01:00
{
2010-06-28 22:00:00 +02:00
// to prevent adds it twice through portals
2010-08-18 22:00:00 +02:00
ent->framenum = sv.net_framenum;
2010-06-28 22:00:00 +02:00
2010-07-24 22:00:00 +02:00
if( netclient && netclient->modelindex ) // apply custom model if present
2010-08-15 22:00:00 +02:00
state->modelindex = netclient->modelindex;
2010-07-24 22:00:00 +02:00
2010-06-28 22:00:00 +02:00
// if we are full, silently discard entities
if( ents->num_entities < MAX_VISIBLE_PACKET )
{
2010-08-16 22:00:00 +02:00
ents->num_entities++; // entity accepted
c_fullsend++; // debug counter
2010-06-28 22:00:00 +02:00
}
else MsgDev( D_ERROR, "too many entities in visible packet list\n" );
2008-09-09 22:00:00 +02:00
}
2010-05-22 22:00:00 +02:00
if( fullvis ) continue; // portal ents will be added anyway, ignore recursion
2010-08-15 22:00:00 +02:00
2008-09-09 22:00:00 +02:00
// if its a portal entity, add everything visible from its camera position
2010-08-15 22:00:00 +02:00
if( !( sv.hostflags & SVF_PORTALPASS ) && ent->v.effects & EF_MERGE_VISIBILITY )
2010-05-22 22:00:00 +02:00
{
2010-08-15 22:00:00 +02:00
sv.hostflags |= SVF_PORTALPASS;
SV_AddEntitiesToPacket( ent, pClient, frame, ents );
sv.hostflags &= ~SVF_PORTALPASS;
2010-05-22 22:00:00 +02:00
}
2008-09-09 22:00:00 +02:00
}
}
2010-08-06 22:00:00 +02:00
static void SV_EmitEvents( sv_client_t *cl, client_frame_t *frame, sizebuf_t *msg )
2009-12-02 22:00:00 +01:00
{
int i, ev;
event_state_t *es;
event_info_t *info;
int ev_count = 0;
int c;
es = &cl->events;
// count events
for( ev = 0; ev < MAX_EVENT_QUEUE; ev++ )
{
info = &es->ei[ev];
if( info->index == 0 )
continue;
ev_count++;
}
// nothing to send
if( !ev_count ) return;
if( ev_count >= MAX_EVENT_QUEUE )
ev_count = MAX_EVENT_QUEUE - 1;
2010-08-04 22:00:00 +02:00
BF_WriteByte( msg, svc_event ); // create message
BF_WriteByte( msg, ev_count ); // Up to MAX_EVENT_QUEUE events
2009-12-02 22:00:00 +01:00
for( i = c = 0 ; i < MAX_EVENT_QUEUE; i++ )
{
info = &es->ei[i];
if( info->index == 0 )
continue;
// only send if there's room
if ( c < ev_count )
SV_PlaybackEvent( msg, info );
info->index = 0;
c++;
}
}
2010-08-04 22:00:00 +02:00
/*
=============
SV_WriteClientData
=============
*/
2010-08-06 22:00:00 +02:00
void SV_WriteClientData( client_frame_t *from, client_frame_t *to, sizebuf_t *msg )
2010-08-04 22:00:00 +02:00
{
clientdata_t *cd, *ocd;
clientdata_t dummy;
2010-10-10 22:00:00 +02:00
cd = &to->clientdata;
2010-08-04 22:00:00 +02:00
if( !from )
{
Mem_Set( &dummy, 0, sizeof( dummy ));
ocd = &dummy;
}
2010-10-10 22:00:00 +02:00
else ocd = &from->clientdata;
2010-08-04 22:00:00 +02:00
BF_WriteByte( msg, svc_clientdata );
MSG_WriteClientData( msg, ocd, cd, sv.time );
}
2008-07-16 22:00:00 +02:00
/*
==================
SV_WriteFrameToClient
==================
*/
2010-08-06 22:00:00 +02:00
void SV_WriteFrameToClient( sv_client_t *cl, sizebuf_t *msg )
2008-07-16 22:00:00 +02:00
{
client_frame_t *frame, *oldframe;
2010-10-10 22:00:00 +02:00
packet_entities_t *from, *to;
2010-06-22 22:00:00 +02:00
int lastframe;
// this is the frame we are creating
frame = &cl->frames[sv.framenum & SV_UPDATE_MASK];
2010-10-10 22:00:00 +02:00
to = &frame->entities;
2008-07-16 22:00:00 +02:00
2010-06-22 22:00:00 +02:00
if( cl->lastframe <= 0 )
{
// client is asking for a retransmit
oldframe = NULL;
lastframe = -1;
2010-10-10 22:00:00 +02:00
from = NULL;
2010-06-22 22:00:00 +02:00
}
else if( sv.framenum - cl->lastframe >= (SV_UPDATE_BACKUP - 3))
2008-07-16 22:00:00 +02:00
{
2010-06-22 22:00:00 +02:00
// client hasn't gotten a good message through in a long time
oldframe = NULL;
lastframe = -1;
2010-10-10 22:00:00 +02:00
from = NULL;
2010-06-22 22:00:00 +02:00
}
else
{ // we have a valid message to delta from
oldframe = &cl->frames[cl->lastframe & SV_UPDATE_MASK];
lastframe = cl->lastframe;
2010-10-10 22:00:00 +02:00
from = &oldframe->entities;
2008-07-16 22:00:00 +02:00
}
2009-12-02 22:00:00 +01:00
// delta encode the events
SV_EmitEvents( cl, frame, msg );
2010-08-04 22:00:00 +02:00
BF_WriteByte( msg, svc_frame );
2010-10-09 22:00:00 +02:00
BF_WriteFloat( msg, (float)sv.time ); // send a servertime each frame
2010-08-04 22:00:00 +02:00
BF_WriteLong( msg, sv.framenum );
BF_WriteLong( msg, lastframe ); // what we are delta'ing from
BF_WriteByte( msg, cl->surpressCount ); // rate dropped packets
2010-06-22 22:00:00 +02:00
cl->surpressCount = 0;
2008-07-16 22:00:00 +02:00
2010-08-04 22:00:00 +02:00
// delta encode the clientdata
SV_WriteClientData( oldframe, frame, msg );
2009-09-28 22:00:00 +02:00
// delta encode the entities
2010-10-10 22:00:00 +02:00
SV_EmitPacketEntities( from, to, msg );
2008-07-16 22:00:00 +02:00
}
/*
=============================================================================
Build a client frame structure
=============================================================================
*/
/*
=============
SV_BuildClientFrame
2010-05-22 22:00:00 +02:00
Decides which entities are going to be visible to the client,
and copies off the playerstate.
2008-07-16 22:00:00 +02:00
=============
*/
void SV_BuildClientFrame( sv_client_t *cl )
{
edict_t *clent;
2009-11-25 22:00:00 +01:00
edict_t *viewent; // may be NULL
2008-07-16 22:00:00 +02:00
client_frame_t *frame;
2010-10-10 22:00:00 +02:00
packet_entities_t *packet;
2010-08-16 22:00:00 +02:00
static sv_ents_t frame_ents;
2008-07-16 22:00:00 +02:00
clent = cl->edict;
2009-11-25 22:00:00 +01:00
viewent = cl->pViewEntity;
2008-09-09 22:00:00 +02:00
sv.net_framenum++;
2008-07-16 22:00:00 +02:00
2010-07-23 22:00:00 +02:00
if( !sv.paused )
2010-06-28 22:00:00 +02:00
{
2010-07-23 22:00:00 +02:00
// update client fixangle
switch( clent->v.fixangle )
{
case 1:
2010-10-09 22:00:00 +02:00
BF_WriteByte( &cl->netchan.message, svc_setangle );
BF_WriteBitAngle( &cl->netchan.message, clent->v.angles[0], 16 );
BF_WriteBitAngle( &cl->netchan.message, clent->v.angles[1], 16 );
2010-08-15 22:00:00 +02:00
clent->v.effects |= EF_NOINTERP;
2010-07-23 22:00:00 +02:00
break;
case 2:
2010-10-09 22:00:00 +02:00
BF_WriteByte( &cl->netchan.message, svc_addangle );
BF_WriteBitAngle( &cl->netchan.message, cl->addangle, 16 );
2010-07-23 22:00:00 +02:00
cl->addangle = 0;
break;
}
clent->v.fixangle = 0; // reset fixangle
}
2010-06-28 22:00:00 +02:00
2008-07-16 22:00:00 +02:00
// this is the frame we are creating
2010-06-22 22:00:00 +02:00
frame = &cl->frames[sv.framenum & SV_UPDATE_MASK];
2010-10-09 22:00:00 +02:00
frame->senttime = host.realtime; // save it for ping calc later
2010-10-10 22:00:00 +02:00
packet = &frame->entities;
2008-09-09 22:00:00 +02:00
// clear everything in this snapshot
frame_ents.num_entities = c_fullsend = 0;
2010-08-18 22:00:00 +02:00
if( !SV_ClientFromEdict( clent, true )) return; // not in game yet
2008-09-09 22:00:00 +02:00
2010-08-04 22:00:00 +02:00
// update clientdata_t
2010-10-10 22:00:00 +02:00
svgame.dllFuncs.pfnUpdateClientData( clent, false, &frame->clientdata );
2008-09-09 22:00:00 +02:00
// add all the entities directly visible to the eye, which
// may include portal entities that merge other viewpoints
2010-08-15 22:00:00 +02:00
sv.hostflags &= ~SVF_PORTALPASS;
SV_AddEntitiesToPacket( viewent, clent, frame, &frame_ents );
2008-07-16 22:00:00 +02:00
2008-09-09 22:00:00 +02:00
// if there were portals visible, there may be out of order entities
// in the list which will need to be resorted for the delta compression
// to work correctly. This also catches the error condition
// of an entity being included twice.
qsort( frame_ents.entities, frame_ents.num_entities, sizeof( frame_ents.entities[0] ), SV_EntityNumbers );
2008-07-16 22:00:00 +02:00
2010-10-10 22:00:00 +02:00
// copy the entity states to client frame
SV_AllocPacketEntities( frame, frame_ents.num_entities );
Mem_Copy( packet->entities, frame_ents.entities, sizeof( entity_state_t ) * frame_ents.num_entities );
2008-07-16 22:00:00 +02:00
}
/*
===============================================================================
FRAME UPDATES
===============================================================================
*/
/*
=======================
SV_SendClientDatagram
=======================
*/
bool SV_SendClientDatagram( sv_client_t *cl )
{
2010-08-04 22:00:00 +02:00
byte msg_buf[MAX_MSGLEN];
2010-08-06 22:00:00 +02:00
sizebuf_t msg;
2008-07-16 22:00:00 +02:00
SV_BuildClientFrame( cl );
2010-08-04 22:00:00 +02:00
BF_Init( &msg, "Datagram", msg_buf, sizeof( msg_buf ));
2008-07-16 22:00:00 +02:00
// send over all the relevant entity_state_t
2008-07-30 22:00:00 +02:00
// and the player state
2008-07-16 22:00:00 +02:00
SV_WriteFrameToClient( cl, &msg );
2010-08-04 22:00:00 +02:00
if( BF_CheckOverflow( &msg ))
2009-09-19 22:00:00 +02:00
{
// must have room left for the packet header
MsgDev( D_WARN, "msg overflowed for %s\n", cl->name );
2010-08-04 22:00:00 +02:00
BF_Clear( &msg );
2009-09-19 22:00:00 +02:00
}
2008-07-16 22:00:00 +02:00
// copy the accumulated multicast datagram
// for this client out to the message
// it is necessary for this to be after the WriteEntities
// so that entity references will be current
2010-08-04 22:00:00 +02:00
if( BF_CheckOverflow( &cl->datagram )) MsgDev( D_WARN, "datagram overflowed for %s\n", cl->name );
else BF_WriteBits( &msg, BF_GetData( &cl->datagram ), BF_GetNumBitsWritten( &cl->datagram ));
BF_Clear( &cl->datagram );
2008-07-16 22:00:00 +02:00
2010-08-04 22:00:00 +02:00
if( BF_CheckOverflow( &msg ))
2008-07-16 22:00:00 +02:00
{
// must have room left for the packet header
MsgDev( D_WARN, "msg overflowed for %s\n", cl->name );
2010-08-04 22:00:00 +02:00
BF_Clear( &msg );
2008-07-16 22:00:00 +02:00
}
2008-11-25 22:00:00 +01:00
2009-09-16 22:00:00 +02:00
// send the datagram
2010-08-04 22:00:00 +02:00
Netchan_TransmitBits( &cl->netchan, BF_GetNumBitsWritten( &msg ), BF_GetData( &msg ));
2009-09-16 22:00:00 +02:00
2010-07-02 22:00:00 +02:00
// record the size for rate estimation
2010-08-04 22:00:00 +02:00
cl->message_size[sv.framenum % RATE_MESSAGES] = BF_GetNumBytesWritten( &msg );
2010-07-02 22:00:00 +02:00
2008-07-16 22:00:00 +02:00
return true;
}
2010-07-02 22:00:00 +02:00
/*
=======================
SV_RateDrop
Returns true if the client is over its current
bandwidth estimation and should not be sent another packet
=======================
*/
bool SV_RateDrop( sv_client_t *cl )
{
int i, total = 0;
// never drop over the loopback
if( NET_IsLocalAddress( cl->netchan.remote_address ))
return false;
for( i = 0; i < RATE_MESSAGES; i++ )
total += cl->message_size[i];
if( total > cl->rate )
{
cl->surpressCount++;
cl->message_size[sv.framenum % RATE_MESSAGES] = 0;
return true;
}
return false;
}
2010-10-09 22:00:00 +02:00
/*
=======================
SV_UpdateToReliableMessages
=======================
*/
void SV_UpdateToReliableMessages( void )
{
int i;
sv_client_t *cl;
// check for changes to be sent over the reliable streams to all clients
for( i = 0, cl = svs.clients; i < sv_maxclients->integer; i++, cl++ )
{
if( !cl->edict ) continue; // not in game yet
if( cl->state != cs_spawned )
continue;
if( cl->sendinfo )
{
cl->sendinfo = false;
SV_FullClientUpdate( cl, &sv.reliable_datagram );
}
}
// clear the server datagram if it overflowed.
if( BF_CheckOverflow( &sv.datagram ))
{
MsgDev( D_ERROR, "sv.datagram overflowed!\n" );
BF_Clear( &sv.datagram );
}
// now send the reliable and server datagrams to all clients.
for( i = 0, cl = svs.clients; i < sv_maxclients->integer; i++, cl++ )
{
if( cl->state < cs_connected || cl->fakeclient )
continue; // reliables go to all connected or spawned
BF_WriteBits( &cl->netchan.message, BF_GetData( &sv.reliable_datagram ), BF_GetNumBitsWritten( &sv.reliable_datagram ));
BF_WriteBits( &cl->datagram, BF_GetData( &sv.datagram ), BF_GetNumBitsWritten( &sv.datagram ));
}
// now clear the reliable and datagram buffers.
BF_Clear( &sv.reliable_datagram );
BF_Clear( &sv.datagram );
}
2008-07-16 22:00:00 +02:00
/*
=======================
SV_SendClientMessages
=======================
*/
void SV_SendClientMessages( void )
{
sv_client_t *cl;
int i;
2010-06-23 22:00:00 +02:00
svs.currentPlayer = NULL;
2009-11-25 22:00:00 +01:00
if( sv.state == ss_dead )
return;
2009-09-28 22:00:00 +02:00
2010-10-09 22:00:00 +02:00
SV_UpdateToReliableMessages ();
// we always need to bump framenum, even if we
// don't run the world, otherwise the delta
// compression can get confused when a client
// has the "current" frame
sv.framenum++;
2008-07-16 22:00:00 +02:00
// send a message to each connected client
2009-09-25 22:00:00 +02:00
for( i = 0, cl = svs.clients; i < sv_maxclients->integer; i++, cl++ )
2008-07-16 22:00:00 +02:00
{
if( !cl->state ) continue;
2009-07-04 22:00:00 +02:00
2010-06-20 22:00:00 +02:00
if( !cl->edict || (cl->edict->v.flags & ( FL_FAKECLIENT|FL_SPECTATOR )))
2009-06-24 22:00:00 +02:00
continue;
2010-06-23 22:00:00 +02:00
svs.currentPlayer = cl;
2010-02-07 22:00:00 +01:00
if( cl->sendmovevars )
{
cl->sendmovevars = false;
2010-10-09 22:00:00 +02:00
SV_FullUpdateMovevars( cl, &cl->netchan.message );
2010-02-07 22:00:00 +01:00
}
2009-12-04 22:00:00 +01:00
2008-07-16 22:00:00 +02:00
// if the reliable message overflowed, drop the client
2010-08-04 22:00:00 +02:00
if( BF_CheckOverflow( &cl->netchan.message ))
2008-07-16 22:00:00 +02:00
{
2010-08-04 22:00:00 +02:00
BF_Clear( &cl->netchan.message );
BF_Clear( &cl->datagram );
2009-06-24 22:00:00 +02:00
SV_BroadcastPrintf( PRINT_HIGH, "%s overflowed\n", cl->name );
2008-07-16 22:00:00 +02:00
SV_DropClient( cl );
2010-04-03 22:00:00 +02:00
cl->send_message = true;
2008-07-16 22:00:00 +02:00
}
2010-04-03 22:00:00 +02:00
// only send messages if the client has sent one
if( !cl->send_message ) continue;
2008-08-02 22:00:00 +02:00
if( cl->state == cs_spawned )
2008-07-16 22:00:00 +02:00
{
2010-07-02 22:00:00 +02:00
// don't overrun bandwidth
if( SV_RateDrop( cl )) continue;
2008-07-16 22:00:00 +02:00
SV_SendClientDatagram( cl );
}
else
{
2010-10-09 22:00:00 +02:00
if( cl->netchan.message.iCurBit || host.realtime - cl->netchan.last_sent > 1.0f )
2008-07-16 22:00:00 +02:00
Netchan_Transmit( &cl->netchan, 0, NULL );
}
2010-04-03 22:00:00 +02:00
// yes, message really sended
cl->send_message = false;
2008-07-16 22:00:00 +02:00
}
2010-06-23 22:00:00 +02:00
// reset current client
svs.currentPlayer = NULL;
2010-03-24 22:00:00 +01:00
}
2010-04-03 22:00:00 +02:00
/*
=======================
SV_SendMessagesToAll
e.g. before changing level
=======================
*/
void SV_SendMessagesToAll( void )
{
int i;
sv_client_t *cl;
for( i = 0, cl = svs.clients; i < sv_maxclients->integer; i++, cl++ )
{
if( cl->state >= cs_connected )
cl->send_message = true;
}
SV_SendClientMessages();
}
2010-03-24 22:00:00 +01:00
/*
=======================
SV_InactivateClients
Purpose: Prepare for level transition, etc.
=======================
*/
void SV_InactivateClients( void )
{
int i;
sv_client_t *cl;
if( sv.state == ss_dead )
return;
// send a message to each connected client
for( i = 0, cl = svs.clients; i < sv_maxclients->integer; i++, cl++ )
{
if( !cl->state || !cl->edict ) continue;
2010-06-22 22:00:00 +02:00
if( !cl->edict || (cl->edict->v.flags & ( FL_FAKECLIENT|FL_SPECTATOR )))
2010-03-24 22:00:00 +01:00
continue;
if( svs.clients[i].state > cs_connected )
svs.clients[i].state = cs_connected;
// clear netchan message (but keep other buffers)
2010-08-04 22:00:00 +02:00
BF_Clear( &cl->netchan.message );
2010-03-24 22:00:00 +01:00
}
2008-07-16 22:00:00 +02:00
}