mirror of
https://github.com/id-Software/Quake.git
synced 2026-03-20 00:49:48 +01:00
The Quake sources as originally release under the GPL license on December 21, 1999
This commit is contained in:
806
QW/server/sv_send.c
Normal file
806
QW/server/sv_send.c
Normal file
@@ -0,0 +1,806 @@
|
||||
/*
|
||||
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.
|
||||
|
||||
*/
|
||||
// sv_main.c -- server main program
|
||||
|
||||
#include "qwsvdef.h"
|
||||
|
||||
#define CHAN_AUTO 0
|
||||
#define CHAN_WEAPON 1
|
||||
#define CHAN_VOICE 2
|
||||
#define CHAN_ITEM 3
|
||||
#define CHAN_BODY 4
|
||||
|
||||
/*
|
||||
=============================================================================
|
||||
|
||||
Con_Printf redirection
|
||||
|
||||
=============================================================================
|
||||
*/
|
||||
|
||||
char outputbuf[8000];
|
||||
|
||||
redirect_t sv_redirected;
|
||||
|
||||
extern cvar_t sv_phs;
|
||||
|
||||
/*
|
||||
==================
|
||||
SV_FlushRedirect
|
||||
==================
|
||||
*/
|
||||
void SV_FlushRedirect (void)
|
||||
{
|
||||
char send[8000+6];
|
||||
|
||||
if (sv_redirected == RD_PACKET)
|
||||
{
|
||||
send[0] = 0xff;
|
||||
send[1] = 0xff;
|
||||
send[2] = 0xff;
|
||||
send[3] = 0xff;
|
||||
send[4] = A2C_PRINT;
|
||||
memcpy (send+5, outputbuf, strlen(outputbuf)+1);
|
||||
|
||||
NET_SendPacket (strlen(send)+1, send, net_from);
|
||||
}
|
||||
else if (sv_redirected == RD_CLIENT)
|
||||
{
|
||||
ClientReliableWrite_Begin (host_client, svc_print, strlen(outputbuf)+3);
|
||||
ClientReliableWrite_Byte (host_client, PRINT_HIGH);
|
||||
ClientReliableWrite_String (host_client, outputbuf);
|
||||
}
|
||||
|
||||
// clear it
|
||||
outputbuf[0] = 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
==================
|
||||
SV_BeginRedirect
|
||||
|
||||
Send Con_Printf data to the remote client
|
||||
instead of the console
|
||||
==================
|
||||
*/
|
||||
void SV_BeginRedirect (redirect_t rd)
|
||||
{
|
||||
sv_redirected = rd;
|
||||
outputbuf[0] = 0;
|
||||
}
|
||||
|
||||
void SV_EndRedirect (void)
|
||||
{
|
||||
SV_FlushRedirect ();
|
||||
sv_redirected = RD_NONE;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
Con_Printf
|
||||
|
||||
Handles cursor positioning, line wrapping, etc
|
||||
================
|
||||
*/
|
||||
#define MAXPRINTMSG 4096
|
||||
// FIXME: make a buffer size safe vsprintf?
|
||||
void Con_Printf (char *fmt, ...)
|
||||
{
|
||||
va_list argptr;
|
||||
char msg[MAXPRINTMSG];
|
||||
|
||||
va_start (argptr,fmt);
|
||||
vsprintf (msg,fmt,argptr);
|
||||
va_end (argptr);
|
||||
|
||||
// add to redirected message
|
||||
if (sv_redirected)
|
||||
{
|
||||
if (strlen (msg) + strlen(outputbuf) > sizeof(outputbuf) - 1)
|
||||
SV_FlushRedirect ();
|
||||
strcat (outputbuf, msg);
|
||||
return;
|
||||
}
|
||||
|
||||
Sys_Printf ("%s", msg); // also echo to debugging console
|
||||
if (sv_logfile)
|
||||
fprintf (sv_logfile, "%s", msg);
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
Con_DPrintf
|
||||
|
||||
A Con_Printf that only shows up if the "developer" cvar is set
|
||||
================
|
||||
*/
|
||||
void Con_DPrintf (char *fmt, ...)
|
||||
{
|
||||
va_list argptr;
|
||||
char msg[MAXPRINTMSG];
|
||||
|
||||
if (!developer.value)
|
||||
return;
|
||||
|
||||
va_start (argptr,fmt);
|
||||
vsprintf (msg,fmt,argptr);
|
||||
va_end (argptr);
|
||||
|
||||
Con_Printf ("%s", msg);
|
||||
}
|
||||
|
||||
/*
|
||||
=============================================================================
|
||||
|
||||
EVENT MESSAGES
|
||||
|
||||
=============================================================================
|
||||
*/
|
||||
|
||||
static void SV_PrintToClient(client_t *cl, int level, char *string)
|
||||
{
|
||||
ClientReliableWrite_Begin (cl, svc_print, strlen(string)+3);
|
||||
ClientReliableWrite_Byte (cl, level);
|
||||
ClientReliableWrite_String (cl, string);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=================
|
||||
SV_ClientPrintf
|
||||
|
||||
Sends text across to be displayed if the level passes
|
||||
=================
|
||||
*/
|
||||
void SV_ClientPrintf (client_t *cl, int level, char *fmt, ...)
|
||||
{
|
||||
va_list argptr;
|
||||
char string[1024];
|
||||
|
||||
if (level < cl->messagelevel)
|
||||
return;
|
||||
|
||||
va_start (argptr,fmt);
|
||||
vsprintf (string, fmt,argptr);
|
||||
va_end (argptr);
|
||||
|
||||
SV_PrintToClient(cl, level, string);
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
SV_BroadcastPrintf
|
||||
|
||||
Sends text to all active clients
|
||||
=================
|
||||
*/
|
||||
void SV_BroadcastPrintf (int level, char *fmt, ...)
|
||||
{
|
||||
va_list argptr;
|
||||
char string[1024];
|
||||
client_t *cl;
|
||||
int i;
|
||||
|
||||
va_start (argptr,fmt);
|
||||
vsprintf (string, fmt,argptr);
|
||||
va_end (argptr);
|
||||
|
||||
Sys_Printf ("%s", string); // print to the console
|
||||
|
||||
for (i=0, cl = svs.clients ; i<MAX_CLIENTS ; i++, cl++)
|
||||
{
|
||||
if (level < cl->messagelevel)
|
||||
continue;
|
||||
if (!cl->state)
|
||||
continue;
|
||||
|
||||
SV_PrintToClient(cl, level, string);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
SV_BroadcastCommand
|
||||
|
||||
Sends text to all active clients
|
||||
=================
|
||||
*/
|
||||
void SV_BroadcastCommand (char *fmt, ...)
|
||||
{
|
||||
va_list argptr;
|
||||
char string[1024];
|
||||
|
||||
if (!sv.state)
|
||||
return;
|
||||
va_start (argptr,fmt);
|
||||
vsprintf (string, fmt,argptr);
|
||||
va_end (argptr);
|
||||
|
||||
MSG_WriteByte (&sv.reliable_datagram, svc_stufftext);
|
||||
MSG_WriteString (&sv.reliable_datagram, string);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=================
|
||||
SV_Multicast
|
||||
|
||||
Sends the contents of sv.multicast to a subset of the clients,
|
||||
then clears sv.multicast.
|
||||
|
||||
MULTICAST_ALL same as broadcast
|
||||
MULTICAST_PVS send to clients potentially visible from org
|
||||
MULTICAST_PHS send to clients potentially hearable from org
|
||||
=================
|
||||
*/
|
||||
void SV_Multicast (vec3_t origin, int to)
|
||||
{
|
||||
client_t *client;
|
||||
byte *mask;
|
||||
mleaf_t *leaf;
|
||||
int leafnum;
|
||||
int j;
|
||||
qboolean reliable;
|
||||
|
||||
leaf = Mod_PointInLeaf (origin, sv.worldmodel);
|
||||
if (!leaf)
|
||||
leafnum = 0;
|
||||
else
|
||||
leafnum = leaf - sv.worldmodel->leafs;
|
||||
|
||||
reliable = false;
|
||||
|
||||
switch (to)
|
||||
{
|
||||
case MULTICAST_ALL_R:
|
||||
reliable = true; // intentional fallthrough
|
||||
case MULTICAST_ALL:
|
||||
mask = sv.pvs; // leaf 0 is everything;
|
||||
break;
|
||||
|
||||
case MULTICAST_PHS_R:
|
||||
reliable = true; // intentional fallthrough
|
||||
case MULTICAST_PHS:
|
||||
mask = sv.phs + leafnum * 4*((sv.worldmodel->numleafs+31)>>5);
|
||||
break;
|
||||
|
||||
case MULTICAST_PVS_R:
|
||||
reliable = true; // intentional fallthrough
|
||||
case MULTICAST_PVS:
|
||||
mask = sv.pvs + leafnum * 4*((sv.worldmodel->numleafs+31)>>5);
|
||||
break;
|
||||
|
||||
default:
|
||||
mask = NULL;
|
||||
SV_Error ("SV_Multicast: bad to:%i", to);
|
||||
}
|
||||
|
||||
// send the data to all relevent clients
|
||||
for (j = 0, client = svs.clients; j < MAX_CLIENTS; j++, client++)
|
||||
{
|
||||
if (client->state != cs_spawned)
|
||||
continue;
|
||||
|
||||
if (to == MULTICAST_PHS_R || to == MULTICAST_PHS) {
|
||||
vec3_t delta;
|
||||
VectorSubtract(origin, client->edict->v.origin, delta);
|
||||
if (Length(delta) <= 1024)
|
||||
goto inrange;
|
||||
}
|
||||
|
||||
leaf = Mod_PointInLeaf (client->edict->v.origin, sv.worldmodel);
|
||||
if (leaf)
|
||||
{
|
||||
// -1 is because pvs rows are 1 based, not 0 based like leafs
|
||||
leafnum = leaf - sv.worldmodel->leafs - 1;
|
||||
if ( !(mask[leafnum>>3] & (1<<(leafnum&7)) ) )
|
||||
{
|
||||
// Con_Printf ("supressed multicast\n");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
inrange:
|
||||
if (reliable) {
|
||||
ClientReliableCheckBlock(client, sv.multicast.cursize);
|
||||
ClientReliableWrite_SZ(client, sv.multicast.data, sv.multicast.cursize);
|
||||
} else
|
||||
SZ_Write (&client->datagram, sv.multicast.data, sv.multicast.cursize);
|
||||
}
|
||||
|
||||
SZ_Clear (&sv.multicast);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
==================
|
||||
SV_StartSound
|
||||
|
||||
Each entity can have eight independant sound sources, like voice,
|
||||
weapon, feet, etc.
|
||||
|
||||
Channel 0 is an auto-allocate channel, the others override anything
|
||||
allready running on that entity/channel pair.
|
||||
|
||||
An attenuation of 0 will play full volume everywhere in the level.
|
||||
Larger attenuations will drop off. (max 4 attenuation)
|
||||
|
||||
==================
|
||||
*/
|
||||
void SV_StartSound (edict_t *entity, int channel, char *sample, int volume,
|
||||
float attenuation)
|
||||
{
|
||||
int sound_num;
|
||||
int field_mask;
|
||||
int i;
|
||||
int ent;
|
||||
vec3_t origin;
|
||||
qboolean use_phs;
|
||||
qboolean reliable = false;
|
||||
|
||||
if (volume < 0 || volume > 255)
|
||||
SV_Error ("SV_StartSound: volume = %i", volume);
|
||||
|
||||
if (attenuation < 0 || attenuation > 4)
|
||||
SV_Error ("SV_StartSound: attenuation = %f", attenuation);
|
||||
|
||||
if (channel < 0 || channel > 15)
|
||||
SV_Error ("SV_StartSound: channel = %i", channel);
|
||||
|
||||
// find precache number for sound
|
||||
for (sound_num=1 ; sound_num<MAX_SOUNDS
|
||||
&& sv.sound_precache[sound_num] ; sound_num++)
|
||||
if (!strcmp(sample, sv.sound_precache[sound_num]))
|
||||
break;
|
||||
|
||||
if ( sound_num == MAX_SOUNDS || !sv.sound_precache[sound_num] )
|
||||
{
|
||||
Con_Printf ("SV_StartSound: %s not precacheed\n", sample);
|
||||
return;
|
||||
}
|
||||
|
||||
ent = NUM_FOR_EDICT(entity);
|
||||
|
||||
if ((channel & 8) || !sv_phs.value) // no PHS flag
|
||||
{
|
||||
if (channel & 8)
|
||||
reliable = true; // sounds that break the phs are reliable
|
||||
use_phs = false;
|
||||
channel &= 7;
|
||||
}
|
||||
else
|
||||
use_phs = true;
|
||||
|
||||
// if (channel == CHAN_BODY || channel == CHAN_VOICE)
|
||||
// reliable = true;
|
||||
|
||||
channel = (ent<<3) | channel;
|
||||
|
||||
field_mask = 0;
|
||||
if (volume != DEFAULT_SOUND_PACKET_VOLUME)
|
||||
channel |= SND_VOLUME;
|
||||
if (attenuation != DEFAULT_SOUND_PACKET_ATTENUATION)
|
||||
channel |= SND_ATTENUATION;
|
||||
|
||||
// use the entity origin unless it is a bmodel
|
||||
if (entity->v.solid == SOLID_BSP)
|
||||
{
|
||||
for (i=0 ; i<3 ; i++)
|
||||
origin[i] = entity->v.origin[i]+0.5*(entity->v.mins[i]+entity->v.maxs[i]);
|
||||
}
|
||||
else
|
||||
{
|
||||
VectorCopy (entity->v.origin, origin);
|
||||
}
|
||||
|
||||
MSG_WriteByte (&sv.multicast, svc_sound);
|
||||
MSG_WriteShort (&sv.multicast, channel);
|
||||
if (channel & SND_VOLUME)
|
||||
MSG_WriteByte (&sv.multicast, volume);
|
||||
if (channel & SND_ATTENUATION)
|
||||
MSG_WriteByte (&sv.multicast, attenuation*64);
|
||||
MSG_WriteByte (&sv.multicast, sound_num);
|
||||
for (i=0 ; i<3 ; i++)
|
||||
MSG_WriteCoord (&sv.multicast, origin[i]);
|
||||
|
||||
if (use_phs)
|
||||
SV_Multicast (origin, reliable ? MULTICAST_PHS_R : MULTICAST_PHS);
|
||||
else
|
||||
SV_Multicast (origin, reliable ? MULTICAST_ALL_R : MULTICAST_ALL);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
===============================================================================
|
||||
|
||||
FRAME UPDATES
|
||||
|
||||
===============================================================================
|
||||
*/
|
||||
|
||||
int sv_nailmodel, sv_supernailmodel, sv_playermodel;
|
||||
|
||||
void SV_FindModelNumbers (void)
|
||||
{
|
||||
int i;
|
||||
|
||||
sv_nailmodel = -1;
|
||||
sv_supernailmodel = -1;
|
||||
sv_playermodel = -1;
|
||||
|
||||
for (i=0 ; i<MAX_MODELS ; i++)
|
||||
{
|
||||
if (!sv.model_precache[i])
|
||||
break;
|
||||
if (!strcmp(sv.model_precache[i],"progs/spike.mdl"))
|
||||
sv_nailmodel = i;
|
||||
if (!strcmp(sv.model_precache[i],"progs/s_spike.mdl"))
|
||||
sv_supernailmodel = i;
|
||||
if (!strcmp(sv.model_precache[i],"progs/player.mdl"))
|
||||
sv_playermodel = i;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
==================
|
||||
SV_WriteClientdataToMessage
|
||||
|
||||
==================
|
||||
*/
|
||||
void SV_WriteClientdataToMessage (client_t *client, sizebuf_t *msg)
|
||||
{
|
||||
int i;
|
||||
edict_t *other;
|
||||
edict_t *ent;
|
||||
|
||||
ent = client->edict;
|
||||
|
||||
// send the chokecount for r_netgraph
|
||||
if (client->chokecount)
|
||||
{
|
||||
MSG_WriteByte (msg, svc_chokecount);
|
||||
MSG_WriteByte (msg, client->chokecount);
|
||||
client->chokecount = 0;
|
||||
}
|
||||
|
||||
// send a damage message if the player got hit this frame
|
||||
if (ent->v.dmg_take || ent->v.dmg_save)
|
||||
{
|
||||
other = PROG_TO_EDICT(ent->v.dmg_inflictor);
|
||||
MSG_WriteByte (msg, svc_damage);
|
||||
MSG_WriteByte (msg, ent->v.dmg_save);
|
||||
MSG_WriteByte (msg, ent->v.dmg_take);
|
||||
for (i=0 ; i<3 ; i++)
|
||||
MSG_WriteCoord (msg, other->v.origin[i] + 0.5*(other->v.mins[i] + other->v.maxs[i]));
|
||||
|
||||
ent->v.dmg_take = 0;
|
||||
ent->v.dmg_save = 0;
|
||||
}
|
||||
|
||||
// a fixangle might get lost in a dropped packet. Oh well.
|
||||
if ( ent->v.fixangle )
|
||||
{
|
||||
MSG_WriteByte (msg, svc_setangle);
|
||||
for (i=0 ; i < 3 ; i++)
|
||||
MSG_WriteAngle (msg, ent->v.angles[i] );
|
||||
ent->v.fixangle = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
=======================
|
||||
SV_UpdateClientStats
|
||||
|
||||
Performs a delta update of the stats array. This should only be performed
|
||||
when a reliable message can be delivered this frame.
|
||||
=======================
|
||||
*/
|
||||
void SV_UpdateClientStats (client_t *client)
|
||||
{
|
||||
edict_t *ent;
|
||||
int stats[MAX_CL_STATS];
|
||||
int i;
|
||||
|
||||
ent = client->edict;
|
||||
memset (stats, 0, sizeof(stats));
|
||||
|
||||
// if we are a spectator and we are tracking a player, we get his stats
|
||||
// so our status bar reflects his
|
||||
if (client->spectator && client->spec_track > 0)
|
||||
ent = svs.clients[client->spec_track - 1].edict;
|
||||
|
||||
stats[STAT_HEALTH] = ent->v.health;
|
||||
stats[STAT_WEAPON] = SV_ModelIndex(PR_GetString(ent->v.weaponmodel));
|
||||
stats[STAT_AMMO] = ent->v.currentammo;
|
||||
stats[STAT_ARMOR] = ent->v.armorvalue;
|
||||
stats[STAT_SHELLS] = ent->v.ammo_shells;
|
||||
stats[STAT_NAILS] = ent->v.ammo_nails;
|
||||
stats[STAT_ROCKETS] = ent->v.ammo_rockets;
|
||||
stats[STAT_CELLS] = ent->v.ammo_cells;
|
||||
if (!client->spectator)
|
||||
stats[STAT_ACTIVEWEAPON] = ent->v.weapon;
|
||||
// stuff the sigil bits into the high bits of items for sbar
|
||||
stats[STAT_ITEMS] = (int)ent->v.items | ((int)pr_global_struct->serverflags << 28);
|
||||
|
||||
for (i=0 ; i<MAX_CL_STATS ; i++)
|
||||
if (stats[i] != client->stats[i])
|
||||
{
|
||||
client->stats[i] = stats[i];
|
||||
if (stats[i] >=0 && stats[i] <= 255)
|
||||
{
|
||||
ClientReliableWrite_Begin(client, svc_updatestat, 3);
|
||||
ClientReliableWrite_Byte(client, i);
|
||||
ClientReliableWrite_Byte(client, stats[i]);
|
||||
}
|
||||
else
|
||||
{
|
||||
ClientReliableWrite_Begin(client, svc_updatestatlong, 6);
|
||||
ClientReliableWrite_Byte(client, i);
|
||||
ClientReliableWrite_Long(client, stats[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
=======================
|
||||
SV_SendClientDatagram
|
||||
=======================
|
||||
*/
|
||||
qboolean SV_SendClientDatagram (client_t *client)
|
||||
{
|
||||
byte buf[MAX_DATAGRAM];
|
||||
sizebuf_t msg;
|
||||
|
||||
msg.data = buf;
|
||||
msg.maxsize = sizeof(buf);
|
||||
msg.cursize = 0;
|
||||
msg.allowoverflow = true;
|
||||
msg.overflowed = false;
|
||||
|
||||
// add the client specific data to the datagram
|
||||
SV_WriteClientdataToMessage (client, &msg);
|
||||
|
||||
// send over all the objects that are in the PVS
|
||||
// this will include clients, a packetentities, and
|
||||
// possibly a nails update
|
||||
SV_WriteEntitiesToClient (client, &msg);
|
||||
|
||||
// copy the accumulated multicast datagram
|
||||
// for this client out to the message
|
||||
if (client->datagram.overflowed)
|
||||
Con_Printf ("WARNING: datagram overflowed for %s\n", client->name);
|
||||
else
|
||||
SZ_Write (&msg, client->datagram.data, client->datagram.cursize);
|
||||
SZ_Clear (&client->datagram);
|
||||
|
||||
// send deltas over reliable stream
|
||||
if (Netchan_CanReliable (&client->netchan))
|
||||
SV_UpdateClientStats (client);
|
||||
|
||||
if (msg.overflowed)
|
||||
{
|
||||
Con_Printf ("WARNING: msg overflowed for %s\n", client->name);
|
||||
SZ_Clear (&msg);
|
||||
}
|
||||
|
||||
// send the datagram
|
||||
Netchan_Transmit (&client->netchan, msg.cursize, buf);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
=======================
|
||||
SV_UpdateToReliableMessages
|
||||
=======================
|
||||
*/
|
||||
void SV_UpdateToReliableMessages (void)
|
||||
{
|
||||
int i, j;
|
||||
client_t *client;
|
||||
eval_t *val;
|
||||
edict_t *ent;
|
||||
|
||||
// check for changes to be sent over the reliable streams to all clients
|
||||
for (i=0, host_client = svs.clients ; i<MAX_CLIENTS ; i++, host_client++)
|
||||
{
|
||||
if (host_client->state != cs_spawned)
|
||||
continue;
|
||||
if (host_client->sendinfo)
|
||||
{
|
||||
host_client->sendinfo = false;
|
||||
SV_FullClientUpdate (host_client, &sv.reliable_datagram);
|
||||
}
|
||||
if (host_client->old_frags != host_client->edict->v.frags)
|
||||
{
|
||||
for (j=0, client = svs.clients ; j<MAX_CLIENTS ; j++, client++)
|
||||
{
|
||||
if (client->state < cs_connected)
|
||||
continue;
|
||||
ClientReliableWrite_Begin(client, svc_updatefrags, 4);
|
||||
ClientReliableWrite_Byte(client, i);
|
||||
ClientReliableWrite_Short(client, host_client->edict->v.frags);
|
||||
}
|
||||
|
||||
host_client->old_frags = host_client->edict->v.frags;
|
||||
}
|
||||
|
||||
// maxspeed/entgravity changes
|
||||
ent = host_client->edict;
|
||||
|
||||
val = GetEdictFieldValue(ent, "gravity");
|
||||
if (val && host_client->entgravity != val->_float) {
|
||||
host_client->entgravity = val->_float;
|
||||
ClientReliableWrite_Begin(host_client, svc_entgravity, 5);
|
||||
ClientReliableWrite_Float(host_client, host_client->entgravity);
|
||||
}
|
||||
val = GetEdictFieldValue(ent, "maxspeed");
|
||||
if (val && host_client->maxspeed != val->_float) {
|
||||
host_client->maxspeed = val->_float;
|
||||
ClientReliableWrite_Begin(host_client, svc_maxspeed, 5);
|
||||
ClientReliableWrite_Float(host_client, host_client->maxspeed);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (sv.datagram.overflowed)
|
||||
SZ_Clear (&sv.datagram);
|
||||
|
||||
// append the broadcast messages to each client messages
|
||||
for (j=0, client = svs.clients ; j<MAX_CLIENTS ; j++, client++)
|
||||
{
|
||||
if (client->state < cs_connected)
|
||||
continue; // reliables go to all connected or spawned
|
||||
|
||||
ClientReliableCheckBlock(client, sv.reliable_datagram.cursize);
|
||||
ClientReliableWrite_SZ(client, sv.reliable_datagram.data, sv.reliable_datagram.cursize);
|
||||
|
||||
if (client->state != cs_spawned)
|
||||
continue; // datagrams only go to spawned
|
||||
SZ_Write (&client->datagram
|
||||
, sv.datagram.data
|
||||
, sv.datagram.cursize);
|
||||
}
|
||||
|
||||
SZ_Clear (&sv.reliable_datagram);
|
||||
SZ_Clear (&sv.datagram);
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
#pragma optimize( "", off )
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/*
|
||||
=======================
|
||||
SV_SendClientMessages
|
||||
=======================
|
||||
*/
|
||||
void SV_SendClientMessages (void)
|
||||
{
|
||||
int i, j;
|
||||
client_t *c;
|
||||
|
||||
// update frags, names, etc
|
||||
SV_UpdateToReliableMessages ();
|
||||
|
||||
// build individual updates
|
||||
for (i=0, c = svs.clients ; i<MAX_CLIENTS ; i++, c++)
|
||||
{
|
||||
if (!c->state)
|
||||
continue;
|
||||
|
||||
if (c->drop) {
|
||||
SV_DropClient(c);
|
||||
c->drop = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
// check to see if we have a backbuf to stick in the reliable
|
||||
if (c->num_backbuf) {
|
||||
// will it fit?
|
||||
if (c->netchan.message.cursize + c->backbuf_size[0] <
|
||||
c->netchan.message.maxsize) {
|
||||
|
||||
Con_DPrintf("%s: backbuf %d bytes\n",
|
||||
c->name, c->backbuf_size[0]);
|
||||
|
||||
// it'll fit
|
||||
SZ_Write(&c->netchan.message, c->backbuf_data[0],
|
||||
c->backbuf_size[0]);
|
||||
|
||||
//move along, move along
|
||||
for (j = 1; j < c->num_backbuf; j++) {
|
||||
memcpy(c->backbuf_data[j - 1], c->backbuf_data[j],
|
||||
c->backbuf_size[j]);
|
||||
c->backbuf_size[j - 1] = c->backbuf_size[j];
|
||||
}
|
||||
|
||||
c->num_backbuf--;
|
||||
if (c->num_backbuf) {
|
||||
memset(&c->backbuf, 0, sizeof(c->backbuf));
|
||||
c->backbuf.data = c->backbuf_data[c->num_backbuf - 1];
|
||||
c->backbuf.cursize = c->backbuf_size[c->num_backbuf - 1];
|
||||
c->backbuf.maxsize = sizeof(c->backbuf_data[c->num_backbuf - 1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// if the reliable message overflowed,
|
||||
// drop the client
|
||||
if (c->netchan.message.overflowed)
|
||||
{
|
||||
SZ_Clear (&c->netchan.message);
|
||||
SZ_Clear (&c->datagram);
|
||||
SV_BroadcastPrintf (PRINT_HIGH, "%s overflowed\n", c->name);
|
||||
Con_Printf ("WARNING: reliable overflow for %s\n",c->name);
|
||||
SV_DropClient (c);
|
||||
c->send_message = true;
|
||||
c->netchan.cleartime = 0; // don't choke this message
|
||||
}
|
||||
|
||||
// only send messages if the client has sent one
|
||||
// and the bandwidth is not choked
|
||||
if (!c->send_message)
|
||||
continue;
|
||||
c->send_message = false; // try putting this after choke?
|
||||
if (!sv.paused && !Netchan_CanPacket (&c->netchan))
|
||||
{
|
||||
c->chokecount++;
|
||||
continue; // bandwidth choke
|
||||
}
|
||||
|
||||
if (c->state == cs_spawned)
|
||||
SV_SendClientDatagram (c);
|
||||
else
|
||||
Netchan_Transmit (&c->netchan, 0, NULL); // just update reliable
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
#pragma optimize( "", on )
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/*
|
||||
=======================
|
||||
SV_SendMessagesToAll
|
||||
|
||||
FIXME: does this sequence right?
|
||||
=======================
|
||||
*/
|
||||
void SV_SendMessagesToAll (void)
|
||||
{
|
||||
int i;
|
||||
client_t *c;
|
||||
|
||||
for (i=0, c = svs.clients ; i<MAX_CLIENTS ; i++, c++)
|
||||
if (c->state) // FIXME: should this only send to active?
|
||||
c->send_message = true;
|
||||
|
||||
SV_SendClientMessages ();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user