2004-08-23 00:15:46 +00:00
|
|
|
/*
|
|
|
|
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
|
2005-10-23 17:57:20 +00:00
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
2004-08-23 00:15:46 +00:00
|
|
|
|
|
|
|
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
|
|
|
|
|
2013-03-31 04:21:08 +00:00
|
|
|
#include "quakedef.h"
|
2004-08-23 00:15:46 +00:00
|
|
|
|
2004-11-29 01:21:00 +00:00
|
|
|
#ifndef CLIENTONLY
|
|
|
|
|
2004-08-23 00:15:46 +00:00
|
|
|
#define CHAN_AUTO 0
|
|
|
|
#define CHAN_WEAPON 1
|
|
|
|
#define CHAN_VOICE 2
|
|
|
|
#define CHAN_ITEM 3
|
|
|
|
#define CHAN_BODY 4
|
|
|
|
|
2007-06-10 05:14:38 +00:00
|
|
|
extern cvar_t sv_gravity, sv_friction, sv_waterfriction, sv_gamespeed, sv_stopspeed, sv_spectatormaxspeed, sv_accelerate, sv_airaccelerate, sv_wateraccelerate, sv_edgefriction;
|
2012-11-27 03:23:19 +00:00
|
|
|
extern cvar_t dpcompat_stats;
|
2007-06-10 05:14:38 +00:00
|
|
|
|
2004-08-23 00:15:46 +00:00
|
|
|
/*
|
|
|
|
=============================================================================
|
|
|
|
|
|
|
|
Con_Printf redirection
|
|
|
|
|
|
|
|
=============================================================================
|
|
|
|
*/
|
|
|
|
|
|
|
|
char outputbuf[8000];
|
|
|
|
|
|
|
|
redirect_t sv_redirected;
|
2005-01-16 00:59:48 +00:00
|
|
|
int sv_redirectedlang;
|
2004-08-23 00:15:46 +00:00
|
|
|
|
|
|
|
extern cvar_t sv_phs;
|
|
|
|
|
|
|
|
/*
|
|
|
|
==================
|
|
|
|
SV_FlushRedirect
|
|
|
|
==================
|
|
|
|
*/
|
|
|
|
void SV_FlushRedirect (void)
|
|
|
|
{
|
|
|
|
int totallen;
|
|
|
|
char send[8000+6];
|
|
|
|
|
|
|
|
if (!*outputbuf)
|
|
|
|
return;
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
2013-05-03 04:28:08 +00:00
|
|
|
NET_SendPacket (NS_SERVER, strlen(send)+1, send, &net_from);
|
2004-08-23 00:15:46 +00:00
|
|
|
}
|
|
|
|
else if (sv_redirected == RD_CLIENT)
|
|
|
|
{
|
|
|
|
int chop;
|
|
|
|
char spare;
|
|
|
|
char *s = outputbuf;
|
|
|
|
totallen = strlen(s)+3;
|
|
|
|
while (sizeof(host_client->backbuf_data[0])/2 < totallen)
|
|
|
|
{
|
|
|
|
chop = sizeof(host_client->backbuf_data[0]) / 2;
|
|
|
|
spare = s[chop];
|
|
|
|
s[chop] = '\0';
|
|
|
|
|
2005-05-26 12:55:34 +00:00
|
|
|
ClientReliableWrite_Begin (host_client, host_client->protocol==SCP_QUAKE2?svcq2_print:svc_print, chop+3);
|
2004-08-23 00:15:46 +00:00
|
|
|
ClientReliableWrite_Byte (host_client, PRINT_HIGH);
|
|
|
|
ClientReliableWrite_String (host_client, s);
|
|
|
|
|
|
|
|
s += chop;
|
|
|
|
totallen -= chop;
|
|
|
|
s[0] = spare;
|
|
|
|
}
|
2005-05-26 12:55:34 +00:00
|
|
|
ClientReliableWrite_Begin (host_client, host_client->protocol==SCP_QUAKE2?svcq2_print:svc_print, strlen(s)+3);
|
2004-08-23 00:15:46 +00:00
|
|
|
ClientReliableWrite_Byte (host_client, PRINT_HIGH);
|
|
|
|
ClientReliableWrite_String (host_client, s);
|
|
|
|
}
|
|
|
|
|
|
|
|
// clear it
|
|
|
|
outputbuf[0] = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
==================
|
|
|
|
SV_BeginRedirect
|
|
|
|
|
|
|
|
Send Con_Printf data to the remote client
|
|
|
|
instead of the console
|
|
|
|
==================
|
|
|
|
*/
|
2005-01-16 00:59:48 +00:00
|
|
|
void SV_BeginRedirect (redirect_t rd, int lang)
|
2004-08-23 00:15:46 +00:00
|
|
|
{
|
|
|
|
sv_redirected = rd;
|
2005-01-16 00:59:48 +00:00
|
|
|
sv_redirectedlang = lang;
|
2004-08-23 00:15:46 +00:00
|
|
|
outputbuf[0] = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void SV_EndRedirect (void)
|
|
|
|
{
|
|
|
|
SV_FlushRedirect ();
|
2005-01-16 00:59:48 +00:00
|
|
|
sv_redirectedlang = 0; //clenliness rather than functionality. Shouldn't be needed.
|
2004-08-23 00:15:46 +00:00
|
|
|
sv_redirected = RD_NONE;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
================
|
|
|
|
Con_Printf
|
|
|
|
|
|
|
|
Handles cursor positioning, line wrapping, etc
|
|
|
|
================
|
|
|
|
*/
|
|
|
|
#define MAXPRINTMSG 4096
|
|
|
|
// FIXME: make a buffer size safe vsprintf?
|
|
|
|
#ifdef SERVERONLY
|
2004-08-27 00:44:39 +00:00
|
|
|
void VARGS Con_Printf (const char *fmt, ...)
|
2004-08-23 00:15:46 +00:00
|
|
|
{
|
|
|
|
va_list argptr;
|
|
|
|
char msg[MAXPRINTMSG];
|
|
|
|
|
|
|
|
va_start (argptr,fmt);
|
2006-03-11 04:39:16 +00:00
|
|
|
vsnprintf (msg,sizeof(msg)-1, fmt,argptr);
|
2004-08-23 00:15:46 +00:00
|
|
|
va_end (argptr);
|
2005-10-23 17:57:20 +00:00
|
|
|
|
2004-08-23 00:15:46 +00:00
|
|
|
// add to redirected message
|
|
|
|
if (sv_redirected)
|
|
|
|
{
|
|
|
|
if (strlen (msg) + strlen(outputbuf) > sizeof(outputbuf) - 1)
|
|
|
|
SV_FlushRedirect ();
|
|
|
|
strcat (outputbuf, msg);
|
|
|
|
if (sv_redirected != -1)
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
Sys_Printf ("%s", msg); // also echo to debugging console
|
2005-09-26 08:07:26 +00:00
|
|
|
Con_Log(msg); // log to console
|
2004-08-23 00:15:46 +00:00
|
|
|
}
|
|
|
|
void Con_TPrintf (translation_t stringnum, ...)
|
|
|
|
{
|
|
|
|
va_list argptr;
|
|
|
|
char msg[MAXPRINTMSG];
|
|
|
|
char *fmt;
|
|
|
|
|
|
|
|
// add to redirected message
|
|
|
|
if (sv_redirected)
|
|
|
|
{
|
2005-01-16 00:59:48 +00:00
|
|
|
fmt = languagetext[stringnum][sv_redirectedlang];
|
2004-08-23 00:15:46 +00:00
|
|
|
va_start (argptr,stringnum);
|
2006-03-11 04:39:16 +00:00
|
|
|
vsnprintf (msg,sizeof(msg)-1, fmt,argptr);
|
2004-08-23 00:15:46 +00:00
|
|
|
va_end (argptr);
|
2005-10-23 17:57:20 +00:00
|
|
|
|
2004-08-23 00:15:46 +00:00
|
|
|
if (strlen (msg) + strlen(outputbuf) > sizeof(outputbuf) - 1)
|
|
|
|
SV_FlushRedirect ();
|
|
|
|
strcat (outputbuf, msg);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
fmt = languagetext[stringnum][svs.language];
|
|
|
|
|
|
|
|
va_start (argptr,stringnum);
|
2006-03-11 04:39:16 +00:00
|
|
|
vsnprintf (msg,sizeof(msg)-1, fmt,argptr);
|
2004-08-23 00:15:46 +00:00
|
|
|
va_end (argptr);
|
|
|
|
|
|
|
|
Sys_Printf ("%s", msg); // also echo to debugging console
|
2005-09-26 08:07:26 +00:00
|
|
|
Con_Log(msg); // log to console
|
2004-08-23 00:15:46 +00:00
|
|
|
}
|
|
|
|
/*
|
|
|
|
================
|
|
|
|
Con_DPrintf
|
|
|
|
|
|
|
|
A Con_Printf that only shows up if the "developer" cvar is set
|
|
|
|
================
|
|
|
|
*/
|
2013-05-04 04:03:12 +00:00
|
|
|
void Con_DPrintf (const char *fmt, ...)
|
2004-08-23 00:15:46 +00:00
|
|
|
{
|
|
|
|
va_list argptr;
|
|
|
|
char msg[MAXPRINTMSG];
|
2005-09-27 04:05:32 +00:00
|
|
|
extern cvar_t log_developer;
|
2004-08-23 00:15:46 +00:00
|
|
|
|
2005-09-27 04:05:32 +00:00
|
|
|
if (!developer.value && !log_developer.value)
|
2004-08-23 00:15:46 +00:00
|
|
|
return;
|
|
|
|
|
|
|
|
va_start (argptr,fmt);
|
2006-03-11 04:39:16 +00:00
|
|
|
vsnprintf (msg,sizeof(msg)-1, fmt,argptr);
|
2004-08-23 00:15:46 +00:00
|
|
|
va_end (argptr);
|
2005-10-23 17:57:20 +00:00
|
|
|
|
2005-09-27 04:05:32 +00:00
|
|
|
// add to redirected message
|
|
|
|
if (sv_redirected)
|
|
|
|
{
|
|
|
|
if (strlen (msg) + strlen(outputbuf) > sizeof(outputbuf) - 1)
|
|
|
|
SV_FlushRedirect ();
|
|
|
|
strcat (outputbuf, msg);
|
|
|
|
if (sv_redirected != -1)
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (developer.value)
|
|
|
|
Sys_Printf ("%s", msg); // also echo to debugging console
|
|
|
|
|
|
|
|
if (log_developer.value)
|
|
|
|
Con_Log(msg); // log to console
|
2004-08-23 00:15:46 +00:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/*
|
|
|
|
=============================================================================
|
|
|
|
|
|
|
|
EVENT MESSAGES
|
|
|
|
|
|
|
|
=============================================================================
|
|
|
|
*/
|
|
|
|
|
2007-06-10 21:33:24 +00:00
|
|
|
void SV_PrintToClient(client_t *cl, int level, char *string)
|
2004-08-23 00:15:46 +00:00
|
|
|
{
|
2005-06-14 04:52:10 +00:00
|
|
|
switch (cl->protocol)
|
2004-08-23 00:15:46 +00:00
|
|
|
{
|
2005-06-14 04:52:10 +00:00
|
|
|
case SCP_BAD: //bot
|
|
|
|
break;
|
|
|
|
case SCP_QUAKE2:
|
2007-08-07 19:16:32 +00:00
|
|
|
#ifdef Q2SERVER
|
2005-06-14 04:52:10 +00:00
|
|
|
ClientReliableWrite_Begin (cl, svcq2_print, strlen(string)+3);
|
|
|
|
ClientReliableWrite_Byte (cl, level);
|
|
|
|
ClientReliableWrite_String (cl, string);
|
|
|
|
#endif
|
2007-08-07 19:16:32 +00:00
|
|
|
break;
|
|
|
|
case SCP_QUAKE3:
|
|
|
|
break;
|
|
|
|
case SCP_QUAKEWORLD:
|
|
|
|
ClientReliableWrite_Begin (cl, svc_print, strlen(string)+3);
|
|
|
|
ClientReliableWrite_Byte (cl, level);
|
|
|
|
ClientReliableWrite_String (cl, string);
|
|
|
|
break;
|
2005-06-14 04:52:10 +00:00
|
|
|
case SCP_DARKPLACES6:
|
|
|
|
case SCP_DARKPLACES7:
|
2007-08-07 19:16:32 +00:00
|
|
|
case SCP_NETQUAKE:
|
2012-10-01 14:29:44 +00:00
|
|
|
case SCP_PROQUAKE:
|
2011-10-27 16:16:29 +00:00
|
|
|
case SCP_FITZ666:
|
2007-08-07 19:16:32 +00:00
|
|
|
#ifdef NQPROT
|
2005-06-14 04:52:10 +00:00
|
|
|
ClientReliableWrite_Begin (cl, svc_print, strlen(string)+3);
|
2004-08-23 00:15:46 +00:00
|
|
|
if (level == PRINT_CHAT)
|
|
|
|
ClientReliableWrite_Byte (cl, 1);
|
2005-06-14 04:52:10 +00:00
|
|
|
ClientReliableWrite_String (cl, string);
|
2004-08-23 00:15:46 +00:00
|
|
|
#endif
|
2005-06-14 04:52:10 +00:00
|
|
|
break;
|
|
|
|
}
|
2004-08-23 00:15:46 +00:00
|
|
|
}
|
|
|
|
|
2011-12-05 15:23:40 +00:00
|
|
|
void SV_StuffcmdToClient(client_t *cl, char *string)
|
|
|
|
{
|
|
|
|
switch (cl->protocol)
|
|
|
|
{
|
|
|
|
case SCP_BAD: //bot
|
|
|
|
break;
|
|
|
|
case SCP_QUAKE2:
|
|
|
|
#ifdef Q2SERVER
|
|
|
|
ClientReliableWrite_Begin (cl, svcq2_stufftext, strlen(string)+3);
|
|
|
|
ClientReliableWrite_String (cl, string);
|
|
|
|
#endif
|
|
|
|
break;
|
|
|
|
case SCP_QUAKE3:
|
|
|
|
break;
|
|
|
|
case SCP_QUAKEWORLD:
|
|
|
|
case SCP_DARKPLACES6:
|
|
|
|
case SCP_DARKPLACES7:
|
|
|
|
case SCP_NETQUAKE:
|
2012-10-01 14:29:44 +00:00
|
|
|
case SCP_PROQUAKE:
|
2011-12-05 15:23:40 +00:00
|
|
|
case SCP_FITZ666:
|
|
|
|
ClientReliableWrite_Begin (cl, svc_stufftext, strlen(string)+3);
|
|
|
|
ClientReliableWrite_String (cl, string);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-08-23 00:15:46 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
=================
|
|
|
|
SV_ClientPrintf
|
|
|
|
|
|
|
|
Sends text across to be displayed if the level passes
|
|
|
|
=================
|
|
|
|
*/
|
|
|
|
void VARGS SV_ClientPrintf (client_t *cl, int level, char *fmt, ...)
|
|
|
|
{
|
|
|
|
va_list argptr;
|
|
|
|
char string[1024];
|
2005-10-23 17:57:20 +00:00
|
|
|
|
2004-08-23 00:15:46 +00:00
|
|
|
if (level < cl->messagelevel)
|
|
|
|
return;
|
2005-10-23 17:57:20 +00:00
|
|
|
|
2004-08-23 00:15:46 +00:00
|
|
|
va_start (argptr,fmt);
|
2006-03-06 01:41:09 +00:00
|
|
|
vsnprintf (string,sizeof(string)-1, fmt,argptr);
|
2004-08-23 00:15:46 +00:00
|
|
|
va_end (argptr);
|
|
|
|
|
|
|
|
if(strlen(string) >= sizeof(string))
|
|
|
|
Sys_Error("SV_ClientPrintf: Buffer stomped\n");
|
|
|
|
|
|
|
|
if (sv.mvdrecording)
|
|
|
|
{
|
2012-08-04 01:35:52 +00:00
|
|
|
sizebuf_t *msg = MVDWrite_Begin (dem_single, cl - svs.clients, strlen(string)+3);
|
|
|
|
MSG_WriteByte (msg, svc_print);
|
|
|
|
MSG_WriteByte (msg, level);
|
|
|
|
MSG_WriteString (msg, string);
|
2004-08-23 00:15:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (cl->controller)
|
|
|
|
SV_PrintToClient(cl->controller, level, string);
|
|
|
|
else
|
|
|
|
SV_PrintToClient(cl, level, string);
|
|
|
|
}
|
|
|
|
|
|
|
|
void VARGS SV_ClientTPrintf (client_t *cl, int level, translation_t stringnum, ...)
|
|
|
|
{
|
|
|
|
va_list argptr;
|
|
|
|
char string[1024];
|
|
|
|
char *fmt = languagetext[stringnum][cl->language];
|
2005-10-23 17:57:20 +00:00
|
|
|
|
2004-08-23 00:15:46 +00:00
|
|
|
if (level < cl->messagelevel)
|
|
|
|
return;
|
2005-10-23 17:57:20 +00:00
|
|
|
|
2004-08-23 00:15:46 +00:00
|
|
|
va_start (argptr,stringnum);
|
2006-03-06 01:41:09 +00:00
|
|
|
vsnprintf (string,sizeof(string)-1, fmt,argptr);
|
2004-08-23 00:15:46 +00:00
|
|
|
va_end (argptr);
|
|
|
|
|
|
|
|
if(strlen(string) >= sizeof(string))
|
|
|
|
Sys_Error("SV_ClientTPrintf: Buffer stomped\n");
|
|
|
|
|
|
|
|
if (sv.mvdrecording)
|
|
|
|
{
|
2012-08-04 01:35:52 +00:00
|
|
|
sizebuf_t *msg = MVDWrite_Begin (dem_single, cl - svs.clients, strlen(string)+3);
|
|
|
|
MSG_WriteByte (msg, svc_print);
|
|
|
|
MSG_WriteByte (msg, level);
|
|
|
|
MSG_WriteString (msg, string);
|
2004-08-23 00:15:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
SV_PrintToClient(cl, level, string);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
=================
|
|
|
|
SV_BroadcastPrintf
|
|
|
|
|
|
|
|
Sends text to all active clients
|
|
|
|
=================
|
|
|
|
*/
|
|
|
|
void VARGS SV_BroadcastPrintf (int level, char *fmt, ...)
|
|
|
|
{
|
|
|
|
va_list argptr;
|
|
|
|
char string[1024];
|
|
|
|
client_t *cl;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
va_start (argptr,fmt);
|
2006-03-06 01:41:09 +00:00
|
|
|
vsnprintf (string,sizeof(string)-1, fmt,argptr);
|
2004-08-23 00:15:46 +00:00
|
|
|
va_end (argptr);
|
|
|
|
|
|
|
|
if(strlen(string) >= sizeof(string))
|
|
|
|
Sys_Error("SV_BroadcastPrintf: Buffer stomped\n");
|
|
|
|
|
|
|
|
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;
|
2005-06-14 04:52:10 +00:00
|
|
|
if (cl->protocol == SCP_BAD)
|
|
|
|
continue;
|
2004-08-23 00:15:46 +00:00
|
|
|
|
|
|
|
if (cl->controller)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
SV_PrintToClient(cl, level, string);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sv.mvdrecording)
|
|
|
|
{
|
2012-08-04 01:35:52 +00:00
|
|
|
sizebuf_t *msg = MVDWrite_Begin (dem_all, 0, strlen(string)+3);
|
|
|
|
MSG_WriteByte (msg, svc_print);
|
|
|
|
MSG_WriteByte (msg, level);
|
|
|
|
MSG_WriteString (msg, string);
|
2004-08-23 00:15:46 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void VARGS SV_BroadcastTPrintf (int level, translation_t stringnum, ...)
|
|
|
|
{
|
|
|
|
va_list argptr;
|
|
|
|
char string[1024];
|
|
|
|
client_t *cl;
|
|
|
|
int i;
|
|
|
|
int oldlang=-1;
|
|
|
|
char *fmt = languagetext[stringnum][oldlang=svs.language];
|
|
|
|
|
|
|
|
va_start (argptr,stringnum);
|
2006-03-06 01:41:09 +00:00
|
|
|
vsnprintf (string,sizeof(string)-1, fmt,argptr);
|
2004-08-23 00:15:46 +00:00
|
|
|
va_end (argptr);
|
|
|
|
|
|
|
|
if(strlen(string) >= sizeof(string))
|
|
|
|
Sys_Error("SV_BroadcastPrintf: Buffer stomped\n");
|
2005-10-23 17:57:20 +00:00
|
|
|
|
2004-08-23 00:15:46 +00:00
|
|
|
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;
|
|
|
|
if (cl->controller)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (oldlang!=cl->language)
|
|
|
|
{
|
|
|
|
fmt = languagetext[stringnum][oldlang=cl->language];
|
|
|
|
|
|
|
|
va_start (argptr,stringnum);
|
2006-03-06 01:41:09 +00:00
|
|
|
vsnprintf (string,sizeof(string)-1, fmt,argptr);
|
2004-08-23 00:15:46 +00:00
|
|
|
va_end (argptr);
|
|
|
|
|
|
|
|
if(strlen(string) >= sizeof(string))
|
|
|
|
Sys_Error("SV_BroadcastPrintf: Buffer stomped\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
SV_PrintToClient(cl, level, string);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
=================
|
|
|
|
SV_BroadcastCommand
|
|
|
|
|
|
|
|
Sends text to all active clients
|
|
|
|
=================
|
|
|
|
*/
|
|
|
|
void VARGS SV_BroadcastCommand (char *fmt, ...)
|
|
|
|
{
|
|
|
|
va_list argptr;
|
|
|
|
char string[1024];
|
|
|
|
int i;
|
|
|
|
client_t *cl;
|
2005-10-23 17:57:20 +00:00
|
|
|
|
2004-08-23 00:15:46 +00:00
|
|
|
if (!sv.state)
|
|
|
|
return;
|
|
|
|
va_start (argptr,fmt);
|
2006-03-06 01:41:09 +00:00
|
|
|
vsnprintf (string,sizeof(string), fmt,argptr);
|
2004-08-23 00:15:46 +00:00
|
|
|
va_end (argptr);
|
|
|
|
|
|
|
|
for (i=0, cl = svs.clients ; i<MAX_CLIENTS ; i++, cl++)
|
|
|
|
{
|
|
|
|
if (cl->controller)
|
|
|
|
continue;
|
|
|
|
if (cl->state>=cs_connected)
|
|
|
|
{
|
2009-08-08 12:43:35 +00:00
|
|
|
if (ISQWCLIENT(cl) || ISNQCLIENT(cl))
|
|
|
|
{
|
|
|
|
ClientReliableWrite_Begin(cl, svc_stufftext, strlen(string)+2);
|
|
|
|
ClientReliableWrite_String (cl, string);
|
|
|
|
}
|
|
|
|
else if (ISQ2CLIENT(cl))
|
|
|
|
{
|
|
|
|
ClientReliableWrite_Begin(cl, svcq2_stufftext, strlen(string)+2);
|
|
|
|
ClientReliableWrite_String (cl, string);
|
|
|
|
}
|
2004-08-23 00:15:46 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
=================
|
|
|
|
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
|
2012-12-04 19:37:57 +00:00
|
|
|
|
|
|
|
MULTICAST_ONE sent to a single client.
|
|
|
|
MULTICAST_INIT sent to clients when they first connect. for completeness.
|
2004-08-23 00:15:46 +00:00
|
|
|
=================
|
|
|
|
*/
|
2004-08-31 23:58:18 +00:00
|
|
|
void SV_MulticastProtExt(vec3_t origin, multicast_t to, int dimension_mask, int with, int without)
|
2004-08-23 00:15:46 +00:00
|
|
|
{
|
|
|
|
client_t *client;
|
|
|
|
qbyte *mask;
|
|
|
|
int leafnum;
|
|
|
|
int j;
|
|
|
|
qboolean reliable;
|
2011-12-23 03:12:29 +00:00
|
|
|
int pnum = 0;
|
2004-08-23 00:15:46 +00:00
|
|
|
|
2012-11-29 13:37:48 +00:00
|
|
|
if (to == MULTICAST_INIT)
|
|
|
|
{
|
|
|
|
//we only have one signon buffer. make sure you don't put non-identical protocols in the buffer
|
|
|
|
SV_FlushSignon();
|
|
|
|
SZ_Write (&sv.signon, sv.multicast.data, sv.multicast.cursize);
|
|
|
|
|
|
|
|
//and send to players that are already on
|
|
|
|
to = MULTICAST_ALL_R;
|
|
|
|
}
|
|
|
|
|
2004-08-23 00:15:46 +00:00
|
|
|
// to = MULTICAST_ALL;
|
|
|
|
#ifdef Q2BSPS
|
2009-11-04 21:16:50 +00:00
|
|
|
if (sv.world.worldmodel->fromgame == fg_quake2 || sv.world.worldmodel->fromgame == fg_quake3)
|
2004-08-23 00:15:46 +00:00
|
|
|
{
|
|
|
|
int area1, area2, cluster;
|
|
|
|
|
|
|
|
reliable = false;
|
|
|
|
|
|
|
|
if (to != MULTICAST_ALL_R && to != MULTICAST_ALL)
|
|
|
|
{
|
2009-11-04 21:16:50 +00:00
|
|
|
leafnum = CM_PointLeafnum (sv.world.worldmodel, origin);
|
|
|
|
area1 = CM_LeafArea (sv.world.worldmodel, leafnum);
|
2004-08-23 00:15:46 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
leafnum = 0; // just to avoid compiler warnings
|
|
|
|
area1 = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (to)
|
|
|
|
{
|
|
|
|
case MULTICAST_ALL_R:
|
|
|
|
reliable = true; // intentional fallthrough
|
|
|
|
case MULTICAST_ALL:
|
|
|
|
leafnum = 0;
|
|
|
|
mask = NULL;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case MULTICAST_PHS_R:
|
|
|
|
reliable = true; // intentional fallthrough
|
|
|
|
case MULTICAST_PHS:
|
2009-11-04 21:16:50 +00:00
|
|
|
leafnum = CM_PointLeafnum (sv.world.worldmodel, origin);
|
|
|
|
cluster = CM_LeafCluster (sv.world.worldmodel, leafnum);
|
|
|
|
mask = CM_ClusterPHS (sv.world.worldmodel, cluster);
|
2004-08-23 00:15:46 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case MULTICAST_PVS_R:
|
|
|
|
reliable = true; // intentional fallthrough
|
|
|
|
case MULTICAST_PVS:
|
2009-11-04 21:16:50 +00:00
|
|
|
leafnum = CM_PointLeafnum (sv.world.worldmodel, origin);
|
|
|
|
cluster = CM_LeafCluster (sv.world.worldmodel, leafnum);
|
|
|
|
mask = CM_ClusterPVS (sv.world.worldmodel, cluster, NULL, 0);
|
2004-08-23 00:15:46 +00:00
|
|
|
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;
|
|
|
|
|
2008-11-28 20:34:51 +00:00
|
|
|
if (client->protocol == SCP_QUAKEWORLD)
|
2004-08-23 00:15:46 +00:00
|
|
|
{
|
2008-11-28 20:34:51 +00:00
|
|
|
if (client->fteprotocolextensions & without)
|
|
|
|
{
|
|
|
|
// Con_Printf ("Version supressed multicast - without pext\n");
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (!(~client->fteprotocolextensions & ~with))
|
|
|
|
{
|
|
|
|
// Con_Printf ("Version supressed multicast - with pext\n");
|
|
|
|
continue;
|
|
|
|
}
|
2004-08-23 00:15:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (mask)
|
|
|
|
{
|
|
|
|
#ifdef Q2SERVER
|
|
|
|
if (ge)
|
2009-11-04 21:16:50 +00:00
|
|
|
leafnum = CM_PointLeafnum (sv.world.worldmodel, client->q2edict->s.origin);
|
2004-08-23 00:15:46 +00:00
|
|
|
else
|
|
|
|
#endif
|
2012-09-30 05:52:03 +00:00
|
|
|
{
|
|
|
|
if (svprogfuncs)
|
|
|
|
{
|
|
|
|
if (!((int)client->edict->xv->dimension_see & dimension_mask))
|
|
|
|
continue;
|
|
|
|
}
|
2009-11-04 21:16:50 +00:00
|
|
|
leafnum = CM_PointLeafnum (sv.world.worldmodel, client->edict->v->origin);
|
2012-09-30 05:52:03 +00:00
|
|
|
}
|
2009-11-04 21:16:50 +00:00
|
|
|
cluster = CM_LeafCluster (sv.world.worldmodel, leafnum);
|
|
|
|
area2 = CM_LeafArea (sv.world.worldmodel, leafnum);
|
|
|
|
if (!CM_AreasConnected (sv.world.worldmodel, area1, area2))
|
2004-08-23 00:15:46 +00:00
|
|
|
continue;
|
|
|
|
if ( mask && (!(mask[cluster>>3] & (1<<(cluster&7)) ) ) )
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2005-06-14 04:52:10 +00:00
|
|
|
switch (client->protocol)
|
2004-08-23 00:15:46 +00:00
|
|
|
{
|
2005-06-14 04:52:10 +00:00
|
|
|
case SCP_BAD:
|
2005-08-03 23:14:59 +00:00
|
|
|
continue; //a bot.
|
|
|
|
|
2006-02-17 19:54:47 +00:00
|
|
|
default:
|
|
|
|
SV_Error("Multicast: Client is using a bad protocl");
|
|
|
|
|
2008-11-09 22:29:28 +00:00
|
|
|
case SCP_QUAKE3:
|
|
|
|
Con_Printf("Skipping multicast for q3 client\n");
|
|
|
|
break;
|
2005-06-14 04:52:10 +00:00
|
|
|
#ifdef NQPROT
|
|
|
|
case SCP_NETQUAKE:
|
2012-10-01 14:29:44 +00:00
|
|
|
case SCP_PROQUAKE:
|
2011-10-27 16:16:29 +00:00
|
|
|
case SCP_FITZ666:
|
2005-06-14 04:52:10 +00:00
|
|
|
case SCP_DARKPLACES6:
|
|
|
|
case SCP_DARKPLACES7:
|
2004-08-23 00:15:46 +00:00
|
|
|
if (reliable)
|
|
|
|
{
|
|
|
|
ClientReliableCheckBlock(client, sv.nqmulticast.cursize);
|
|
|
|
ClientReliableWrite_SZ(client, sv.nqmulticast.data, sv.nqmulticast.cursize);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
SZ_Write (&client->datagram, sv.nqmulticast.data, sv.nqmulticast.cursize);
|
2005-06-14 04:52:10 +00:00
|
|
|
break;
|
2005-07-14 01:57:34 +00:00
|
|
|
#endif
|
|
|
|
#ifdef Q2SERVER
|
|
|
|
case SCP_QUAKE2:
|
|
|
|
if (reliable)
|
|
|
|
{
|
|
|
|
ClientReliableCheckBlock(client, sv.q2multicast.cursize);
|
|
|
|
ClientReliableWrite_SZ(client, sv.q2multicast.data, sv.q2multicast.cursize);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
SZ_Write (&client->datagram, sv.q2multicast.data, sv.q2multicast.cursize);
|
|
|
|
break;
|
2004-08-23 00:15:46 +00:00
|
|
|
#endif
|
2005-06-14 04:52:10 +00:00
|
|
|
case SCP_QUAKEWORLD:
|
|
|
|
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);
|
|
|
|
break;
|
2004-08-23 00:15:46 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
#endif
|
|
|
|
{
|
|
|
|
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:
|
Fixes, workarounds, and breakages. Hexen2 should work much better (-hexen2 says no mission pack, -portals says h2mp). Started working on splitting bigcoords per client, far too much work still to go on that. Removed gl_ztrick entirely. Enabled csprogs download by default. Added client support for fitzquake's 666 protocol, needs testing, some cleanup for dp protocols too, no server support, couldn't selectively enable it anyway. Now attempting to cache shadow meshes for explosions and stuff. Played with lightmaps a little, should potentially run a little faster on certain (intel?) cards. Tweeked npfte a little to try to avoid deadlocks and crashes. Fixed sky worldspawn parsing. Added h2mp's model format. Fixed baseline issue in q2 client, made servers generate q2 baselines. MOVETYPE_PUSH will not rotate extra if rotation is forced. Made status command show allowed client types. Changed lighting on weapons - should now be shaded.
git-svn-id: https://svn.code.sf.net/p/fteqw/code/branches/wip@3572 fc73d0e0-1445-4013-8a0c-d673dee63da5
2010-08-11 03:36:31 +00:00
|
|
|
if (!sv.phs) /*broadcast if no pvs*/
|
|
|
|
mask = sv.pvs;
|
|
|
|
else
|
2011-12-23 03:12:29 +00:00
|
|
|
{
|
|
|
|
leafnum = sv.world.worldmodel->funcs.LeafnumForPoint(sv.world.worldmodel, origin);
|
Fixes, workarounds, and breakages. Hexen2 should work much better (-hexen2 says no mission pack, -portals says h2mp). Started working on splitting bigcoords per client, far too much work still to go on that. Removed gl_ztrick entirely. Enabled csprogs download by default. Added client support for fitzquake's 666 protocol, needs testing, some cleanup for dp protocols too, no server support, couldn't selectively enable it anyway. Now attempting to cache shadow meshes for explosions and stuff. Played with lightmaps a little, should potentially run a little faster on certain (intel?) cards. Tweeked npfte a little to try to avoid deadlocks and crashes. Fixed sky worldspawn parsing. Added h2mp's model format. Fixed baseline issue in q2 client, made servers generate q2 baselines. MOVETYPE_PUSH will not rotate extra if rotation is forced. Made status command show allowed client types. Changed lighting on weapons - should now be shaded.
git-svn-id: https://svn.code.sf.net/p/fteqw/code/branches/wip@3572 fc73d0e0-1445-4013-8a0c-d673dee63da5
2010-08-11 03:36:31 +00:00
|
|
|
mask = sv.phs + leafnum * 4*((sv.world.worldmodel->numleafs+31)>>5);
|
2011-12-23 03:12:29 +00:00
|
|
|
}
|
2004-08-23 00:15:46 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case MULTICAST_PVS_R:
|
|
|
|
reliable = true; // intentional fallthrough
|
|
|
|
case MULTICAST_PVS:
|
2011-12-23 03:12:29 +00:00
|
|
|
leafnum = sv.world.worldmodel->funcs.LeafnumForPoint(sv.world.worldmodel, origin);
|
2009-11-04 21:16:50 +00:00
|
|
|
mask = sv.pvs + leafnum * 4*((sv.world.worldmodel->numleafs+31)>>5);
|
2004-08-23 00:15:46 +00:00
|
|
|
break;
|
|
|
|
|
2011-12-23 03:12:29 +00:00
|
|
|
case MULTICAST_ONE_R:
|
|
|
|
reliable = true;
|
|
|
|
case MULTICAST_ONE:
|
|
|
|
if (svprogfuncs)
|
|
|
|
{
|
|
|
|
edict_t *ent = PROG_TO_EDICT(svprogfuncs, pr_global_struct->msg_entity);
|
|
|
|
pnum = NUM_FOR_EDICT(svprogfuncs, ent) - 1;
|
|
|
|
}
|
|
|
|
mask = NULL;
|
|
|
|
break;
|
|
|
|
|
2004-08-23 00:15:46 +00:00
|
|
|
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;
|
|
|
|
|
2004-10-10 06:32:29 +00:00
|
|
|
if (client->controller)
|
|
|
|
continue; //FIXME: send if at least one of the players is near enough.
|
|
|
|
|
2008-11-28 20:34:51 +00:00
|
|
|
if (client->protocol == SCP_QUAKEWORLD)
|
2004-08-23 00:15:46 +00:00
|
|
|
{
|
2008-11-28 20:34:51 +00:00
|
|
|
if (client->fteprotocolextensions & without)
|
|
|
|
{
|
|
|
|
// Con_Printf ("Version supressed multicast - without pext\n");
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (!(client->fteprotocolextensions & with) && with)
|
|
|
|
{
|
|
|
|
// Con_Printf ("Version supressed multicast - with pext\n");
|
|
|
|
continue;
|
|
|
|
}
|
2004-08-23 00:15:46 +00:00
|
|
|
}
|
|
|
|
|
2011-12-23 03:12:29 +00:00
|
|
|
if (!mask)
|
|
|
|
{
|
|
|
|
if (pnum != j)
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
else if (svprogfuncs)
|
2009-03-03 01:52:30 +00:00
|
|
|
{
|
2008-11-09 22:29:28 +00:00
|
|
|
if (!((int)client->edict->xv->dimension_see & dimension_mask))
|
|
|
|
continue;
|
|
|
|
|
2009-03-03 01:52:30 +00:00
|
|
|
if (to == MULTICAST_PHS_R || to == MULTICAST_PHS)
|
|
|
|
{
|
|
|
|
vec3_t delta;
|
|
|
|
VectorSubtract(origin, client->edict->v->origin, delta);
|
|
|
|
if (Length(delta) <= 1024)
|
|
|
|
goto inrange;
|
|
|
|
}
|
2004-08-23 00:15:46 +00:00
|
|
|
|
2009-03-03 01:52:30 +00:00
|
|
|
// -1 is because pvs rows are 1 based, not 0 based like leafs
|
|
|
|
if (mask != sv.pvs)
|
2004-08-23 00:15:46 +00:00
|
|
|
{
|
2010-08-16 02:03:02 +00:00
|
|
|
vec3_t pos;
|
|
|
|
VectorAdd(client->edict->v->origin, client->edict->v->view_ofs, pos);
|
|
|
|
leafnum = sv.world.worldmodel->funcs.LeafnumForPoint (sv.world.worldmodel, pos)-1;
|
2009-03-03 01:52:30 +00:00
|
|
|
if ( !(mask[leafnum>>3] & (1<<(leafnum&7)) ) )
|
|
|
|
{
|
|
|
|
// Con_Printf ("PVS supressed multicast\n");
|
|
|
|
continue;
|
|
|
|
}
|
2004-08-23 00:15:46 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
inrange:
|
2005-08-03 23:14:59 +00:00
|
|
|
switch (client->protocol)
|
2004-08-23 00:15:46 +00:00
|
|
|
{
|
2005-08-03 23:14:59 +00:00
|
|
|
case SCP_BAD:
|
|
|
|
continue; //a bot.
|
2006-02-17 19:54:47 +00:00
|
|
|
default:
|
|
|
|
SV_Error("multicast: Client is using a bad protocol");
|
2005-08-03 23:14:59 +00:00
|
|
|
|
2008-11-09 22:29:28 +00:00
|
|
|
case SCP_QUAKE3:
|
|
|
|
Con_Printf("Skipping multicast for q3 client\n");
|
|
|
|
break;
|
|
|
|
|
2005-08-03 23:14:59 +00:00
|
|
|
#ifdef NQPROT
|
|
|
|
case SCP_NETQUAKE:
|
2012-10-01 14:29:44 +00:00
|
|
|
case SCP_PROQUAKE:
|
2011-10-27 16:16:29 +00:00
|
|
|
case SCP_FITZ666:
|
2005-08-03 23:14:59 +00:00
|
|
|
case SCP_DARKPLACES6:
|
|
|
|
case SCP_DARKPLACES7: //extra prediction stuff
|
|
|
|
if (reliable)
|
|
|
|
{
|
2004-08-23 00:15:46 +00:00
|
|
|
ClientReliableCheckBlock(client, sv.nqmulticast.cursize);
|
|
|
|
ClientReliableWrite_SZ(client, sv.nqmulticast.data, sv.nqmulticast.cursize);
|
2005-08-03 23:14:59 +00:00
|
|
|
}
|
|
|
|
else
|
2004-08-23 00:15:46 +00:00
|
|
|
SZ_Write (&client->datagram, sv.nqmulticast.data, sv.nqmulticast.cursize);
|
2005-08-03 23:14:59 +00:00
|
|
|
|
|
|
|
break;
|
|
|
|
#endif
|
|
|
|
#ifdef Q2SERVER
|
|
|
|
case SCP_QUAKE2:
|
|
|
|
if (reliable)
|
|
|
|
{
|
|
|
|
ClientReliableCheckBlock(client, sv.q2multicast.cursize);
|
|
|
|
ClientReliableWrite_SZ(client, sv.q2multicast.data, sv.q2multicast.cursize);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
SZ_Write (&client->datagram, sv.q2multicast.data, sv.q2multicast.cursize);
|
|
|
|
break;
|
|
|
|
#endif
|
|
|
|
case SCP_QUAKEWORLD:
|
|
|
|
if (reliable)
|
|
|
|
{
|
2004-08-23 00:15:46 +00:00
|
|
|
ClientReliableCheckBlock(client, sv.multicast.cursize);
|
|
|
|
ClientReliableWrite_SZ(client, sv.multicast.data, sv.multicast.cursize);
|
2005-08-03 23:14:59 +00:00
|
|
|
}
|
|
|
|
else
|
2004-08-23 00:15:46 +00:00
|
|
|
SZ_Write (&client->datagram, sv.multicast.data, sv.multicast.cursize);
|
2005-08-03 23:14:59 +00:00
|
|
|
break;
|
2004-08-23 00:15:46 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-08-04 01:35:52 +00:00
|
|
|
if (sv.mvdrecording && ((demo.recorder.fteprotocolextensions & with) == with) && !(demo.recorder.fteprotocolextensions & without))
|
2004-08-23 00:15:46 +00:00
|
|
|
{
|
2012-08-04 01:35:52 +00:00
|
|
|
sizebuf_t *msg;
|
2011-12-23 03:12:29 +00:00
|
|
|
if (!mask)
|
2004-08-23 00:15:46 +00:00
|
|
|
{
|
2011-12-23 03:12:29 +00:00
|
|
|
/*no distinction between reliable or not*/
|
2012-08-04 01:35:52 +00:00
|
|
|
msg = MVDWrite_Begin(dem_single, pnum, sv.multicast.cursize);
|
2011-12-23 03:12:29 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (reliable)
|
|
|
|
{
|
2012-08-04 01:35:52 +00:00
|
|
|
msg = MVDWrite_Begin(dem_all, 0, sv.multicast.cursize);
|
2011-12-23 03:12:29 +00:00
|
|
|
}
|
|
|
|
else
|
2012-08-04 01:35:52 +00:00
|
|
|
msg = &demo.datagram;
|
2011-12-23 03:12:29 +00:00
|
|
|
}
|
2012-08-04 01:35:52 +00:00
|
|
|
SZ_Write(&demo.datagram, sv.multicast.data, sv.multicast.cursize);
|
2004-08-23 00:15:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef NQPROT
|
|
|
|
SZ_Clear (&sv.nqmulticast);
|
2005-07-14 01:57:34 +00:00
|
|
|
#endif
|
|
|
|
#ifdef Q2SERVER
|
|
|
|
SZ_Clear (&sv.q2multicast);
|
2004-08-23 00:15:46 +00:00
|
|
|
#endif
|
|
|
|
SZ_Clear (&sv.multicast);
|
|
|
|
}
|
|
|
|
|
|
|
|
//version does all the work now
|
2005-03-18 06:13:11 +00:00
|
|
|
void VARGS SV_Multicast (vec3_t origin, multicast_t to)
|
2004-08-23 00:15:46 +00:00
|
|
|
{
|
2004-08-31 23:58:18 +00:00
|
|
|
SV_MulticastProtExt(origin, to, FULLDIMENSIONMASK, 0, 0);
|
2004-08-23 00:15:46 +00:00
|
|
|
}
|
|
|
|
|
2005-10-23 17:57:20 +00:00
|
|
|
/*
|
2004-08-23 00:15:46 +00:00
|
|
|
==================
|
|
|
|
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
|
2005-07-28 15:22:15 +00:00
|
|
|
already running on that entity/channel pair.
|
2004-08-23 00:15:46 +00:00
|
|
|
|
|
|
|
An attenuation of 0 will play full volume everywhere in the level.
|
|
|
|
Larger attenuations will drop off. (max 4 attenuation)
|
|
|
|
|
|
|
|
==================
|
2005-10-23 17:57:20 +00:00
|
|
|
*/
|
2010-11-06 23:05:29 +00:00
|
|
|
void SV_StartSound (int ent, vec3_t origin, int seenmask, int channel, char *sample, int volume, float attenuation, int pitchadj)
|
2005-10-23 17:57:20 +00:00
|
|
|
{
|
2004-08-23 00:15:46 +00:00
|
|
|
int sound_num;
|
2008-11-28 20:34:51 +00:00
|
|
|
int extfield_mask;
|
|
|
|
int qwflags;
|
2004-08-23 00:15:46 +00:00
|
|
|
int i;
|
|
|
|
qboolean use_phs;
|
2013-03-12 22:35:33 +00:00
|
|
|
qboolean reliable;
|
2005-10-19 21:11:05 +00:00
|
|
|
int requiredextensions = 0;
|
2004-08-23 00:15:46 +00:00
|
|
|
|
2013-03-12 22:35:33 +00:00
|
|
|
if (channel & 256)
|
|
|
|
{
|
|
|
|
channel -= 256;
|
|
|
|
reliable = true;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
reliable = false;
|
|
|
|
|
2004-08-23 00:15:46 +00:00
|
|
|
if (volume < 0 || volume > 255)
|
2005-01-16 00:59:48 +00:00
|
|
|
{
|
|
|
|
Con_Printf ("SV_StartSound: volume = %i", volume);
|
|
|
|
return;
|
|
|
|
}
|
2004-08-23 00:15:46 +00:00
|
|
|
|
|
|
|
if (attenuation < 0 || attenuation > 4)
|
2005-01-16 00:59:48 +00:00
|
|
|
{
|
|
|
|
Con_Printf ("SV_StartSound: attenuation = %f", attenuation);
|
|
|
|
return;
|
|
|
|
}
|
2004-08-23 00:15:46 +00:00
|
|
|
|
2013-03-12 22:35:33 +00:00
|
|
|
if (channel < 0 || channel > 255)
|
2005-01-16 00:59:48 +00:00
|
|
|
{
|
|
|
|
Con_Printf ("SV_StartSound: channel = %i", channel);
|
|
|
|
return;
|
|
|
|
}
|
2004-08-23 00:15:46 +00:00
|
|
|
|
|
|
|
// find precache number for sound
|
2010-08-21 13:31:39 +00:00
|
|
|
if (!*sample)
|
|
|
|
sound_num = 0;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
for (sound_num=1 ; sound_num<MAX_SOUNDS
|
|
|
|
&& sv.strings.sound_precache[sound_num] ; sound_num++)
|
|
|
|
if (!strcmp(sample, sv.strings.sound_precache[sound_num]))
|
|
|
|
break;
|
|
|
|
}
|
2005-10-23 17:57:20 +00:00
|
|
|
|
2006-02-17 02:51:59 +00:00
|
|
|
if ( sound_num == MAX_SOUNDS || !sv.strings.sound_precache[sound_num] )
|
2004-08-23 00:15:46 +00:00
|
|
|
{
|
|
|
|
Con_DPrintf ("SV_StartSound: %s not precacheed\n", sample);
|
|
|
|
return;
|
|
|
|
}
|
2005-10-23 17:57:20 +00:00
|
|
|
|
2013-03-12 22:35:33 +00:00
|
|
|
if (reliable || !sv_phs.value) // no PHS flag
|
2004-08-23 00:15:46 +00:00
|
|
|
use_phs = false;
|
|
|
|
else
|
2010-08-21 13:31:39 +00:00
|
|
|
use_phs = attenuation!=0;
|
2004-08-23 00:15:46 +00:00
|
|
|
|
2008-11-28 20:34:51 +00:00
|
|
|
// if (channel == CHAN_BODY || channel == CHAN_VOICE)
|
|
|
|
// reliable = true;
|
2004-08-23 00:15:46 +00:00
|
|
|
|
2008-11-28 20:34:51 +00:00
|
|
|
extfield_mask = 0;
|
|
|
|
if (volume != DEFAULT_SOUND_PACKET_VOLUME)
|
|
|
|
extfield_mask |= NQSND_VOLUME;
|
|
|
|
if (attenuation != DEFAULT_SOUND_PACKET_ATTENUATION)
|
|
|
|
extfield_mask |= NQSND_ATTENUATION;
|
|
|
|
if (ent >= 8192 || channel >= 8)
|
|
|
|
extfield_mask |= DPSND_LARGEENTITY;
|
|
|
|
if (sound_num > 0xff)
|
|
|
|
extfield_mask |= DPSND_LARGESOUND;
|
2010-11-06 23:54:36 +00:00
|
|
|
if (pitchadj && (pitchadj != 100))
|
2010-11-06 23:05:29 +00:00
|
|
|
extfield_mask |= FTESND_PITCHADJ;
|
2008-11-28 20:34:51 +00:00
|
|
|
|
|
|
|
#ifdef PEXT_SOUNDDBL
|
2010-11-06 23:05:29 +00:00
|
|
|
if (channel >= 8 || ent >= 2048 || sound_num > 0xff || pitchadj)
|
2008-11-28 20:34:51 +00:00
|
|
|
{
|
|
|
|
//if any of the above conditions evaluates to true, then we can't use standard qw protocols
|
|
|
|
MSG_WriteByte (&sv.multicast, svcfte_soundextended);
|
|
|
|
MSG_WriteByte (&sv.multicast, extfield_mask);
|
|
|
|
if (extfield_mask & NQSND_VOLUME)
|
|
|
|
MSG_WriteByte (&sv.multicast, volume);
|
|
|
|
if (extfield_mask & NQSND_ATTENUATION)
|
|
|
|
MSG_WriteByte (&sv.multicast, attenuation*64);
|
2010-11-06 23:05:29 +00:00
|
|
|
if (extfield_mask & FTESND_PITCHADJ)
|
2010-11-06 23:54:36 +00:00
|
|
|
MSG_WriteByte (&sv.multicast, pitchadj);
|
2008-11-28 20:34:51 +00:00
|
|
|
if (extfield_mask & DPSND_LARGEENTITY)
|
|
|
|
{
|
------------------------------------------------------------------------
r4169 | acceptthis | 2013-01-17 08:55:12 +0000 (Thu, 17 Jan 2013) | 31 lines
removed MAX_VISEDICTS limit.
PEXT2_REPLACEMENTDELTAS tweaked, now has 4 million entity limit. still not enabled by default.
TE_BEAM now maps to a separate TEQW_BEAM to avoid conflicts with QW.
added android multitouch emulation for windows/rawinput (in_simulatemultitouch).
split topcolor/bottomcolor from scoreboard, for dp's colormap|1024 feature.
now using utf-8 for windows consoles.
qcc warnings/errors now give clickable console links for quick+easy editing.
disabled menutint when the currently active item changes contrast or gamma (for OneManClan).
Added support for drawfont/drawfontscale.
tweaked the qcvm a little to reduce the number of pointers.
.doll file loading. still experimental and will likely crash. requires csqc active, even if its a dummy progs. this will be fixed in time. Still other things that need cleaning up.
windows: gl_font "?" shows the standard windows font-selection dialog, and can be used to select windows fonts. not all work. and you probably don't want to use windings.
fixed splitscreen support when playing mvds. added mini-scoreboards to splitscreen.
editor/debugger now shows asm if there's no linenumber info. also, pressing f1 for help shows the shortcuts.
Added support for .framegroups files for psk(psa) and iqm formats.
True support for ezquake's colour codes. Mutually exclusive with background colours.
path command output slightly more readable.
added support for digest_hex (MD4, SHA1, CRC16).
skingroups now colourmap correctly.
Fix terrain colour hints, and litdata from the wrong bsp.
fix ftp dual-homed issue. support epsv command, and enable ipv6 (eprt still not supported).
remove d3d11 compilation from the makefile. the required headers are not provided by mingw, and are not available to the build bot, so don't bother.
fix v *= v.x and similar opcodes.
fteqcc: fixed support for áéÃóú type chars in names. utf-8 files now properly supported (even with the utf-8 bom/identifier). utf-16 also supported.
fteqcc: fixed '#if 1 == 3 && 4' parsing.
fteqcc: -Werror acts on the warning, rather than as a separate error. Line numbers are thus more readable.
fteqcc: copyright message now includes compile date instead.
fteqccgui: the treeview control is now coloured depending on whether there were warnings/errors in the last compile.
fteqccgui: the output window is now focused and scrolls down as compilation progresses.
pr_dumpplatform command dumps out some pragmas to convert more serious warnings to errors. This is to avoid the infamous 'fteqcc sucks cos my code sucks' issue.
rewrote prespawn/modelist/soundlist code. server tracks progress now.
------------------------------------------------------------------------
git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@4167 fc73d0e0-1445-4013-8a0c-d673dee63da5
2013-03-12 22:29:40 +00:00
|
|
|
MSG_WriteEntity (&sv.multicast, ent);
|
2008-11-28 20:34:51 +00:00
|
|
|
MSG_WriteByte (&sv.multicast, channel);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
MSG_WriteShort (&sv.multicast, (ent<<3) | channel);
|
|
|
|
if (extfield_mask & DPSND_LARGESOUND)
|
|
|
|
MSG_WriteShort (&sv.multicast, sound_num);
|
|
|
|
else
|
|
|
|
MSG_WriteByte (&sv.multicast, sound_num);
|
|
|
|
for (i=0 ; i<3 ; i++)
|
|
|
|
MSG_WriteCoord (&sv.multicast, origin[i]);
|
|
|
|
|
|
|
|
requiredextensions |= PEXT_SOUNDDBL;
|
|
|
|
if (ent > 512)
|
|
|
|
requiredextensions |= PEXT_ENTITYDBL;
|
|
|
|
if (ent > 1024)
|
|
|
|
requiredextensions |= PEXT_ENTITYDBL2;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
#endif
|
|
|
|
{
|
|
|
|
qwflags = (ent<<3) | channel;
|
|
|
|
|
|
|
|
if (volume != DEFAULT_SOUND_PACKET_VOLUME)
|
|
|
|
qwflags |= SND_VOLUME;
|
|
|
|
if (attenuation != DEFAULT_SOUND_PACKET_ATTENUATION)
|
|
|
|
qwflags |= SND_ATTENUATION;
|
|
|
|
|
|
|
|
MSG_WriteByte (&sv.multicast, svc_sound);
|
|
|
|
MSG_WriteShort (&sv.multicast, qwflags);
|
|
|
|
if (qwflags & SND_VOLUME)
|
|
|
|
MSG_WriteByte (&sv.multicast, volume);
|
|
|
|
if (qwflags & 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 (ent > 512)
|
|
|
|
requiredextensions |= PEXT_ENTITYDBL;
|
|
|
|
if (ent > 1024)
|
|
|
|
requiredextensions |= PEXT_ENTITYDBL2;
|
|
|
|
}
|
2005-10-19 21:11:05 +00:00
|
|
|
|
2004-08-23 00:15:46 +00:00
|
|
|
#ifdef NQPROT
|
|
|
|
MSG_WriteByte (&sv.nqmulticast, svc_sound);
|
2008-11-28 20:34:51 +00:00
|
|
|
MSG_WriteByte (&sv.nqmulticast, extfield_mask);
|
|
|
|
if (extfield_mask & NQSND_VOLUME)
|
2004-08-23 00:15:46 +00:00
|
|
|
MSG_WriteByte (&sv.nqmulticast, volume);
|
2008-11-28 20:34:51 +00:00
|
|
|
if (extfield_mask & NQSND_ATTENUATION)
|
2004-08-23 00:15:46 +00:00
|
|
|
MSG_WriteByte (&sv.nqmulticast, attenuation*64);
|
2010-11-06 23:05:29 +00:00
|
|
|
if (extfield_mask & FTESND_PITCHADJ)
|
2010-11-06 23:54:36 +00:00
|
|
|
MSG_WriteByte (&sv.nqmulticast, pitchadj);
|
2008-11-28 20:34:51 +00:00
|
|
|
if (extfield_mask & DPSND_LARGEENTITY)
|
|
|
|
{
|
------------------------------------------------------------------------
r4169 | acceptthis | 2013-01-17 08:55:12 +0000 (Thu, 17 Jan 2013) | 31 lines
removed MAX_VISEDICTS limit.
PEXT2_REPLACEMENTDELTAS tweaked, now has 4 million entity limit. still not enabled by default.
TE_BEAM now maps to a separate TEQW_BEAM to avoid conflicts with QW.
added android multitouch emulation for windows/rawinput (in_simulatemultitouch).
split topcolor/bottomcolor from scoreboard, for dp's colormap|1024 feature.
now using utf-8 for windows consoles.
qcc warnings/errors now give clickable console links for quick+easy editing.
disabled menutint when the currently active item changes contrast or gamma (for OneManClan).
Added support for drawfont/drawfontscale.
tweaked the qcvm a little to reduce the number of pointers.
.doll file loading. still experimental and will likely crash. requires csqc active, even if its a dummy progs. this will be fixed in time. Still other things that need cleaning up.
windows: gl_font "?" shows the standard windows font-selection dialog, and can be used to select windows fonts. not all work. and you probably don't want to use windings.
fixed splitscreen support when playing mvds. added mini-scoreboards to splitscreen.
editor/debugger now shows asm if there's no linenumber info. also, pressing f1 for help shows the shortcuts.
Added support for .framegroups files for psk(psa) and iqm formats.
True support for ezquake's colour codes. Mutually exclusive with background colours.
path command output slightly more readable.
added support for digest_hex (MD4, SHA1, CRC16).
skingroups now colourmap correctly.
Fix terrain colour hints, and litdata from the wrong bsp.
fix ftp dual-homed issue. support epsv command, and enable ipv6 (eprt still not supported).
remove d3d11 compilation from the makefile. the required headers are not provided by mingw, and are not available to the build bot, so don't bother.
fix v *= v.x and similar opcodes.
fteqcc: fixed support for áéÃóú type chars in names. utf-8 files now properly supported (even with the utf-8 bom/identifier). utf-16 also supported.
fteqcc: fixed '#if 1 == 3 && 4' parsing.
fteqcc: -Werror acts on the warning, rather than as a separate error. Line numbers are thus more readable.
fteqcc: copyright message now includes compile date instead.
fteqccgui: the treeview control is now coloured depending on whether there were warnings/errors in the last compile.
fteqccgui: the output window is now focused and scrolls down as compilation progresses.
pr_dumpplatform command dumps out some pragmas to convert more serious warnings to errors. This is to avoid the infamous 'fteqcc sucks cos my code sucks' issue.
rewrote prespawn/modelist/soundlist code. server tracks progress now.
------------------------------------------------------------------------
git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@4167 fc73d0e0-1445-4013-8a0c-d673dee63da5
2013-03-12 22:29:40 +00:00
|
|
|
MSG_WriteEntity (&sv.nqmulticast, ent);
|
2008-11-28 20:34:51 +00:00
|
|
|
MSG_WriteByte (&sv.nqmulticast, channel);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
MSG_WriteShort (&sv.nqmulticast, (ent<<3) | channel);
|
|
|
|
if (extfield_mask & DPSND_LARGESOUND)
|
|
|
|
MSG_WriteShort (&sv.nqmulticast, sound_num);
|
|
|
|
else
|
|
|
|
MSG_WriteByte (&sv.nqmulticast, sound_num);
|
2004-08-23 00:15:46 +00:00
|
|
|
for (i=0 ; i<3 ; i++)
|
|
|
|
MSG_WriteCoord (&sv.nqmulticast, origin[i]);
|
|
|
|
#endif
|
|
|
|
if (use_phs)
|
2009-03-03 01:52:30 +00:00
|
|
|
SV_MulticastProtExt(origin, reliable ? MULTICAST_PHS_R : MULTICAST_PHS, seenmask, requiredextensions, 0);
|
2004-08-23 00:15:46 +00:00
|
|
|
else
|
2009-03-03 01:52:30 +00:00
|
|
|
SV_MulticastProtExt(origin, reliable ? MULTICAST_ALL_R : MULTICAST_ALL, seenmask, requiredextensions, 0);
|
|
|
|
}
|
|
|
|
|
2013-03-12 23:24:15 +00:00
|
|
|
void SVQ1_StartSound (float *origin, wedict_t *wentity, int channel, char *sample, int volume, float attenuation, int pitchadj)
|
2009-03-03 01:52:30 +00:00
|
|
|
{
|
2011-09-03 03:49:43 +00:00
|
|
|
edict_t *entity = (edict_t*)wentity;
|
2009-03-03 01:52:30 +00:00
|
|
|
int i;
|
2013-03-12 23:24:15 +00:00
|
|
|
vec3_t originbuf;
|
|
|
|
if (!origin)
|
2009-03-03 01:52:30 +00:00
|
|
|
{
|
2013-03-12 23:24:15 +00:00
|
|
|
origin = originbuf;
|
|
|
|
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);
|
|
|
|
}
|
2009-03-03 01:52:30 +00:00
|
|
|
}
|
|
|
|
|
2010-11-06 23:05:29 +00:00
|
|
|
SV_StartSound(NUM_FOR_EDICT(svprogfuncs, entity), origin, entity->xv->dimension_seen, channel, sample, volume, attenuation, pitchadj);
|
2004-08-23 00:15:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
===============================================================================
|
|
|
|
|
|
|
|
FRAME UPDATES
|
|
|
|
|
|
|
|
===============================================================================
|
|
|
|
*/
|
|
|
|
|
|
|
|
int sv_nailmodel, sv_supernailmodel, sv_playermodel;
|
|
|
|
|
|
|
|
void SV_FindModelNumbers (void)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
sv_nailmodel = -1;
|
|
|
|
sv_supernailmodel = -1;
|
|
|
|
sv_playermodel = -1;
|
2005-10-23 17:57:20 +00:00
|
|
|
|
2004-08-23 00:15:46 +00:00
|
|
|
for (i=0 ; i<MAX_MODELS ; i++)
|
|
|
|
{
|
2006-02-17 02:51:59 +00:00
|
|
|
if (!sv.strings.model_precache[i])
|
2004-08-23 00:15:46 +00:00
|
|
|
break;
|
2011-10-27 16:16:29 +00:00
|
|
|
if (!strcmp(sv.strings.model_precache[i],"progs/spike.mdl") && sv.multicast.prim.coordsize == 2)
|
2004-08-23 00:15:46 +00:00
|
|
|
sv_nailmodel = i;
|
2011-10-27 16:16:29 +00:00
|
|
|
if (!strcmp(sv.strings.model_precache[i],"progs/s_spike.mdl") && sv.multicast.prim.coordsize == 2)
|
2004-08-23 00:15:46 +00:00
|
|
|
sv_supernailmodel = i;
|
2006-02-17 02:51:59 +00:00
|
|
|
if (!strcmp(sv.strings.model_precache[i],"progs/player.mdl"))
|
2004-08-23 00:15:46 +00:00
|
|
|
sv_playermodel = i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void SV_WriteEntityDataToMessage (client_t *client, sizebuf_t *msg, int pnum)
|
|
|
|
{
|
|
|
|
edict_t *other;
|
|
|
|
edict_t *ent;
|
|
|
|
int i;
|
2010-12-05 02:46:07 +00:00
|
|
|
float newa;
|
2004-08-23 00:15:46 +00:00
|
|
|
|
|
|
|
ent = client->edict;
|
|
|
|
|
2009-03-03 01:52:30 +00:00
|
|
|
if (!ent)
|
|
|
|
return;
|
|
|
|
|
2004-08-23 00:15:46 +00:00
|
|
|
// send a damage message if the player got hit this frame
|
2005-03-28 00:11:59 +00:00
|
|
|
if (ent->v->dmg_take || ent->v->dmg_save)
|
2004-08-23 00:15:46 +00:00
|
|
|
{
|
2005-03-28 00:11:59 +00:00
|
|
|
other = PROG_TO_EDICT(svprogfuncs, ent->v->dmg_inflictor);
|
2004-08-23 00:15:46 +00:00
|
|
|
if (pnum)
|
|
|
|
{
|
2008-05-25 22:23:43 +00:00
|
|
|
MSG_WriteByte(msg, svcfte_choosesplitclient);
|
2004-08-23 00:15:46 +00:00
|
|
|
MSG_WriteByte(msg, pnum);
|
|
|
|
}
|
|
|
|
MSG_WriteByte (msg, svc_damage);
|
2005-03-28 00:11:59 +00:00
|
|
|
MSG_WriteByte (msg, ent->v->dmg_save);
|
|
|
|
MSG_WriteByte (msg, ent->v->dmg_take);
|
2004-08-23 00:15:46 +00:00
|
|
|
for (i=0 ; i<3 ; i++)
|
2005-03-28 00:11:59 +00:00
|
|
|
MSG_WriteCoord (msg, other->v->origin[i] + 0.5*(other->v->mins[i] + other->v->maxs[i]));
|
2005-10-23 17:57:20 +00:00
|
|
|
|
2005-03-28 00:11:59 +00:00
|
|
|
ent->v->dmg_take = 0;
|
|
|
|
ent->v->dmg_save = 0;
|
2004-08-23 00:15:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// a fixangle might get lost in a dropped packet. Oh well.
|
2010-12-05 02:46:07 +00:00
|
|
|
if (ent->v->fixangle)
|
2004-08-23 00:15:46 +00:00
|
|
|
{
|
|
|
|
if (pnum)
|
|
|
|
{
|
2008-05-25 22:23:43 +00:00
|
|
|
MSG_WriteByte(msg, svcfte_choosesplitclient);
|
2004-08-23 00:15:46 +00:00
|
|
|
MSG_WriteByte(msg, pnum);
|
|
|
|
}
|
2012-02-12 05:18:31 +00:00
|
|
|
if (!client->lockangles && (client->fteprotocolextensions2 & PEXT2_SETANGLEDELTA) && client->delta_sequence != -1)
|
2010-12-05 02:46:07 +00:00
|
|
|
{
|
|
|
|
MSG_WriteByte (msg, svcfte_setangledelta);
|
|
|
|
for (i=0 ; i < 3 ; i++)
|
|
|
|
{
|
|
|
|
newa = ent->v->angles[i] - SHORT2ANGLE(client->lastcmd.angles[i]);
|
|
|
|
MSG_WriteAngle16 (msg, newa);
|
|
|
|
client->lastcmd.angles[i] = ANGLE2SHORT(ent->v->angles[i]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
MSG_WriteByte (msg, svc_setangle);
|
|
|
|
for (i=0 ; i < 3 ; i++)
|
|
|
|
MSG_WriteAngle (msg, ent->v->angles[i]);
|
|
|
|
}
|
2005-03-28 00:11:59 +00:00
|
|
|
ent->v->fixangle = 0;
|
2012-02-12 05:18:31 +00:00
|
|
|
client->lockangles = true;
|
2004-08-23 00:15:46 +00:00
|
|
|
}
|
2012-02-12 05:18:31 +00:00
|
|
|
else
|
|
|
|
client->lockangles = false;
|
2004-08-23 00:15:46 +00:00
|
|
|
}
|
|
|
|
|
2010-08-21 22:12:43 +00:00
|
|
|
/*sends the a centerprint string directly to the client*/
|
|
|
|
void SV_WriteCenterPrint(client_t *cl, char *s)
|
|
|
|
{
|
|
|
|
if (cl->controller)
|
|
|
|
{ //this is a slave client.
|
|
|
|
//find the right number and send.
|
|
|
|
int pnum = 0;
|
|
|
|
client_t *sp;
|
|
|
|
for (sp = cl->controller; sp; sp = sp->controlled)
|
|
|
|
{
|
|
|
|
if (sp == cl)
|
|
|
|
break;
|
|
|
|
pnum++;
|
|
|
|
}
|
|
|
|
cl = cl->controller;
|
|
|
|
|
|
|
|
ClientReliableWrite_Begin (cl, svcfte_choosesplitclient, 4 + strlen(s));
|
|
|
|
ClientReliableWrite_Byte (cl, pnum);
|
|
|
|
ClientReliableWrite_Byte (cl, svc_centerprint);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ClientReliableWrite_Begin (cl, svc_centerprint, 2 + strlen(s));
|
|
|
|
}
|
|
|
|
ClientReliableWrite_String (cl, s);
|
|
|
|
|
|
|
|
if (sv.mvdrecording)
|
|
|
|
{
|
2012-08-04 01:35:52 +00:00
|
|
|
sizebuf_t *msg = MVDWrite_Begin (dem_single, cl - svs.clients, 2 + strlen(s));
|
|
|
|
MSG_WriteByte (msg, svc_centerprint);
|
|
|
|
MSG_WriteString (msg, s);
|
2010-08-21 22:12:43 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-08-23 00:15:46 +00:00
|
|
|
/*
|
|
|
|
==================
|
|
|
|
SV_WriteClientdataToMessage
|
|
|
|
|
|
|
|
==================
|
|
|
|
*/
|
|
|
|
void SV_WriteClientdataToMessage (client_t *client, sizebuf_t *msg)
|
|
|
|
{
|
|
|
|
#ifdef NQPROT
|
2004-09-20 23:25:38 +00:00
|
|
|
int i;
|
2004-08-23 00:15:46 +00:00
|
|
|
int bits, items;
|
|
|
|
edict_t *ent;
|
|
|
|
#endif
|
|
|
|
client_t *split;
|
|
|
|
int pnum=0;
|
2013-03-12 22:35:33 +00:00
|
|
|
int weaponmodelindex = 0;
|
|
|
|
qboolean nqjunk = true;
|
2004-08-23 00:15:46 +00:00
|
|
|
|
|
|
|
// send the chokecount for r_netgraph
|
2005-05-26 12:55:34 +00:00
|
|
|
if (ISQWCLIENT(client))
|
2004-08-23 00:15:46 +00:00
|
|
|
if (client->chokecount)
|
|
|
|
{
|
|
|
|
MSG_WriteByte (msg, svc_chokecount);
|
|
|
|
MSG_WriteByte (msg, client->chokecount);
|
|
|
|
client->chokecount = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (split = client; split; split=split->controlled, pnum++)
|
2012-02-12 05:18:31 +00:00
|
|
|
{
|
2004-08-23 00:15:46 +00:00
|
|
|
SV_WriteEntityDataToMessage(split, msg, pnum);
|
2012-02-12 05:18:31 +00:00
|
|
|
|
|
|
|
if (split->centerprintstring && ! client->num_backbuf)
|
|
|
|
{
|
|
|
|
SV_WriteCenterPrint(split, split->centerprintstring);
|
|
|
|
Z_Free(split->centerprintstring);
|
|
|
|
split->centerprintstring = NULL;
|
|
|
|
}
|
|
|
|
}
|
2005-06-14 04:52:10 +00:00
|
|
|
/*
|
2005-05-26 12:55:34 +00:00
|
|
|
MSG_WriteByte (msg, svc_time);
|
|
|
|
MSG_WriteFloat(msg, sv.physicstime);
|
|
|
|
client->nextservertimeupdate = sv.physicstime;
|
2005-06-14 04:52:10 +00:00
|
|
|
*/
|
2004-08-23 00:15:46 +00:00
|
|
|
|
|
|
|
#ifdef NQPROT
|
2005-05-26 12:55:34 +00:00
|
|
|
if (ISQWCLIENT(client))
|
2004-08-23 00:15:46 +00:00
|
|
|
return;
|
|
|
|
|
|
|
|
ent = client->edict;
|
|
|
|
|
|
|
|
|
2013-03-12 22:35:33 +00:00
|
|
|
if (!(client->fteprotocolextensions2 & PEXT2_REPLACEMENTDELTAS))
|
|
|
|
{
|
|
|
|
MSG_WriteByte (msg, svc_time);
|
|
|
|
MSG_WriteFloat(msg, sv.world.physicstime);
|
2013-03-12 22:53:23 +00:00
|
|
|
|
|
|
|
if (client->fteprotocolextensions2 & PEXT2_PREDINFO)
|
|
|
|
MSG_WriteLong(msg, client->last_sequence);
|
|
|
|
|
2013-03-12 22:35:33 +00:00
|
|
|
// Con_Printf("%f\n", sv.world.physicstime);
|
|
|
|
}
|
2004-08-23 00:15:46 +00:00
|
|
|
|
|
|
|
|
|
|
|
bits = 0;
|
2013-03-12 22:35:33 +00:00
|
|
|
|
2005-03-28 00:11:59 +00:00
|
|
|
if (ent->v->view_ofs[2] != DEFAULT_VIEWHEIGHT)
|
2004-08-23 00:15:46 +00:00
|
|
|
bits |= SU_VIEWHEIGHT;
|
2005-10-23 17:57:20 +00:00
|
|
|
|
2005-03-28 00:11:59 +00:00
|
|
|
// if (ent->v->idealpitch)
|
2004-08-23 00:15:46 +00:00
|
|
|
// bits |= SU_IDEALPITCH;
|
|
|
|
|
|
|
|
// stuff the sigil bits into the high bits of items for sbar, or else
|
|
|
|
// mix in items2
|
|
|
|
// val = GetEdictFieldValue(ent, "items2", &items2cache);
|
|
|
|
|
|
|
|
// if (val)
|
2005-03-28 00:11:59 +00:00
|
|
|
// items = (int)ent->v->items | ((int)val->_float << 23);
|
2004-08-23 00:15:46 +00:00
|
|
|
// else
|
2005-03-28 00:11:59 +00:00
|
|
|
items = (int)ent->v->items | ((int)pr_global_struct->serverflags << 28);
|
2005-10-23 17:57:20 +00:00
|
|
|
|
2004-08-23 00:15:46 +00:00
|
|
|
|
|
|
|
bits |= SU_ITEMS;
|
2005-10-23 17:57:20 +00:00
|
|
|
|
2005-03-28 00:11:59 +00:00
|
|
|
if ( (int)ent->v->flags & FL_ONGROUND)
|
2004-08-23 00:15:46 +00:00
|
|
|
bits |= SU_ONGROUND;
|
2005-10-23 17:57:20 +00:00
|
|
|
|
2005-03-28 00:11:59 +00:00
|
|
|
if ( ent->v->waterlevel >= 2)
|
2004-08-23 00:15:46 +00:00
|
|
|
bits |= SU_INWATER;
|
2005-10-23 17:57:20 +00:00
|
|
|
|
2004-08-23 00:15:46 +00:00
|
|
|
for (i=0 ; i<3 ; i++)
|
|
|
|
{
|
2005-03-28 00:11:59 +00:00
|
|
|
// if (ent->v->punchangle[i])
|
2004-08-23 00:15:46 +00:00
|
|
|
// bits |= (SU_PUNCH1<<i);
|
2005-03-28 00:11:59 +00:00
|
|
|
if (ent->v->velocity[i])
|
2004-08-23 00:15:46 +00:00
|
|
|
bits |= (SU_VELOCITY1<<i);
|
|
|
|
}
|
2005-10-23 17:57:20 +00:00
|
|
|
|
2013-03-12 22:35:33 +00:00
|
|
|
if (client->protocol == SCP_DARKPLACES6 || client->protocol == SCP_DARKPLACES7)
|
|
|
|
{
|
|
|
|
//bits &= ~SU_ITEMS;
|
|
|
|
nqjunk = false;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
nqjunk = true;
|
|
|
|
|
|
|
|
if (ent->v->weaponframe)
|
|
|
|
bits |= SU_WEAPONFRAME;
|
2004-08-23 00:15:46 +00:00
|
|
|
|
2013-03-12 22:35:33 +00:00
|
|
|
if (ent->v->armorvalue)
|
|
|
|
bits |= SU_ARMOR;
|
2004-08-23 00:15:46 +00:00
|
|
|
|
2013-03-12 22:35:33 +00:00
|
|
|
weaponmodelindex = SV_ModelIndex(ent->v->weaponmodel + svprogfuncs->stringtable);
|
2004-08-23 00:15:46 +00:00
|
|
|
|
2013-03-12 22:35:33 +00:00
|
|
|
if (weaponmodelindex)
|
|
|
|
bits |= SU_WEAPONMODEL;
|
|
|
|
|
|
|
|
if (client->protocol == SCP_FITZ666)
|
|
|
|
{
|
|
|
|
if (weaponmodelindex & 0xff00)
|
|
|
|
bits |= FITZSU_WEAPONMODEL2;
|
|
|
|
if ((int)ent->v->armorvalue & 0xff00)
|
|
|
|
bits |= FITZSU_ARMOR2;
|
|
|
|
if ((int)ent->v->currentammo & 0xff00)
|
|
|
|
bits |= FITZSU_AMMO2;
|
|
|
|
if ((int)ent->v->ammo_shells & 0xff00)
|
|
|
|
bits |= FITZSU_SHELLS2;
|
|
|
|
if ((int)ent->v->ammo_nails & 0xff00)
|
|
|
|
bits |= FITZSU_NAILS2;
|
|
|
|
if ((int)ent->v->ammo_rockets & 0xff00)
|
|
|
|
bits |= FITZSU_ROCKETS2;
|
|
|
|
if ((int)ent->v->ammo_cells & 0xff00)
|
|
|
|
bits |= FITZSU_CELLS2;
|
|
|
|
if ((int)ent->v->weaponframe & 0xff00)
|
|
|
|
bits |= FITZSU_WEAPONFRAME2;
|
|
|
|
if (ent->xv->alpha && ent->xv->alpha < 1)
|
|
|
|
bits |= FITZSU_WEAPONALPHA;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (bits >= (1u<<16))
|
2005-06-14 04:52:10 +00:00
|
|
|
bits |= SU_EXTEND1;
|
2013-03-12 22:35:33 +00:00
|
|
|
if (bits >= (1u<<24))
|
2013-03-12 22:36:18 +00:00
|
|
|
bits |= SU_EXTEND2;
|
2013-03-12 22:35:33 +00:00
|
|
|
if (bits >= (1ull<<32))
|
2013-03-12 22:36:18 +00:00
|
|
|
bits |= SU_EXTEND3;
|
2005-06-14 04:52:10 +00:00
|
|
|
|
2004-08-23 00:15:46 +00:00
|
|
|
// send the data
|
|
|
|
|
|
|
|
MSG_WriteByte (msg, svc_clientdata);
|
|
|
|
MSG_WriteShort (msg, bits);
|
|
|
|
|
2013-03-12 22:36:18 +00:00
|
|
|
if (bits & SU_EXTEND1)
|
|
|
|
MSG_WriteByte(msg, bits>>16);
|
|
|
|
if (bits & SU_EXTEND2)
|
|
|
|
MSG_WriteByte(msg, bits>>24);
|
|
|
|
|
2004-08-23 00:15:46 +00:00
|
|
|
if (bits & SU_VIEWHEIGHT)
|
2005-03-28 00:11:59 +00:00
|
|
|
MSG_WriteChar (msg, ent->v->view_ofs[2]);
|
2004-08-23 00:15:46 +00:00
|
|
|
|
|
|
|
// if (bits & SU_IDEALPITCH)
|
2005-03-28 00:11:59 +00:00
|
|
|
// MSG_WriteChar (msg, ent->v->idealpitch);
|
2004-08-23 00:15:46 +00:00
|
|
|
|
|
|
|
for (i=0 ; i<3 ; i++)
|
|
|
|
{
|
|
|
|
// if (bits & (SU_PUNCH1<<i))
|
2005-03-28 00:11:59 +00:00
|
|
|
// MSG_WriteChar (msg, ent->v->punchangle[i]);
|
2004-08-23 00:15:46 +00:00
|
|
|
if (bits & (SU_VELOCITY1<<i))
|
2005-06-14 04:52:10 +00:00
|
|
|
{
|
|
|
|
if (client->protocol == SCP_DARKPLACES6 || client->protocol == SCP_DARKPLACES7)
|
|
|
|
MSG_WriteCoord(msg, ent->v->velocity[i]);
|
|
|
|
else
|
|
|
|
MSG_WriteChar (msg, ent->v->velocity[i]/16);
|
|
|
|
}
|
2004-08-23 00:15:46 +00:00
|
|
|
}
|
|
|
|
|
2005-06-14 04:52:10 +00:00
|
|
|
if (bits & SU_ITEMS)
|
|
|
|
MSG_WriteLong (msg, items);
|
|
|
|
|
2004-08-23 00:15:46 +00:00
|
|
|
if (bits & SU_WEAPONFRAME)
|
2005-03-28 00:11:59 +00:00
|
|
|
MSG_WriteByte (msg, ent->v->weaponframe);
|
2004-08-23 00:15:46 +00:00
|
|
|
if (bits & SU_ARMOR)
|
|
|
|
{
|
2013-03-12 22:35:33 +00:00
|
|
|
if (ent->v->armorvalue>255 && !(bits & FITZSU_ARMOR2))
|
2004-08-23 00:15:46 +00:00
|
|
|
MSG_WriteByte (msg, 255);
|
|
|
|
else
|
2005-03-28 00:11:59 +00:00
|
|
|
MSG_WriteByte (msg, ent->v->armorvalue);
|
2004-08-23 00:15:46 +00:00
|
|
|
}
|
2013-03-12 22:35:33 +00:00
|
|
|
if (bits & SU_WEAPONMODEL)
|
|
|
|
MSG_WriteByte (msg, weaponmodelindex);
|
|
|
|
|
|
|
|
if (nqjunk)
|
2004-08-23 00:15:46 +00:00
|
|
|
{
|
2013-03-12 22:35:33 +00:00
|
|
|
MSG_WriteShort (msg, ent->v->health);
|
|
|
|
MSG_WriteByte (msg, ent->v->currentammo);
|
|
|
|
MSG_WriteByte (msg, ent->v->ammo_shells);
|
|
|
|
MSG_WriteByte (msg, ent->v->ammo_nails);
|
|
|
|
MSG_WriteByte (msg, ent->v->ammo_rockets);
|
|
|
|
MSG_WriteByte (msg, ent->v->ammo_cells);
|
|
|
|
|
|
|
|
if (standard_quake)
|
2004-08-23 00:15:46 +00:00
|
|
|
{
|
2013-03-12 22:35:33 +00:00
|
|
|
MSG_WriteByte (msg, ent->v->weapon);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
for(i=0;i<32;i++)
|
2004-08-23 00:15:46 +00:00
|
|
|
{
|
2013-03-12 22:35:33 +00:00
|
|
|
if ( ((int)ent->v->weapon) & (1<<i) )
|
|
|
|
{
|
|
|
|
MSG_WriteByte (msg, i);
|
|
|
|
break;
|
|
|
|
}
|
2004-08-23 00:15:46 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2013-03-12 22:35:33 +00:00
|
|
|
|
|
|
|
if (bits & FITZSU_WEAPONMODEL2) MSG_WriteByte (msg, weaponmodelindex >> 8);
|
|
|
|
if (bits & FITZSU_ARMOR2) MSG_WriteByte (msg, (int)ent->v->armorvalue >> 8);
|
|
|
|
if (bits & FITZSU_AMMO2) MSG_WriteByte (msg, (int)ent->v->currentammo >> 8);
|
|
|
|
if (bits & FITZSU_SHELLS2) MSG_WriteByte (msg, (int)ent->v->ammo_shells >> 8);
|
|
|
|
if (bits & FITZSU_NAILS2) MSG_WriteByte (msg, (int)ent->v->ammo_nails >> 8);
|
|
|
|
if (bits & FITZSU_ROCKETS2) MSG_WriteByte (msg, (int)ent->v->ammo_rockets >> 8);
|
|
|
|
if (bits & FITZSU_CELLS2) MSG_WriteByte (msg, (int)ent->v->ammo_cells >> 8);
|
|
|
|
if (bits & FITZSU_WEAPONFRAME2) MSG_WriteByte (msg, (int)ent->v->weaponframe >> 8);
|
|
|
|
if (bits & FITZSU_WEAPONALPHA) MSG_WriteByte (msg, ent->xv->alpha*255);
|
|
|
|
|
2004-08-23 00:15:46 +00:00
|
|
|
// }
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2004-10-13 06:36:08 +00:00
|
|
|
typedef struct {
|
2008-11-09 22:29:28 +00:00
|
|
|
int type; //negative means a global.
|
2004-10-13 06:36:08 +00:00
|
|
|
char name[64];
|
2008-11-09 22:29:28 +00:00
|
|
|
union {
|
|
|
|
evalc_t c;
|
|
|
|
eval_t *g; //just store a pointer to it.
|
|
|
|
} eval;
|
2004-10-13 06:36:08 +00:00
|
|
|
int statnum;
|
|
|
|
} qcstat_t;
|
|
|
|
qcstat_t qcstats[MAX_CL_STATS-32];
|
|
|
|
int numqcstats;
|
2008-11-09 22:29:28 +00:00
|
|
|
void SV_QCStatEval(int type, char *name, evalc_t *field, eval_t *global, int statnum)
|
2004-10-13 06:36:08 +00:00
|
|
|
{
|
2005-02-28 07:16:19 +00:00
|
|
|
int i;
|
2004-10-13 06:36:08 +00:00
|
|
|
if (numqcstats == sizeof(qcstats)/sizeof(qcstats[0]))
|
|
|
|
{
|
|
|
|
Con_Printf("Too many stat types\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2005-02-28 07:16:19 +00:00
|
|
|
for (i = 0; i < numqcstats; i++)
|
|
|
|
{
|
|
|
|
if (qcstats[i].statnum == statnum)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (i == numqcstats)
|
2008-01-23 01:31:01 +00:00
|
|
|
{
|
|
|
|
if (i == sizeof(qcstats)/sizeof(qcstats[0]))
|
|
|
|
{
|
|
|
|
Con_Printf("Too many stats specified for csqc\n");
|
|
|
|
return;
|
|
|
|
}
|
2005-02-28 07:16:19 +00:00
|
|
|
numqcstats++;
|
2008-01-23 01:31:01 +00:00
|
|
|
}
|
2005-02-28 07:16:19 +00:00
|
|
|
|
|
|
|
qcstats[i].type = type;
|
|
|
|
qcstats[i].statnum = statnum;
|
|
|
|
Q_strncpyz(qcstats[i].name, name, sizeof(qcstats[i].name));
|
2008-11-09 22:29:28 +00:00
|
|
|
if (type < 0)
|
|
|
|
qcstats[i].eval.g = global;
|
|
|
|
else
|
|
|
|
memcpy(&qcstats[i].eval.c, field, sizeof(evalc_t));
|
|
|
|
}
|
|
|
|
|
|
|
|
void SV_QCStatGlobal(int type, char *globalname, int statnum)
|
|
|
|
{
|
|
|
|
eval_t *glob;
|
|
|
|
|
2010-08-16 02:03:02 +00:00
|
|
|
if (type < 0)
|
|
|
|
return;
|
|
|
|
|
2011-05-20 04:10:46 +00:00
|
|
|
glob = svprogfuncs->FindGlobal(svprogfuncs, globalname, PR_ANY, NULL);
|
2008-11-09 22:29:28 +00:00
|
|
|
if (!glob)
|
|
|
|
{
|
|
|
|
Con_Printf("couldn't find named global for csqc stat (%s)\n", globalname);
|
|
|
|
return;
|
|
|
|
}
|
2010-08-16 02:03:02 +00:00
|
|
|
SV_QCStatEval(-type, globalname, NULL, glob, statnum);
|
|
|
|
}
|
|
|
|
|
|
|
|
void SV_QCStatPtr(int type, void *ptr, int statnum)
|
|
|
|
{
|
|
|
|
SV_QCStatEval(-type, "", NULL, ptr, statnum);
|
2008-01-23 01:31:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void SV_QCStatName(int type, char *name, int statnum)
|
|
|
|
{
|
|
|
|
evalc_t cache;
|
2008-11-09 22:29:28 +00:00
|
|
|
if (type < 0)
|
|
|
|
return;
|
|
|
|
|
2008-05-31 10:35:38 +00:00
|
|
|
memset(&cache, 0, sizeof(cache));
|
2008-01-23 01:31:01 +00:00
|
|
|
if (!svprogfuncs->GetEdictFieldValue(svprogfuncs, NULL, name, &cache))
|
|
|
|
return;
|
|
|
|
|
2008-11-09 22:29:28 +00:00
|
|
|
SV_QCStatEval(type, name, &cache, NULL, statnum);
|
2008-01-23 01:31:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void SV_QCStatFieldIdx(int type, unsigned int fieldindex, int statnum)
|
|
|
|
{
|
|
|
|
evalc_t cache;
|
|
|
|
char *name;
|
|
|
|
etype_t ftype;
|
|
|
|
|
2008-11-09 22:29:28 +00:00
|
|
|
if (type < 0)
|
|
|
|
return;
|
|
|
|
|
2008-01-23 01:31:01 +00:00
|
|
|
if (!svprogfuncs->QueryField(svprogfuncs, fieldindex, &ftype, &name, &cache))
|
|
|
|
{
|
|
|
|
Con_Printf("invalid field for csqc stat\n");
|
|
|
|
return;
|
|
|
|
}
|
2008-11-09 22:29:28 +00:00
|
|
|
SV_QCStatEval(type, name, &cache, NULL, statnum);
|
2004-10-13 06:36:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void SV_ClearQCStats(void)
|
|
|
|
{
|
|
|
|
numqcstats = 0;
|
|
|
|
}
|
|
|
|
|
2011-05-20 04:10:46 +00:00
|
|
|
extern cvar_t dpcompat_stats;
|
2008-05-25 22:23:43 +00:00
|
|
|
void SV_UpdateQCStats(edict_t *ent, int *statsi, char **statss, float *statsf)
|
2004-10-13 06:36:08 +00:00
|
|
|
{
|
|
|
|
char *s;
|
|
|
|
int i;
|
2008-11-09 22:29:28 +00:00
|
|
|
int t;
|
2004-10-13 06:36:08 +00:00
|
|
|
|
|
|
|
for (i = 0; i < numqcstats; i++)
|
|
|
|
{
|
|
|
|
eval_t *eval;
|
2008-11-09 22:29:28 +00:00
|
|
|
t = qcstats[i].type;
|
|
|
|
if (t < 0)
|
|
|
|
{
|
|
|
|
t = -t;
|
|
|
|
eval = qcstats[i].eval.g;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
eval = svprogfuncs->GetEdictFieldValue(svprogfuncs, ent, qcstats[i].name, &qcstats[i].eval.c);
|
|
|
|
}
|
2008-01-23 01:31:01 +00:00
|
|
|
if (!eval)
|
|
|
|
continue;
|
2004-10-13 06:36:08 +00:00
|
|
|
|
2008-11-09 22:29:28 +00:00
|
|
|
switch(t)
|
2004-10-13 06:36:08 +00:00
|
|
|
{
|
|
|
|
case ev_float:
|
2008-05-25 22:23:43 +00:00
|
|
|
statsf[qcstats[i].statnum] = eval->_float;
|
2004-10-13 06:36:08 +00:00
|
|
|
break;
|
2011-05-20 04:10:46 +00:00
|
|
|
case ev_vector:
|
|
|
|
statsf[qcstats[i].statnum+0] = eval->_vector[0];
|
|
|
|
statsf[qcstats[i].statnum+1] = eval->_vector[1];
|
|
|
|
statsf[qcstats[i].statnum+2] = eval->_vector[2];
|
|
|
|
break;
|
2004-10-13 06:36:08 +00:00
|
|
|
case ev_integer:
|
2008-05-25 22:23:43 +00:00
|
|
|
statsi[qcstats[i].statnum] = eval->_int;
|
2004-10-13 06:36:08 +00:00
|
|
|
break;
|
|
|
|
case ev_entity:
|
2008-05-25 22:23:43 +00:00
|
|
|
statsi[qcstats[i].statnum] = NUM_FOR_EDICT(svprogfuncs, PROG_TO_EDICT(svprogfuncs, eval->edict));
|
2004-10-13 06:36:08 +00:00
|
|
|
break;
|
|
|
|
case ev_string:
|
|
|
|
s = PR_GetString(svprogfuncs, eval->string);
|
2008-05-25 22:23:43 +00:00
|
|
|
statss[qcstats[i].statnum] = s;
|
|
|
|
// statsi[qcstats[i].statnum+0] = LittleLong(((int*)s)[0]); //so the network is sent out correctly as a string.
|
|
|
|
// statsi[qcstats[i].statnum+1] = LittleLong(((int*)s)[1]);
|
|
|
|
// statsi[qcstats[i].statnum+2] = LittleLong(((int*)s)[2]);
|
|
|
|
// statsi[qcstats[i].statnum+3] = LittleLong(((int*)s)[3]);
|
2004-10-13 06:36:08 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-08-16 04:12:15 +00:00
|
|
|
/*this function calculates the current stat values for the given client*/
|
|
|
|
void SV_CalcClientStats(client_t *client, int statsi[MAX_CL_STATS], float statsf[MAX_CL_STATS], char *statss[MAX_CL_STATS])
|
2004-08-23 00:15:46 +00:00
|
|
|
{
|
|
|
|
extern qboolean pr_items2;
|
2011-08-16 04:12:15 +00:00
|
|
|
edict_t *ent;
|
2004-08-23 00:15:46 +00:00
|
|
|
ent = client->edict;
|
2011-08-16 04:12:15 +00:00
|
|
|
memset (statsi, 0, sizeof(int)*MAX_CL_STATS);
|
|
|
|
memset (statsf, 0, sizeof(float)*MAX_CL_STATS);
|
|
|
|
memset (statss, 0, sizeof(char*)*MAX_CL_STATS);
|
2005-10-23 17:57:20 +00:00
|
|
|
|
2004-08-23 00:15:46 +00:00
|
|
|
// 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)
|
2013-05-09 02:18:15 +00:00
|
|
|
ent = EDICT_NUM(svprogfuncs, client->spec_track);
|
2004-08-23 00:15:46 +00:00
|
|
|
|
2009-03-03 01:52:30 +00:00
|
|
|
#ifdef HLSERVER
|
|
|
|
if (svs.gametype == GT_HALFLIFE)
|
2005-10-19 21:11:05 +00:00
|
|
|
{
|
2009-03-03 01:52:30 +00:00
|
|
|
SVHL_BuildStats(client, statsi, statsf, statss);
|
2005-10-19 21:11:05 +00:00
|
|
|
}
|
|
|
|
else
|
2009-03-03 01:52:30 +00:00
|
|
|
#endif
|
2005-10-19 21:11:05 +00:00
|
|
|
{
|
2009-03-03 01:52:30 +00:00
|
|
|
statsf[STAT_HEALTH] = ent->v->health; //sorry, but mneh
|
|
|
|
statsi[STAT_WEAPON] = SV_ModelIndex(PR_GetString(svprogfuncs, ent->v->weaponmodel));
|
2011-08-16 04:12:15 +00:00
|
|
|
if (client->fteprotocolextensions & PEXT_MODELDBL)
|
2009-03-03 01:52:30 +00:00
|
|
|
{
|
2011-07-30 14:14:56 +00:00
|
|
|
if ((unsigned)statsi[STAT_WEAPON] >= MAX_MODELS)
|
2009-03-03 01:52:30 +00:00
|
|
|
statsi[STAT_WEAPON] = 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if ((unsigned)statsi[STAT_WEAPON] >= 256)
|
|
|
|
statsi[STAT_WEAPON] = 0;
|
|
|
|
}
|
|
|
|
statsf[STAT_AMMO] = ent->v->currentammo;
|
|
|
|
statsf[STAT_ARMOR] = ent->v->armorvalue;
|
|
|
|
statsf[STAT_SHELLS] = ent->v->ammo_shells;
|
|
|
|
statsf[STAT_NAILS] = ent->v->ammo_nails;
|
|
|
|
statsf[STAT_ROCKETS] = ent->v->ammo_rockets;
|
|
|
|
statsf[STAT_CELLS] = ent->v->ammo_cells;
|
|
|
|
if (!client->spectator)
|
|
|
|
{
|
2012-02-12 05:18:31 +00:00
|
|
|
statsf[STAT_ACTIVEWEAPON] = ent->v->weapon;
|
2012-02-14 15:50:34 +00:00
|
|
|
if ((client->csqcactive && !(client->fteprotocolextensions2 & PEXT2_REPLACEMENTDELTAS)) || client->protocol != SCP_QUAKEWORLD)
|
2012-02-12 05:18:31 +00:00
|
|
|
statsf[STAT_WEAPONFRAME] = ent->v->weaponframe;
|
2009-03-03 01:52:30 +00:00
|
|
|
}
|
2004-08-23 00:15:46 +00:00
|
|
|
|
2009-03-03 01:52:30 +00:00
|
|
|
// stuff the sigil bits into the high bits of items for sbar
|
|
|
|
if (pr_items2)
|
|
|
|
statsi[STAT_ITEMS] = (int)ent->v->items | ((int)ent->xv->items2 << 23);
|
|
|
|
else
|
|
|
|
statsi[STAT_ITEMS] = (int)ent->v->items | ((int)pr_global_struct->serverflags << 28);
|
2004-08-23 00:15:46 +00:00
|
|
|
|
2009-03-03 01:52:30 +00:00
|
|
|
statsf[STAT_VIEWHEIGHT] = ent->v->view_ofs[2];
|
|
|
|
#ifdef PEXT_VIEW2
|
|
|
|
if (ent->xv->view2)
|
|
|
|
statsi[STAT_VIEW2] = NUM_FOR_EDICT(svprogfuncs, PROG_TO_EDICT(svprogfuncs, ent->xv->view2));
|
|
|
|
else
|
|
|
|
statsi[STAT_VIEW2] = 0;
|
|
|
|
#endif
|
2005-06-14 04:52:10 +00:00
|
|
|
|
2009-03-03 01:52:30 +00:00
|
|
|
if (!ent->xv->viewzoom)
|
|
|
|
statsi[STAT_VIEWZOOM] = 255;
|
|
|
|
else
|
|
|
|
statsi[STAT_VIEWZOOM] = ent->xv->viewzoom*255;
|
2007-06-10 05:14:38 +00:00
|
|
|
|
2013-03-12 22:53:23 +00:00
|
|
|
if (client->fteprotocolextensions2 & PEXT2_PREDINFO)
|
|
|
|
{
|
|
|
|
statsf[STAT_MOVEVARS_GRAVITY] = sv_gravity.value;
|
|
|
|
statsf[STAT_MOVEVARS_ENTGRAVITY] = host_client->entgravity;
|
|
|
|
statsf[STAT_MOVEVARS_MAXSPEED] = host_client->maxspeed;
|
|
|
|
}
|
2011-08-16 04:12:15 +00:00
|
|
|
if (client->protocol == SCP_DARKPLACES7)
|
2009-03-03 01:52:30 +00:00
|
|
|
{
|
2012-02-12 05:18:31 +00:00
|
|
|
/*note: statsf is truncated, which would mess things up*/
|
2009-03-03 01:52:30 +00:00
|
|
|
float *statsfi = (float*)statsi;
|
|
|
|
// statsfi[STAT_MOVEVARS_WALLFRICTION] = sv_wall
|
|
|
|
statsfi[STAT_MOVEVARS_FRICTION] = sv_friction.value;
|
|
|
|
statsfi[STAT_MOVEVARS_WATERFRICTION] = sv_waterfriction.value;
|
|
|
|
statsfi[STAT_MOVEVARS_TICRATE] = 72;
|
|
|
|
statsfi[STAT_MOVEVARS_TIMESCALE] = sv_gamespeed.value;
|
|
|
|
statsfi[STAT_MOVEVARS_GRAVITY] = sv_gravity.value;
|
|
|
|
statsfi[STAT_MOVEVARS_STOPSPEED] = sv_stopspeed.value;
|
|
|
|
statsfi[STAT_MOVEVARS_MAXSPEED] = host_client->maxspeed;
|
|
|
|
statsfi[STAT_MOVEVARS_SPECTATORMAXSPEED] = sv_spectatormaxspeed.value;
|
|
|
|
statsfi[STAT_MOVEVARS_ACCELERATE] = sv_accelerate.value;
|
|
|
|
statsfi[STAT_MOVEVARS_AIRACCELERATE] = sv_airaccelerate.value;
|
|
|
|
statsfi[STAT_MOVEVARS_WATERACCELERATE] = sv_wateraccelerate.value;
|
|
|
|
statsfi[STAT_MOVEVARS_ENTGRAVITY] = host_client->entgravity;
|
2013-03-12 22:53:23 +00:00
|
|
|
statsfi[STAT_MOVEVARS_JUMPVELOCITY] = 270;//sv_jumpvelocity.value; //bah
|
2009-03-03 01:52:30 +00:00
|
|
|
statsfi[STAT_MOVEVARS_EDGEFRICTION] = sv_edgefriction.value;
|
|
|
|
statsfi[STAT_MOVEVARS_MAXAIRSPEED] = host_client->maxspeed;
|
|
|
|
statsfi[STAT_MOVEVARS_STEPHEIGHT] = 18;
|
|
|
|
statsfi[STAT_MOVEVARS_AIRACCEL_QW] = 1;
|
|
|
|
statsfi[STAT_MOVEVARS_AIRACCEL_SIDEWAYS_FRICTION] = sv_gravity.value;
|
|
|
|
}
|
2004-10-10 06:32:29 +00:00
|
|
|
|
2009-03-03 01:52:30 +00:00
|
|
|
SV_UpdateQCStats(ent, statsi, statss, statsf);
|
|
|
|
}
|
2011-08-16 04:12:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
=======================
|
|
|
|
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, int pnum)
|
|
|
|
{
|
|
|
|
int statsi[MAX_CL_STATS];
|
|
|
|
float statsf[MAX_CL_STATS];
|
|
|
|
char *statss[MAX_CL_STATS];
|
|
|
|
int i, m;
|
|
|
|
|
|
|
|
/*figure out what the stat values should be*/
|
|
|
|
SV_CalcClientStats(client, statsi, statsf, statss);
|
|
|
|
|
2004-08-23 00:15:46 +00:00
|
|
|
m = MAX_QW_STATS;
|
2011-09-03 03:49:43 +00:00
|
|
|
if (client->fteprotocolextensions & (PEXT_HEXEN2|PEXT_CSQC))
|
2004-08-23 00:15:46 +00:00
|
|
|
m = MAX_CL_STATS;
|
|
|
|
|
|
|
|
for (i=0 ; i<m ; i++)
|
|
|
|
{
|
2009-11-07 13:29:15 +00:00
|
|
|
#ifdef SERVER_DEMO_PLAYBACK
|
2004-08-23 00:15:46 +00:00
|
|
|
if (sv.demofile)
|
|
|
|
{
|
|
|
|
if (!client->spec_track)
|
|
|
|
{
|
2008-05-25 22:23:43 +00:00
|
|
|
statsf[i] = 0;
|
2004-08-23 00:15:46 +00:00
|
|
|
if (i == STAT_HEALTH)
|
2008-05-25 22:23:43 +00:00
|
|
|
statsf[i] = 100;
|
2004-08-23 00:15:46 +00:00
|
|
|
}
|
|
|
|
else
|
2008-05-25 22:23:43 +00:00
|
|
|
{
|
|
|
|
statsf[i] = sv.recordedplayer[client->spec_track - 1].stats[i];
|
|
|
|
statsi[i] = sv.recordedplayer[client->spec_track - 1].stats[i];
|
|
|
|
}
|
2004-08-23 00:15:46 +00:00
|
|
|
}
|
2009-11-07 13:29:15 +00:00
|
|
|
#endif
|
2008-05-25 22:23:43 +00:00
|
|
|
if (!ISQWCLIENT(client))
|
2004-08-23 00:15:46 +00:00
|
|
|
{
|
2008-05-25 22:23:43 +00:00
|
|
|
if (!statsi[i])
|
2008-11-09 22:29:28 +00:00
|
|
|
statsi[i] = statsf[i];
|
2008-05-25 22:23:43 +00:00
|
|
|
if (statsi[i] != client->statsi[i])
|
2004-08-23 00:15:46 +00:00
|
|
|
{
|
2008-05-25 22:23:43 +00:00
|
|
|
client->statsi[i] = statsi[i];
|
2012-09-30 05:52:03 +00:00
|
|
|
ClientReliableWrite_Begin(client, svcnq_updatestatlong, 6);
|
2004-08-23 00:15:46 +00:00
|
|
|
ClientReliableWrite_Byte(client, i);
|
2008-05-25 22:23:43 +00:00
|
|
|
ClientReliableWrite_Long(client, statsi[i]);
|
2005-05-26 12:55:34 +00:00
|
|
|
}
|
2008-05-25 22:23:43 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2009-07-18 20:46:42 +00:00
|
|
|
#ifdef PEXT_CSQC
|
2011-06-04 16:11:35 +00:00
|
|
|
if (client->fteprotocolextensions & PEXT_CSQC)
|
2008-05-25 22:23:43 +00:00
|
|
|
{
|
|
|
|
if (statss[i] || client->statss[i])
|
|
|
|
if (strcmp(statss[i]?statss[i]:"", client->statss[i]?client->statss[i]:""))
|
|
|
|
{
|
|
|
|
client->statss[i] = statss[i];
|
|
|
|
if (pnum)
|
|
|
|
{
|
|
|
|
ClientReliableWrite_Begin(client->controller, svcfte_choosesplitclient, 5+strlen(statss[i]));
|
|
|
|
ClientReliableWrite_Byte(client->controller, pnum);
|
|
|
|
ClientReliableWrite_Byte(client->controller, svcfte_updatestatstring);
|
2008-11-28 20:34:51 +00:00
|
|
|
ClientReliableWrite_Byte(client->controller, i);
|
|
|
|
ClientReliableWrite_String(client->controller, statss[i]);
|
2008-05-25 22:23:43 +00:00
|
|
|
}
|
|
|
|
else
|
2008-11-28 20:34:51 +00:00
|
|
|
{
|
2008-05-25 22:23:43 +00:00
|
|
|
ClientReliableWrite_Begin(client, svcfte_updatestatstring, 3+strlen(statss[i]));
|
2008-11-28 20:34:51 +00:00
|
|
|
ClientReliableWrite_Byte(client, i);
|
|
|
|
ClientReliableWrite_String(client, statss[i]);
|
|
|
|
}
|
2008-05-25 22:23:43 +00:00
|
|
|
}
|
|
|
|
}
|
2011-05-20 04:10:46 +00:00
|
|
|
if (dpcompat_stats.ival)
|
|
|
|
{
|
|
|
|
if (statsf[i])
|
|
|
|
{
|
|
|
|
statsi[i] = statsf[i];
|
|
|
|
statsf[i] = 0;
|
|
|
|
}
|
|
|
|
}
|
2009-07-18 20:46:42 +00:00
|
|
|
#endif
|
2011-05-20 04:10:46 +00:00
|
|
|
|
|
|
|
if (statsf[i])
|
|
|
|
{
|
2011-06-04 16:11:35 +00:00
|
|
|
if (client->fteprotocolextensions & PEXT_CSQC)
|
2011-05-20 04:10:46 +00:00
|
|
|
{
|
2011-06-04 16:11:35 +00:00
|
|
|
if (statsf[i] != client->statsf[i])
|
2011-05-20 04:10:46 +00:00
|
|
|
{
|
2011-06-04 16:11:35 +00:00
|
|
|
if (statsf[i] - (float)(int)statsf[i] == 0 && statsf[i] >= 0 && statsf[i] <= 255)
|
2011-05-20 04:10:46 +00:00
|
|
|
{
|
2011-06-04 16:11:35 +00:00
|
|
|
if (pnum)
|
|
|
|
{
|
|
|
|
ClientReliableWrite_Begin(client->controller, svcfte_choosesplitclient, 5);
|
|
|
|
ClientReliableWrite_Byte(client->controller, pnum);
|
2012-09-30 05:52:03 +00:00
|
|
|
ClientReliableWrite_Byte(client->controller, svcqw_updatestatbyte);
|
2011-06-04 16:11:35 +00:00
|
|
|
ClientReliableWrite_Byte(client->controller, i);
|
|
|
|
ClientReliableWrite_Byte(client->controller, statsf[i]);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2012-09-30 05:52:03 +00:00
|
|
|
ClientReliableWrite_Begin(client, svcqw_updatestatbyte, 3);
|
2011-06-04 16:11:35 +00:00
|
|
|
ClientReliableWrite_Byte(client, i);
|
|
|
|
ClientReliableWrite_Byte(client, statsf[i]);
|
|
|
|
}
|
2011-05-20 04:10:46 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2011-06-04 16:11:35 +00:00
|
|
|
if (pnum)
|
|
|
|
{
|
|
|
|
ClientReliableWrite_Begin(client->controller, svcfte_choosesplitclient, 8);
|
|
|
|
ClientReliableWrite_Byte(client->controller, pnum);
|
|
|
|
ClientReliableWrite_Byte(client->controller, svcfte_updatestatfloat);
|
|
|
|
ClientReliableWrite_Byte(client->controller, i);
|
|
|
|
ClientReliableWrite_Float(client->controller, statsf[i]);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ClientReliableWrite_Begin(client, svcfte_updatestatfloat, 6);
|
|
|
|
ClientReliableWrite_Byte(client, i);
|
|
|
|
ClientReliableWrite_Float(client, statsf[i]);
|
|
|
|
}
|
2011-05-20 04:10:46 +00:00
|
|
|
}
|
2011-06-04 16:11:35 +00:00
|
|
|
client->statsf[i] = statsf[i];
|
|
|
|
/*make sure statsf is correct*/
|
|
|
|
client->statsi[i] = statsf[i];
|
2011-05-20 04:10:46 +00:00
|
|
|
}
|
2011-06-05 01:36:14 +00:00
|
|
|
continue;
|
2011-06-04 16:11:35 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
statsi[i] = statsf[i];
|
2011-05-20 04:10:46 +00:00
|
|
|
}
|
|
|
|
}
|
2011-06-04 16:11:35 +00:00
|
|
|
if (statsi[i] != client->statsi[i])
|
2004-08-23 00:15:46 +00:00
|
|
|
{
|
2008-05-25 22:23:43 +00:00
|
|
|
client->statsi[i] = statsi[i];
|
2011-05-20 04:10:46 +00:00
|
|
|
client->statsf[i] = statsi[i];
|
2008-05-25 22:23:43 +00:00
|
|
|
|
|
|
|
if (statsi[i] >=0 && statsi[i] <= 255)
|
|
|
|
{
|
2008-11-28 20:34:51 +00:00
|
|
|
if (pnum)
|
|
|
|
{
|
|
|
|
ClientReliableWrite_Begin(client->controller, svcfte_choosesplitclient, 5);
|
|
|
|
ClientReliableWrite_Byte(client->controller, pnum);
|
2012-09-30 05:52:03 +00:00
|
|
|
ClientReliableWrite_Byte(client->controller, svcqw_updatestatbyte);
|
2008-11-28 20:34:51 +00:00
|
|
|
ClientReliableWrite_Byte(client->controller, i);
|
|
|
|
ClientReliableWrite_Byte(client->controller, statsi[i]);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2012-09-30 05:52:03 +00:00
|
|
|
ClientReliableWrite_Begin(client, svcqw_updatestatbyte, 3);
|
2008-11-28 20:34:51 +00:00
|
|
|
ClientReliableWrite_Byte(client, i);
|
|
|
|
ClientReliableWrite_Byte(client, statsi[i]);
|
|
|
|
}
|
2004-08-23 00:15:46 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2008-11-28 20:34:51 +00:00
|
|
|
if (pnum)
|
|
|
|
{
|
|
|
|
ClientReliableWrite_Begin(client->controller, svcfte_choosesplitclient, 8);
|
|
|
|
ClientReliableWrite_Byte(client->controller, pnum);
|
2012-09-30 05:52:03 +00:00
|
|
|
ClientReliableWrite_Byte(client->controller, svcqw_updatestatlong);
|
2008-11-28 20:34:51 +00:00
|
|
|
ClientReliableWrite_Byte(client->controller, i);
|
|
|
|
ClientReliableWrite_Long(client->controller, statsi[i]);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2012-09-30 05:52:03 +00:00
|
|
|
ClientReliableWrite_Begin(client, svcqw_updatestatlong, 6);
|
2008-11-28 20:34:51 +00:00
|
|
|
ClientReliableWrite_Byte(client, i);
|
|
|
|
ClientReliableWrite_Long(client, statsi[i]);
|
|
|
|
}
|
2004-08-23 00:15:46 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-05-09 02:18:15 +00:00
|
|
|
qboolean SV_CanTrack(client_t *client, int entity)
|
|
|
|
{
|
|
|
|
if (entity < 0 || entity > sv.allocated_client_slots || svs.clients[entity-1].state != cs_spawned || svs.clients[entity-1].spectator)
|
|
|
|
return false;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2004-08-23 00:15:46 +00:00
|
|
|
/*
|
|
|
|
=======================
|
|
|
|
SV_SendClientDatagram
|
|
|
|
=======================
|
|
|
|
*/
|
|
|
|
qboolean SV_SendClientDatagram (client_t *client)
|
|
|
|
{
|
2012-02-12 05:18:31 +00:00
|
|
|
qbyte buf[MAX_OVERALLMSGLEN];
|
2004-08-23 00:15:46 +00:00
|
|
|
sizebuf_t msg;
|
2009-06-23 21:49:44 +00:00
|
|
|
unsigned int sentbytes, fnum;
|
2004-08-23 00:15:46 +00:00
|
|
|
|
|
|
|
msg.data = buf;
|
|
|
|
msg.maxsize = sizeof(buf);
|
|
|
|
msg.cursize = 0;
|
|
|
|
msg.allowoverflow = true;
|
|
|
|
msg.overflowed = false;
|
Fixes, workarounds, and breakages. Hexen2 should work much better (-hexen2 says no mission pack, -portals says h2mp). Started working on splitting bigcoords per client, far too much work still to go on that. Removed gl_ztrick entirely. Enabled csprogs download by default. Added client support for fitzquake's 666 protocol, needs testing, some cleanup for dp protocols too, no server support, couldn't selectively enable it anyway. Now attempting to cache shadow meshes for explosions and stuff. Played with lightmaps a little, should potentially run a little faster on certain (intel?) cards. Tweeked npfte a little to try to avoid deadlocks and crashes. Fixed sky worldspawn parsing. Added h2mp's model format. Fixed baseline issue in q2 client, made servers generate q2 baselines. MOVETYPE_PUSH will not rotate extra if rotation is forced. Made status command show allowed client types. Changed lighting on weapons - should now be shaded.
git-svn-id: https://svn.code.sf.net/p/fteqw/code/branches/wip@3572 fc73d0e0-1445-4013-8a0c-d673dee63da5
2010-08-11 03:36:31 +00:00
|
|
|
msg.prim = client->datagram.prim;
|
2004-08-23 00:15:46 +00:00
|
|
|
|
2013-05-09 02:18:15 +00:00
|
|
|
if (client->spec_track && !SV_CanTrack(client, client->spec_track))
|
|
|
|
{
|
|
|
|
client->spec_track = 0;
|
|
|
|
client->edict->v->goalentity = 0;
|
|
|
|
}
|
|
|
|
|
------------------------------------------------------------------------
r4169 | acceptthis | 2013-01-17 08:55:12 +0000 (Thu, 17 Jan 2013) | 31 lines
removed MAX_VISEDICTS limit.
PEXT2_REPLACEMENTDELTAS tweaked, now has 4 million entity limit. still not enabled by default.
TE_BEAM now maps to a separate TEQW_BEAM to avoid conflicts with QW.
added android multitouch emulation for windows/rawinput (in_simulatemultitouch).
split topcolor/bottomcolor from scoreboard, for dp's colormap|1024 feature.
now using utf-8 for windows consoles.
qcc warnings/errors now give clickable console links for quick+easy editing.
disabled menutint when the currently active item changes contrast or gamma (for OneManClan).
Added support for drawfont/drawfontscale.
tweaked the qcvm a little to reduce the number of pointers.
.doll file loading. still experimental and will likely crash. requires csqc active, even if its a dummy progs. this will be fixed in time. Still other things that need cleaning up.
windows: gl_font "?" shows the standard windows font-selection dialog, and can be used to select windows fonts. not all work. and you probably don't want to use windings.
fixed splitscreen support when playing mvds. added mini-scoreboards to splitscreen.
editor/debugger now shows asm if there's no linenumber info. also, pressing f1 for help shows the shortcuts.
Added support for .framegroups files for psk(psa) and iqm formats.
True support for ezquake's colour codes. Mutually exclusive with background colours.
path command output slightly more readable.
added support for digest_hex (MD4, SHA1, CRC16).
skingroups now colourmap correctly.
Fix terrain colour hints, and litdata from the wrong bsp.
fix ftp dual-homed issue. support epsv command, and enable ipv6 (eprt still not supported).
remove d3d11 compilation from the makefile. the required headers are not provided by mingw, and are not available to the build bot, so don't bother.
fix v *= v.x and similar opcodes.
fteqcc: fixed support for áéÃóú type chars in names. utf-8 files now properly supported (even with the utf-8 bom/identifier). utf-16 also supported.
fteqcc: fixed '#if 1 == 3 && 4' parsing.
fteqcc: -Werror acts on the warning, rather than as a separate error. Line numbers are thus more readable.
fteqcc: copyright message now includes compile date instead.
fteqccgui: the treeview control is now coloured depending on whether there were warnings/errors in the last compile.
fteqccgui: the output window is now focused and scrolls down as compilation progresses.
pr_dumpplatform command dumps out some pragmas to convert more serious warnings to errors. This is to avoid the infamous 'fteqcc sucks cos my code sucks' issue.
rewrote prespawn/modelist/soundlist code. server tracks progress now.
------------------------------------------------------------------------
git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@4167 fc73d0e0-1445-4013-8a0c-d673dee63da5
2013-03-12 22:29:40 +00:00
|
|
|
if (client->protocol != SCP_FITZ666 && !client->netchan.fragmentsize)
|
2012-02-12 05:18:31 +00:00
|
|
|
msg.maxsize = MAX_DATAGRAM;
|
|
|
|
|
2009-11-04 21:16:50 +00:00
|
|
|
if (sv.world.worldmodel && !client->controller)
|
2004-08-23 00:15:46 +00:00
|
|
|
{
|
2005-05-26 12:55:34 +00:00
|
|
|
if (ISQ2CLIENT(client))
|
2004-08-23 00:15:46 +00:00
|
|
|
{
|
2012-02-12 05:18:31 +00:00
|
|
|
SVQ2_BuildClientFrame (client);
|
2004-08-23 00:15:46 +00:00
|
|
|
|
|
|
|
// send over all the relevant entity_state_t
|
|
|
|
// and the player_state_t
|
2012-02-12 05:18:31 +00:00
|
|
|
SVQ2_WriteFrameToClient (client, &msg);
|
2004-08-23 00:15:46 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// 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, false);
|
|
|
|
}
|
2011-09-05 01:48:23 +00:00
|
|
|
#ifdef VOICECHAT
|
2010-11-15 02:40:31 +00:00
|
|
|
SV_VoiceSendPacket(client, &msg);
|
|
|
|
#endif
|
2004-08-23 00:15:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// 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
|
2009-11-04 21:16:50 +00:00
|
|
|
if (sv.world.worldmodel)
|
2005-05-26 12:55:34 +00:00
|
|
|
if (!ISQ2CLIENT(client) && Netchan_CanReliable (&client->netchan, SV_RateForClient(client)))
|
2004-08-23 00:15:46 +00:00
|
|
|
{
|
|
|
|
int pnum=1;
|
|
|
|
client_t *c;
|
|
|
|
SV_UpdateClientStats (client, 0);
|
|
|
|
|
|
|
|
for (c = client->controlled; c; c = c->controlled,pnum++)
|
|
|
|
SV_UpdateClientStats(c, pnum);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (msg.overflowed)
|
|
|
|
{
|
|
|
|
Con_Printf ("WARNING: msg overflowed for %s\n", client->name);
|
|
|
|
SZ_Clear (&msg);
|
|
|
|
}
|
|
|
|
|
2007-06-20 00:02:54 +00:00
|
|
|
SV_DarkPlacesDownloadChunk(client, &msg);
|
|
|
|
|
2004-08-23 00:15:46 +00:00
|
|
|
// send the datagram
|
2009-06-23 21:49:44 +00:00
|
|
|
fnum = client->netchan.outgoing_sequence;
|
|
|
|
sentbytes = Netchan_Transmit (&client->netchan, msg.cursize, buf, SV_RateForClient(client));
|
2004-08-23 00:15:46 +00:00
|
|
|
|
2009-08-08 12:43:35 +00:00
|
|
|
if (ISQWCLIENT(client) || ISNQCLIENT(client))
|
2009-06-23 21:49:44 +00:00
|
|
|
client->frameunion.frames[fnum & UPDATE_MASK].packetsizeout += sentbytes;
|
2004-08-23 00:15:46 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2005-03-04 13:30:30 +00:00
|
|
|
client_t *SV_SplitClientDest(client_t *client, qbyte first, int size)
|
|
|
|
{
|
|
|
|
client_t *sp;
|
|
|
|
if (client->controller)
|
|
|
|
{ //this is a slave client.
|
|
|
|
//find the right number and send.
|
|
|
|
int pnum = 0;
|
|
|
|
for (sp = client->controller; sp; sp = sp->controlled)
|
|
|
|
{
|
|
|
|
if (sp == client)
|
|
|
|
break;
|
|
|
|
pnum++;
|
|
|
|
}
|
|
|
|
sp = client->controller;
|
|
|
|
|
2008-05-25 22:23:43 +00:00
|
|
|
ClientReliableWrite_Begin (sp, svcfte_choosesplitclient, size+2);
|
2005-03-04 13:30:30 +00:00
|
|
|
ClientReliableWrite_Byte (sp, pnum);
|
|
|
|
ClientReliableWrite_Byte (sp, first);
|
|
|
|
return sp;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ClientReliableWrite_Begin (client, first, size);
|
|
|
|
return client;
|
|
|
|
}
|
2005-10-23 17:57:20 +00:00
|
|
|
}
|
2012-05-09 15:30:53 +00:00
|
|
|
|
|
|
|
void SV_FlushBroadcasts (void)
|
|
|
|
{
|
|
|
|
client_t *client;
|
|
|
|
int j;
|
|
|
|
// 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
|
|
|
|
if (client->controller)
|
|
|
|
continue; //splitscreen
|
|
|
|
|
|
|
|
if (client->protocol == SCP_BAD)
|
|
|
|
continue; //botclient
|
|
|
|
|
|
|
|
#ifdef Q2SERVER
|
|
|
|
if (ISQ2CLIENT(client))
|
|
|
|
{
|
|
|
|
ClientReliableCheckBlock(client, sv.q2reliable_datagram.cursize);
|
|
|
|
ClientReliableWrite_SZ(client, sv.q2reliable_datagram.data, sv.q2reliable_datagram.cursize);
|
|
|
|
|
|
|
|
if (client->state != cs_spawned)
|
|
|
|
continue; // datagrams only go to spawned
|
|
|
|
SZ_Write (&client->datagram
|
|
|
|
, sv.q2datagram.data
|
|
|
|
, sv.q2datagram.cursize);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
#endif
|
|
|
|
#ifdef NQPROT
|
|
|
|
if (!ISQWCLIENT(client))
|
|
|
|
{
|
|
|
|
if (client->pextknown)
|
|
|
|
{
|
|
|
|
ClientReliableCheckBlock(client, sv.nqreliable_datagram.cursize);
|
|
|
|
ClientReliableWrite_SZ(client, sv.nqreliable_datagram.data, sv.nqreliable_datagram.cursize);
|
|
|
|
}
|
|
|
|
if (client->state != cs_spawned)
|
|
|
|
continue; // datagrams only go to spawned
|
|
|
|
SZ_Write (&client->datagram
|
|
|
|
, sv.nqdatagram.data
|
|
|
|
, sv.nqdatagram.cursize);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
#endif
|
|
|
|
{
|
|
|
|
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 NQPROT
|
|
|
|
SZ_Clear (&sv.nqreliable_datagram);
|
|
|
|
SZ_Clear (&sv.nqdatagram);
|
|
|
|
#endif
|
|
|
|
SZ_Clear (&sv.q2reliable_datagram);
|
|
|
|
SZ_Clear (&sv.q2datagram);
|
|
|
|
}
|
|
|
|
|
2004-08-23 00:15:46 +00:00
|
|
|
/*
|
|
|
|
=======================
|
|
|
|
SV_UpdateToReliableMessages
|
|
|
|
=======================
|
|
|
|
*/
|
|
|
|
void SV_UpdateToReliableMessages (void)
|
|
|
|
{
|
|
|
|
int i, j;
|
2005-03-04 13:30:30 +00:00
|
|
|
client_t *client, *sp;
|
2004-08-23 00:15:46 +00:00
|
|
|
edict_t *ent;
|
2005-08-26 22:56:51 +00:00
|
|
|
char *name;
|
2004-08-23 00:15:46 +00:00
|
|
|
|
2009-03-03 01:52:30 +00:00
|
|
|
float curgrav;
|
|
|
|
float curspeed;
|
|
|
|
int curfrags;
|
|
|
|
|
2004-08-23 00:15:46 +00:00
|
|
|
// 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++)
|
|
|
|
{
|
2007-09-02 19:55:17 +00:00
|
|
|
if ((svs.gametype == GT_Q1QVM || svs.gametype == GT_PROGS) && host_client->state == cs_spawned)
|
2005-08-26 22:56:51 +00:00
|
|
|
{
|
|
|
|
//DP_SV_CLIENTCOLORS
|
2007-09-02 19:55:17 +00:00
|
|
|
if (host_client->edict->xv->clientcolors != host_client->playercolor)
|
2005-08-26 22:56:51 +00:00
|
|
|
{
|
2007-09-02 19:55:17 +00:00
|
|
|
Info_SetValueForKey(host_client->userinfo, "topcolor", va("%i", (int)host_client->edict->xv->clientcolors/16), sizeof(host_client->userinfo));
|
|
|
|
Info_SetValueForKey(host_client->userinfo, "bottomcolor", va("%i", (int)host_client->edict->xv->clientcolors&15), sizeof(host_client->userinfo));
|
2005-08-26 22:56:51 +00:00
|
|
|
{
|
------------------------------------------------------------------------
r4169 | acceptthis | 2013-01-17 08:55:12 +0000 (Thu, 17 Jan 2013) | 31 lines
removed MAX_VISEDICTS limit.
PEXT2_REPLACEMENTDELTAS tweaked, now has 4 million entity limit. still not enabled by default.
TE_BEAM now maps to a separate TEQW_BEAM to avoid conflicts with QW.
added android multitouch emulation for windows/rawinput (in_simulatemultitouch).
split topcolor/bottomcolor from scoreboard, for dp's colormap|1024 feature.
now using utf-8 for windows consoles.
qcc warnings/errors now give clickable console links for quick+easy editing.
disabled menutint when the currently active item changes contrast or gamma (for OneManClan).
Added support for drawfont/drawfontscale.
tweaked the qcvm a little to reduce the number of pointers.
.doll file loading. still experimental and will likely crash. requires csqc active, even if its a dummy progs. this will be fixed in time. Still other things that need cleaning up.
windows: gl_font "?" shows the standard windows font-selection dialog, and can be used to select windows fonts. not all work. and you probably don't want to use windings.
fixed splitscreen support when playing mvds. added mini-scoreboards to splitscreen.
editor/debugger now shows asm if there's no linenumber info. also, pressing f1 for help shows the shortcuts.
Added support for .framegroups files for psk(psa) and iqm formats.
True support for ezquake's colour codes. Mutually exclusive with background colours.
path command output slightly more readable.
added support for digest_hex (MD4, SHA1, CRC16).
skingroups now colourmap correctly.
Fix terrain colour hints, and litdata from the wrong bsp.
fix ftp dual-homed issue. support epsv command, and enable ipv6 (eprt still not supported).
remove d3d11 compilation from the makefile. the required headers are not provided by mingw, and are not available to the build bot, so don't bother.
fix v *= v.x and similar opcodes.
fteqcc: fixed support for áéÃóú type chars in names. utf-8 files now properly supported (even with the utf-8 bom/identifier). utf-16 also supported.
fteqcc: fixed '#if 1 == 3 && 4' parsing.
fteqcc: -Werror acts on the warning, rather than as a separate error. Line numbers are thus more readable.
fteqcc: copyright message now includes compile date instead.
fteqccgui: the treeview control is now coloured depending on whether there were warnings/errors in the last compile.
fteqccgui: the output window is now focused and scrolls down as compilation progresses.
pr_dumpplatform command dumps out some pragmas to convert more serious warnings to errors. This is to avoid the infamous 'fteqcc sucks cos my code sucks' issue.
rewrote prespawn/modelist/soundlist code. server tracks progress now.
------------------------------------------------------------------------
git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@4167 fc73d0e0-1445-4013-8a0c-d673dee63da5
2013-03-12 22:29:40 +00:00
|
|
|
SV_ExtractFromUserinfo (host_client, true); //this will take care of nq for us anyway.
|
2005-08-26 22:56:51 +00:00
|
|
|
|
|
|
|
MSG_WriteByte (&sv.reliable_datagram, svc_setinfo);
|
|
|
|
MSG_WriteByte (&sv.reliable_datagram, i);
|
|
|
|
MSG_WriteString (&sv.reliable_datagram, "topcolor");
|
|
|
|
MSG_WriteString (&sv.reliable_datagram, Info_ValueForKey(host_client->userinfo, "topcolor"));
|
2005-10-23 17:57:20 +00:00
|
|
|
|
2005-08-26 22:56:51 +00:00
|
|
|
MSG_WriteByte (&sv.reliable_datagram, svc_setinfo);
|
|
|
|
MSG_WriteByte (&sv.reliable_datagram, i);
|
|
|
|
MSG_WriteString (&sv.reliable_datagram, "bottomcolor");
|
|
|
|
MSG_WriteString (&sv.reliable_datagram, Info_ValueForKey(host_client->userinfo, "bottomcolor"));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
name = PR_GetString(svprogfuncs, host_client->edict->v->netname);
|
|
|
|
if (name != host_client->name)
|
|
|
|
{
|
|
|
|
if (strcmp(host_client->name, name))
|
|
|
|
{
|
2012-01-24 04:24:14 +00:00
|
|
|
char oname[80];
|
|
|
|
Q_strncpyz(oname, host_client->name, sizeof(oname));
|
|
|
|
|
2011-12-05 15:23:40 +00:00
|
|
|
Con_DPrintf("Client %s programatically renamed to %s\n", host_client->name, name);
|
2005-08-26 22:56:51 +00:00
|
|
|
Info_SetValueForKey(host_client->userinfo, "name", name, sizeof(host_client->userinfo));
|
------------------------------------------------------------------------
r4169 | acceptthis | 2013-01-17 08:55:12 +0000 (Thu, 17 Jan 2013) | 31 lines
removed MAX_VISEDICTS limit.
PEXT2_REPLACEMENTDELTAS tweaked, now has 4 million entity limit. still not enabled by default.
TE_BEAM now maps to a separate TEQW_BEAM to avoid conflicts with QW.
added android multitouch emulation for windows/rawinput (in_simulatemultitouch).
split topcolor/bottomcolor from scoreboard, for dp's colormap|1024 feature.
now using utf-8 for windows consoles.
qcc warnings/errors now give clickable console links for quick+easy editing.
disabled menutint when the currently active item changes contrast or gamma (for OneManClan).
Added support for drawfont/drawfontscale.
tweaked the qcvm a little to reduce the number of pointers.
.doll file loading. still experimental and will likely crash. requires csqc active, even if its a dummy progs. this will be fixed in time. Still other things that need cleaning up.
windows: gl_font "?" shows the standard windows font-selection dialog, and can be used to select windows fonts. not all work. and you probably don't want to use windings.
fixed splitscreen support when playing mvds. added mini-scoreboards to splitscreen.
editor/debugger now shows asm if there's no linenumber info. also, pressing f1 for help shows the shortcuts.
Added support for .framegroups files for psk(psa) and iqm formats.
True support for ezquake's colour codes. Mutually exclusive with background colours.
path command output slightly more readable.
added support for digest_hex (MD4, SHA1, CRC16).
skingroups now colourmap correctly.
Fix terrain colour hints, and litdata from the wrong bsp.
fix ftp dual-homed issue. support epsv command, and enable ipv6 (eprt still not supported).
remove d3d11 compilation from the makefile. the required headers are not provided by mingw, and are not available to the build bot, so don't bother.
fix v *= v.x and similar opcodes.
fteqcc: fixed support for áéÃóú type chars in names. utf-8 files now properly supported (even with the utf-8 bom/identifier). utf-16 also supported.
fteqcc: fixed '#if 1 == 3 && 4' parsing.
fteqcc: -Werror acts on the warning, rather than as a separate error. Line numbers are thus more readable.
fteqcc: copyright message now includes compile date instead.
fteqccgui: the treeview control is now coloured depending on whether there were warnings/errors in the last compile.
fteqccgui: the output window is now focused and scrolls down as compilation progresses.
pr_dumpplatform command dumps out some pragmas to convert more serious warnings to errors. This is to avoid the infamous 'fteqcc sucks cos my code sucks' issue.
rewrote prespawn/modelist/soundlist code. server tracks progress now.
------------------------------------------------------------------------
git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@4167 fc73d0e0-1445-4013-8a0c-d673dee63da5
2013-03-12 22:29:40 +00:00
|
|
|
SV_ExtractFromUserinfo (host_client, true);
|
2005-08-26 22:56:51 +00:00
|
|
|
|
2012-01-24 04:24:14 +00:00
|
|
|
if (strcmp(oname, host_client->name))
|
|
|
|
{
|
2005-08-26 22:56:51 +00:00
|
|
|
MSG_WriteByte (&sv.reliable_datagram, svc_setinfo);
|
|
|
|
MSG_WriteByte (&sv.reliable_datagram, i);
|
|
|
|
MSG_WriteString (&sv.reliable_datagram, "name");
|
|
|
|
MSG_WriteString (&sv.reliable_datagram, host_client->name);
|
|
|
|
}
|
|
|
|
}
|
2007-06-20 00:02:54 +00:00
|
|
|
host_client->edict->v->netname = PR_SetString(svprogfuncs, host_client->name);
|
2005-08-26 22:56:51 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-08-23 00:15:46 +00:00
|
|
|
if (host_client->state != cs_spawned)
|
|
|
|
{
|
2005-08-26 22:56:51 +00:00
|
|
|
if (!host_client->state && host_client->name && host_client->name[0]) //if this is a writebyte bot
|
2004-08-23 00:15:46 +00:00
|
|
|
{
|
2005-03-28 00:11:59 +00:00
|
|
|
if (host_client->old_frags != (int)host_client->edict->v->frags)
|
2004-08-23 00:15:46 +00:00
|
|
|
{
|
|
|
|
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);
|
2005-03-28 00:11:59 +00:00
|
|
|
ClientReliableWrite_Short(client, host_client->edict->v->frags);
|
2004-08-23 00:15:46 +00:00
|
|
|
}
|
|
|
|
|
2005-03-04 13:30:30 +00:00
|
|
|
if (sv.mvdrecording)
|
|
|
|
{
|
2012-08-04 01:35:52 +00:00
|
|
|
sizebuf_t *msg = MVDWrite_Begin(dem_all, 0, 4);
|
|
|
|
MSG_WriteByte(msg, svc_updatefrags);
|
|
|
|
MSG_WriteByte(msg, i);
|
|
|
|
MSG_WriteShort(msg, host_client->edict->v->frags);
|
2005-03-04 13:30:30 +00:00
|
|
|
}
|
|
|
|
|
2005-03-28 00:11:59 +00:00
|
|
|
host_client->old_frags = host_client->edict->v->frags;
|
2004-08-23 00:15:46 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
}
|
2009-03-03 01:52:30 +00:00
|
|
|
if (svs.gametype == GT_PROGS || svs.gametype == GT_Q1QVM)
|
|
|
|
{
|
|
|
|
ent = host_client->edict;
|
|
|
|
|
|
|
|
curfrags = host_client->edict->v->frags;
|
|
|
|
curgrav = ent->xv->gravity*sv_gravity.value;
|
|
|
|
curspeed = ent->xv->maxspeed;
|
|
|
|
if (progstype != PROG_QW)
|
|
|
|
{
|
|
|
|
if (!curgrav)
|
2010-07-11 02:22:39 +00:00
|
|
|
curgrav = sv_gravity.value;
|
2009-03-03 01:52:30 +00:00
|
|
|
if (!curspeed)
|
|
|
|
curspeed = sv_maxspeed.value;
|
|
|
|
}
|
|
|
|
if (ent->xv->hasted)
|
|
|
|
curspeed*=ent->xv->hasted;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
curgrav = sv_gravity.value;
|
|
|
|
curspeed = sv_maxspeed.value;
|
|
|
|
curfrags = 0;
|
|
|
|
}
|
|
|
|
#ifdef SVCHAT //enforce a no moving time when chatting. Prevent client prediction going mad.
|
|
|
|
if (host_client->chat.active)
|
|
|
|
curspeed = 0;
|
|
|
|
#endif
|
|
|
|
|
2005-05-26 12:55:34 +00:00
|
|
|
if (!ISQ2CLIENT(host_client))
|
2004-08-23 00:15:46 +00:00
|
|
|
{
|
|
|
|
if (host_client->sendinfo)
|
|
|
|
{
|
|
|
|
host_client->sendinfo = false;
|
2013-03-31 04:21:08 +00:00
|
|
|
SV_FullClientUpdate (host_client, NULL);
|
2004-08-23 00:15:46 +00:00
|
|
|
}
|
2009-03-03 01:52:30 +00:00
|
|
|
if (host_client->old_frags != curfrags)
|
2004-08-23 00:15:46 +00:00
|
|
|
{
|
|
|
|
for (j=0, client = svs.clients ; j<MAX_CLIENTS ; j++, client++)
|
|
|
|
{
|
|
|
|
if (client->state < cs_connected)
|
|
|
|
continue;
|
|
|
|
if (client->controller)
|
|
|
|
continue;
|
|
|
|
ClientReliableWrite_Begin(client, svc_updatefrags, 4);
|
|
|
|
ClientReliableWrite_Byte(client, i);
|
2009-03-03 01:52:30 +00:00
|
|
|
ClientReliableWrite_Short(client, curfrags);
|
2004-08-23 00:15:46 +00:00
|
|
|
}
|
|
|
|
|
2005-03-04 13:30:30 +00:00
|
|
|
if (sv.mvdrecording)
|
|
|
|
{
|
2012-08-04 01:35:52 +00:00
|
|
|
sizebuf_t *msg = MVDWrite_Begin(dem_all, 0, 4);
|
|
|
|
MSG_WriteByte(msg, svc_updatefrags);
|
|
|
|
MSG_WriteByte(msg, i);
|
|
|
|
MSG_WriteShort(msg, curfrags);
|
2005-03-04 13:30:30 +00:00
|
|
|
}
|
|
|
|
|
2009-03-03 01:52:30 +00:00
|
|
|
host_client->old_frags = curfrags;
|
2004-08-23 00:15:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
{
|
2009-03-03 01:52:30 +00:00
|
|
|
if (host_client->entgravity != curgrav)
|
2005-05-26 12:55:34 +00:00
|
|
|
{
|
2005-10-23 17:57:20 +00:00
|
|
|
if (ISQWCLIENT(host_client))
|
|
|
|
{
|
|
|
|
sp = SV_SplitClientDest(host_client, svc_entgravity, 5);
|
2009-03-03 01:52:30 +00:00
|
|
|
ClientReliableWrite_Float(sp, curgrav/movevars.gravity); //lie to the client in a cunning way
|
2005-10-23 17:57:20 +00:00
|
|
|
}
|
2009-03-03 01:52:30 +00:00
|
|
|
host_client->entgravity = curgrav;
|
2004-08-23 00:15:46 +00:00
|
|
|
}
|
2009-03-03 01:52:30 +00:00
|
|
|
|
|
|
|
if (host_client->maxspeed != curspeed)
|
2005-05-26 12:55:34 +00:00
|
|
|
{ //MSVC can really suck at times (optimiser bug)
|
2005-10-23 17:57:20 +00:00
|
|
|
if (ISQWCLIENT(host_client))
|
|
|
|
{
|
|
|
|
if (host_client->controller)
|
|
|
|
{ //this is a slave client.
|
|
|
|
//find the right number and send.
|
|
|
|
int pnum = 0;
|
|
|
|
client_t *sp;
|
|
|
|
for (sp = host_client->controller; sp; sp = sp->controlled)
|
|
|
|
{
|
|
|
|
if (sp == host_client)
|
|
|
|
break;
|
|
|
|
pnum++;
|
|
|
|
}
|
|
|
|
sp = host_client->controller;
|
|
|
|
|
2008-05-25 22:23:43 +00:00
|
|
|
ClientReliableWrite_Begin (sp, svcfte_choosesplitclient, 7);
|
2005-10-23 17:57:20 +00:00
|
|
|
ClientReliableWrite_Byte (sp, pnum);
|
|
|
|
ClientReliableWrite_Byte (sp, svc_maxspeed);
|
2009-03-03 01:52:30 +00:00
|
|
|
ClientReliableWrite_Float(sp, curspeed);
|
2005-10-23 17:57:20 +00:00
|
|
|
}
|
|
|
|
else
|
2005-05-26 12:55:34 +00:00
|
|
|
{
|
2005-10-23 17:57:20 +00:00
|
|
|
ClientReliableWrite_Begin(host_client, svc_maxspeed, 5);
|
2009-03-03 01:52:30 +00:00
|
|
|
ClientReliableWrite_Float(host_client, curspeed);
|
2005-05-26 12:55:34 +00:00
|
|
|
}
|
|
|
|
}
|
2009-03-03 01:52:30 +00:00
|
|
|
host_client->maxspeed = curspeed;
|
2004-08-23 00:15:46 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sv.reliable_datagram.overflowed)
|
|
|
|
{
|
|
|
|
Con_Printf("WARNING: Reliable datagram overflowed\n");
|
|
|
|
SZ_Clear (&sv.reliable_datagram);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sv.datagram.overflowed)
|
|
|
|
SZ_Clear (&sv.datagram);
|
|
|
|
|
|
|
|
#ifdef NQPROT
|
2009-01-30 02:48:03 +00:00
|
|
|
if (sv.nqdatagram.overflowed)
|
2004-08-23 00:15:46 +00:00
|
|
|
SZ_Clear (&sv.nqdatagram);
|
|
|
|
#endif
|
2005-05-26 12:55:34 +00:00
|
|
|
#ifdef Q2SERVER
|
2004-08-23 00:15:46 +00:00
|
|
|
if (sv.q2datagram.overflowed)
|
|
|
|
SZ_Clear (&sv.q2datagram);
|
2005-05-26 12:55:34 +00:00
|
|
|
#endif
|
2004-08-23 00:15:46 +00:00
|
|
|
|
2012-05-09 15:30:53 +00:00
|
|
|
SV_FlushBroadcasts();
|
2004-08-23 00:15:46 +00:00
|
|
|
}
|
|
|
|
|
2004-09-14 21:41:59 +00:00
|
|
|
#ifdef _MSC_VER
|
2004-08-23 00:15:46 +00:00
|
|
|
#pragma optimize( "", off )
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
=======================
|
|
|
|
SV_SendClientMessages
|
|
|
|
=======================
|
|
|
|
*/
|
|
|
|
void SV_SendClientMessages (void)
|
|
|
|
{
|
|
|
|
int i, j;
|
|
|
|
client_t *c;
|
2009-06-23 21:49:44 +00:00
|
|
|
int sentbytes, fnum;
|
2011-10-27 16:16:29 +00:00
|
|
|
float pt = sv.paused?realtime:sv.world.physicstime;
|
2004-08-23 00:15:46 +00:00
|
|
|
|
2005-03-04 13:30:30 +00:00
|
|
|
#ifdef Q3SERVER
|
|
|
|
if (svs.gametype == GT_QUAKE3)
|
|
|
|
{
|
|
|
|
for (i=0, c = svs.clients ; i<MAX_CLIENTS ; i++, c++)
|
|
|
|
{
|
|
|
|
if (c->state <= cs_zombie)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (c->drop)
|
|
|
|
{
|
|
|
|
SV_DropClient(c);
|
|
|
|
c->drop = false;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2005-09-08 01:52:32 +00:00
|
|
|
if (c->protocol == SCP_BAD) //this is a bot.
|
|
|
|
{
|
|
|
|
SZ_Clear (&c->netchan.message);
|
|
|
|
SZ_Clear (&c->datagram);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2005-03-04 13:30:30 +00:00
|
|
|
SVQ3_SendMessage(c);
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2004-08-23 00:15:46 +00:00
|
|
|
// update frags, names, etc
|
|
|
|
SV_UpdateToReliableMessages ();
|
|
|
|
|
|
|
|
// build individual updates
|
|
|
|
for (i=0, c = svs.clients ; i<MAX_CLIENTS ; i++, c++)
|
|
|
|
{
|
2009-09-08 14:52:32 +00:00
|
|
|
if (c->state <= cs_zombie)
|
2004-08-23 00:15:46 +00:00
|
|
|
continue;
|
|
|
|
|
|
|
|
if (c->drop)
|
|
|
|
{
|
|
|
|
SV_DropClient(c);
|
|
|
|
c->drop = false;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef SVCHAT
|
|
|
|
SV_ChatThink(c);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if (c->wasrecorded)
|
|
|
|
{
|
|
|
|
c->netchan.message.cursize = 0;
|
|
|
|
c->datagram.cursize = 0;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (c->istobeloaded && c->state == cs_zombie)
|
|
|
|
{ //not yet present.
|
|
|
|
c->netchan.message.cursize = 0;
|
|
|
|
c->datagram.cursize = 0;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2008-11-09 22:29:28 +00:00
|
|
|
#ifdef Q3SERVER
|
|
|
|
if (ISQ3CLIENT(c))
|
|
|
|
{ //q3 protocols bypass backbuffering and pretty much everything else
|
|
|
|
if (c->state <= cs_zombie)
|
|
|
|
continue;
|
|
|
|
SVQ3_SendMessage(c);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2004-08-23 00:15:46 +00:00
|
|
|
// 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]);
|
2005-10-23 17:57:20 +00:00
|
|
|
|
2004-08-23 00:15:46 +00:00
|
|
|
//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]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-06-14 04:52:10 +00:00
|
|
|
if (c->protocol == SCP_BAD)
|
|
|
|
{
|
|
|
|
SZ_Clear (&c->netchan.message);
|
|
|
|
SZ_Clear (&c->datagram);
|
2005-09-14 04:40:30 +00:00
|
|
|
c->num_backbuf = 0;
|
2005-06-14 04:52:10 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2004-08-23 00:15:46 +00:00
|
|
|
// 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);
|
|
|
|
c->send_message = true;
|
|
|
|
c->netchan.cleartime = 0; // don't choke this message
|
2012-02-12 05:18:31 +00:00
|
|
|
SV_DropClient (c);
|
2011-07-08 19:11:58 +00:00
|
|
|
continue;
|
2004-08-23 00:15:46 +00:00
|
|
|
}
|
|
|
|
|
2013-03-12 22:35:33 +00:00
|
|
|
#ifdef NQPROT
|
2004-08-23 00:15:46 +00:00
|
|
|
// only send messages if the client has sent one
|
|
|
|
// and the bandwidth is not choked
|
2005-05-26 12:55:34 +00:00
|
|
|
if (ISNQCLIENT(c))
|
2013-03-12 22:35:33 +00:00
|
|
|
{
|
|
|
|
//tread carefully with NQ:
|
|
|
|
//while loading models etc, NQ will error out if it receives anything that it wasn't expecting.
|
|
|
|
//we should still send unreliable nops whenever we want as a keepalive (and we may need to in order to wake up the client).
|
|
|
|
//other unreliables are disallowed when connecting, due to sync issues.
|
|
|
|
//reliables may be sent only if some other code has said that its okay (to avoid stray name changes killing clients).
|
|
|
|
if (c->state == cs_connected)
|
2007-06-20 00:02:54 +00:00
|
|
|
{
|
2013-03-12 22:35:33 +00:00
|
|
|
if (c->nextservertimeupdate > pt + 6)
|
|
|
|
c->nextservertimeupdate = 0;
|
2007-06-20 00:02:54 +00:00
|
|
|
|
2013-03-12 22:35:33 +00:00
|
|
|
c->netchan.nqunreliableonly = !c->send_message;
|
|
|
|
c->datagram.cursize = 0;
|
|
|
|
if (!c->send_message && c->nextservertimeupdate < pt)
|
2007-06-20 00:02:54 +00:00
|
|
|
{
|
2013-03-12 22:35:33 +00:00
|
|
|
if (c->nextservertimeupdate)
|
|
|
|
MSG_WriteByte(&c->datagram, svc_nop);
|
|
|
|
c->nextservertimeupdate = pt+5;
|
|
|
|
}
|
|
|
|
c->send_message = true;
|
|
|
|
//we can still send an outgoing packet if something set send_message. This should really only be svnq_new_f and friends.
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2013-03-12 22:53:23 +00:00
|
|
|
if (c->nextservertimeupdate > pt + 0.1)
|
2013-03-12 22:35:33 +00:00
|
|
|
c->nextservertimeupdate = 0;
|
|
|
|
|
|
|
|
c->netchan.nqunreliableonly = false;
|
|
|
|
c->send_message = false;
|
|
|
|
//nq sends one packet only for each server physics frame
|
|
|
|
if (c->nextservertimeupdate < pt && c->state != cs_zombie)
|
|
|
|
{
|
|
|
|
c->send_message = true;
|
2013-03-12 22:53:23 +00:00
|
|
|
c->nextservertimeupdate = pt + 1.0/77;
|
2007-06-20 00:02:54 +00:00
|
|
|
}
|
|
|
|
}
|
2005-05-26 12:55:34 +00:00
|
|
|
}
|
2013-03-12 22:35:33 +00:00
|
|
|
//qw servers will set send_message on packet reception.
|
|
|
|
#endif
|
|
|
|
|
2004-08-23 00:15:46 +00:00
|
|
|
if (!c->send_message)
|
|
|
|
continue;
|
|
|
|
c->send_message = false; // try putting this after choke?
|
2010-08-12 09:04:05 +00:00
|
|
|
|
|
|
|
if (c->controller)
|
|
|
|
continue; /*shouldn't have been set*/
|
|
|
|
|
2004-10-19 16:10:14 +00:00
|
|
|
if (!sv.paused && !Netchan_CanPacket (&c->netchan, SV_RateForClient(c)))
|
2004-08-23 00:15:46 +00:00
|
|
|
{
|
|
|
|
c->chokecount++;
|
2009-05-24 10:11:17 +00:00
|
|
|
c->waschoked = true;
|
2004-08-23 00:15:46 +00:00
|
|
|
continue; // bandwidth choke
|
|
|
|
}
|
2009-05-24 10:11:17 +00:00
|
|
|
c->waschoked = false;
|
2004-08-23 00:15:46 +00:00
|
|
|
|
2012-02-27 12:23:15 +00:00
|
|
|
if (sv.time > c->ratetime + 1)
|
|
|
|
{
|
|
|
|
c->inrate = c->netchan.bytesin / (sv.time - c->ratetime);
|
|
|
|
c->outrate = c->netchan.bytesout / (sv.time - c->ratetime);
|
|
|
|
c->netchan.bytesin = 0;
|
|
|
|
c->netchan.bytesout = 0;
|
|
|
|
c->ratetime = sv.time;
|
|
|
|
}
|
|
|
|
|
2004-08-23 00:15:46 +00:00
|
|
|
if (c->state == cs_spawned)
|
|
|
|
SV_SendClientDatagram (c);
|
|
|
|
else
|
2006-01-03 21:31:56 +00:00
|
|
|
{
|
------------------------------------------------------------------------
r4169 | acceptthis | 2013-01-17 08:55:12 +0000 (Thu, 17 Jan 2013) | 31 lines
removed MAX_VISEDICTS limit.
PEXT2_REPLACEMENTDELTAS tweaked, now has 4 million entity limit. still not enabled by default.
TE_BEAM now maps to a separate TEQW_BEAM to avoid conflicts with QW.
added android multitouch emulation for windows/rawinput (in_simulatemultitouch).
split topcolor/bottomcolor from scoreboard, for dp's colormap|1024 feature.
now using utf-8 for windows consoles.
qcc warnings/errors now give clickable console links for quick+easy editing.
disabled menutint when the currently active item changes contrast or gamma (for OneManClan).
Added support for drawfont/drawfontscale.
tweaked the qcvm a little to reduce the number of pointers.
.doll file loading. still experimental and will likely crash. requires csqc active, even if its a dummy progs. this will be fixed in time. Still other things that need cleaning up.
windows: gl_font "?" shows the standard windows font-selection dialog, and can be used to select windows fonts. not all work. and you probably don't want to use windings.
fixed splitscreen support when playing mvds. added mini-scoreboards to splitscreen.
editor/debugger now shows asm if there's no linenumber info. also, pressing f1 for help shows the shortcuts.
Added support for .framegroups files for psk(psa) and iqm formats.
True support for ezquake's colour codes. Mutually exclusive with background colours.
path command output slightly more readable.
added support for digest_hex (MD4, SHA1, CRC16).
skingroups now colourmap correctly.
Fix terrain colour hints, and litdata from the wrong bsp.
fix ftp dual-homed issue. support epsv command, and enable ipv6 (eprt still not supported).
remove d3d11 compilation from the makefile. the required headers are not provided by mingw, and are not available to the build bot, so don't bother.
fix v *= v.x and similar opcodes.
fteqcc: fixed support for áéÃóú type chars in names. utf-8 files now properly supported (even with the utf-8 bom/identifier). utf-16 also supported.
fteqcc: fixed '#if 1 == 3 && 4' parsing.
fteqcc: -Werror acts on the warning, rather than as a separate error. Line numbers are thus more readable.
fteqcc: copyright message now includes compile date instead.
fteqccgui: the treeview control is now coloured depending on whether there were warnings/errors in the last compile.
fteqccgui: the output window is now focused and scrolls down as compilation progresses.
pr_dumpplatform command dumps out some pragmas to convert more serious warnings to errors. This is to avoid the infamous 'fteqcc sucks cos my code sucks' issue.
rewrote prespawn/modelist/soundlist code. server tracks progress now.
------------------------------------------------------------------------
git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@4167 fc73d0e0-1445-4013-8a0c-d673dee63da5
2013-03-12 22:29:40 +00:00
|
|
|
SV_SendClientPrespawnInfo(c);
|
|
|
|
|
2007-06-20 00:02:54 +00:00
|
|
|
SV_DarkPlacesDownloadChunk(c, &c->datagram);
|
2009-06-23 21:49:44 +00:00
|
|
|
fnum = c->netchan.outgoing_sequence;
|
|
|
|
sentbytes = Netchan_Transmit (&c->netchan, c->datagram.cursize, c->datagram.data, SV_RateForClient(c)); // just update reliable
|
2009-08-08 12:43:35 +00:00
|
|
|
if (ISQWCLIENT(c) || ISNQCLIENT(c))
|
2009-06-23 21:49:44 +00:00
|
|
|
c->frameunion.frames[fnum & UPDATE_MASK].packetsizeout += sentbytes;
|
2006-01-03 21:31:56 +00:00
|
|
|
c->datagram.cursize = 0;
|
|
|
|
}
|
2005-10-23 17:57:20 +00:00
|
|
|
|
2004-08-23 00:15:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
SV_CleanupEnts();
|
|
|
|
}
|
|
|
|
|
2004-09-14 21:41:59 +00:00
|
|
|
#ifdef _MSC_VER
|
2004-08-23 00:15:46 +00:00
|
|
|
#pragma optimize( "", on )
|
|
|
|
#endif
|
|
|
|
|
2013-03-12 22:44:00 +00:00
|
|
|
void SV_WriteMVDMessage (sizebuf_t *msg, int type, int to, float time);
|
2004-08-23 00:15:46 +00:00
|
|
|
|
2006-09-17 00:59:22 +00:00
|
|
|
void DemoWriteQTVTimePad(int msecs);
|
2004-08-23 00:15:46 +00:00
|
|
|
#define Max(a, b) ((a>b)?a:b)
|
|
|
|
void SV_SendMVDMessage(void)
|
|
|
|
{
|
2011-08-16 04:12:15 +00:00
|
|
|
int i, j, m, cls = 0;
|
2004-08-23 00:15:46 +00:00
|
|
|
client_t *c;
|
|
|
|
qbyte buf[MAX_DATAGRAM];
|
|
|
|
sizebuf_t msg;
|
2011-08-16 04:12:15 +00:00
|
|
|
int statsi[MAX_CL_STATS];
|
|
|
|
float statsf[MAX_CL_STATS];
|
|
|
|
char *statss[MAX_CL_STATS];
|
2004-08-23 00:15:46 +00:00
|
|
|
float min_fps;
|
|
|
|
extern cvar_t sv_demofps;
|
|
|
|
extern cvar_t sv_demoPings;
|
2005-01-24 23:47:32 +00:00
|
|
|
// extern cvar_t sv_demoMaxSize;
|
2012-08-04 01:35:52 +00:00
|
|
|
sizebuf_t *dmsg;
|
2004-08-23 00:15:46 +00:00
|
|
|
|
2006-09-17 00:59:22 +00:00
|
|
|
SV_MVD_RunPendingConnections();
|
|
|
|
|
2004-08-23 00:15:46 +00:00
|
|
|
if (!sv.mvdrecording)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (sv_demoPings.value)
|
|
|
|
{
|
|
|
|
if (sv.time - demo.pingtime > sv_demoPings.value)
|
|
|
|
{
|
|
|
|
SV_MVDPings();
|
|
|
|
demo.pingtime = sv.time;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-08-16 04:12:15 +00:00
|
|
|
if (sv_demofps.value <= 1)
|
2004-08-23 00:15:46 +00:00
|
|
|
min_fps = 30.0;
|
|
|
|
else
|
|
|
|
min_fps = sv_demofps.value;
|
|
|
|
|
|
|
|
min_fps = Max(4, min_fps);
|
|
|
|
if (sv.time - demo.time < 1.0/min_fps)
|
|
|
|
return;
|
|
|
|
|
|
|
|
for (i=0, c = svs.clients ; i<MAX_CLIENTS ; i++, c++)
|
|
|
|
{
|
|
|
|
if (c->state != cs_spawned)
|
|
|
|
continue; // datagrams only go to spawned
|
|
|
|
|
|
|
|
cls |= 1 << i;
|
|
|
|
}
|
|
|
|
|
2006-09-17 00:59:22 +00:00
|
|
|
if (!cls)
|
|
|
|
{
|
2004-08-23 00:15:46 +00:00
|
|
|
SZ_Clear (&demo.datagram);
|
2006-09-17 00:59:22 +00:00
|
|
|
DemoWriteQTVTimePad((int)((sv.time - demo.time)*1000));
|
|
|
|
DestFlush(false);
|
|
|
|
demo.time = sv.time;
|
2004-08-23 00:15:46 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
msg.data = buf;
|
|
|
|
msg.maxsize = sizeof(buf);
|
|
|
|
msg.cursize = 0;
|
|
|
|
msg.allowoverflow = true;
|
|
|
|
msg.overflowed = false;
|
2005-10-23 17:57:20 +00:00
|
|
|
|
2011-08-16 04:12:15 +00:00
|
|
|
m = MAX_QW_STATS;
|
2011-09-03 03:49:43 +00:00
|
|
|
if (demo.recorder.fteprotocolextensions & (PEXT_HEXEN2|PEXT_CSQC))
|
2011-08-16 04:12:15 +00:00
|
|
|
m = MAX_CL_STATS;
|
|
|
|
|
2004-08-23 00:15:46 +00:00
|
|
|
for (i=0, c = svs.clients ; i<MAX_CLIENTS ; i++, c++)
|
|
|
|
{
|
|
|
|
if (c->state != cs_spawned)
|
|
|
|
continue; // datagrams only go to spawned
|
|
|
|
|
|
|
|
if (c->spectator)
|
|
|
|
continue;
|
|
|
|
|
2011-08-16 04:12:15 +00:00
|
|
|
/*figure out what the stat values should be*/
|
|
|
|
SV_CalcClientStats(c, statsi, statsf, statss);
|
2005-10-23 17:57:20 +00:00
|
|
|
|
2011-08-16 04:12:15 +00:00
|
|
|
for (j=0 ; j<m ; j++)
|
|
|
|
{
|
|
|
|
if (demo.recorder.fteprotocolextensions & PEXT_CSQC)
|
|
|
|
{
|
|
|
|
if (statss[j] || demo.statss[i][j])
|
|
|
|
if (strcmp(statss[j]?statss[j]:"", demo.statss[i][j]?demo.statss[i][j]:""))
|
|
|
|
{
|
2012-08-04 01:35:52 +00:00
|
|
|
sizebuf_t *msg = MVDWrite_Begin(dem_stats, i, 3+strlen(statss[j]));
|
2011-08-16 04:12:15 +00:00
|
|
|
demo.statss[i][j] = statss[j];
|
2012-08-04 01:35:52 +00:00
|
|
|
MSG_WriteByte(msg, svcfte_updatestatstring);
|
|
|
|
MSG_WriteByte(msg, j);
|
|
|
|
MSG_WriteString(msg, statss[j]);
|
2011-08-16 04:12:15 +00:00
|
|
|
}
|
|
|
|
}
|
2004-08-23 00:15:46 +00:00
|
|
|
|
2011-08-16 04:12:15 +00:00
|
|
|
if (statsf[j])
|
|
|
|
{
|
|
|
|
if (demo.recorder.fteprotocolextensions & PEXT_CSQC)
|
|
|
|
{
|
|
|
|
if (statsf[j] != demo.statsf[i][j])
|
|
|
|
{
|
|
|
|
if (statsf[j] - (float)(int)statsf[j] == 0 && statsf[j] >= 0 && statsf[j] <= 255)
|
|
|
|
{
|
2012-08-04 01:35:52 +00:00
|
|
|
dmsg = MVDWrite_Begin(dem_stats, i, 3);
|
2012-09-30 05:52:03 +00:00
|
|
|
MSG_WriteByte(dmsg, svcqw_updatestatbyte);
|
2012-08-04 01:35:52 +00:00
|
|
|
MSG_WriteByte(dmsg, j);
|
|
|
|
MSG_WriteByte(dmsg, statsf[j]);
|
2011-08-16 04:12:15 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2012-08-04 01:35:52 +00:00
|
|
|
dmsg = MVDWrite_Begin(dem_stats, i, 6);
|
|
|
|
MSG_WriteByte(dmsg, svcfte_updatestatfloat);
|
|
|
|
MSG_WriteByte(dmsg, j);
|
|
|
|
MSG_WriteFloat(dmsg, statsf[j]);
|
2011-08-16 04:12:15 +00:00
|
|
|
}
|
|
|
|
demo.statsf[i][j] = statsf[j];
|
|
|
|
/*make sure statsf is correct*/
|
|
|
|
demo.statsi[i][j] = statsf[j];
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
statsi[j] = statsf[j];
|
|
|
|
}
|
2004-08-23 00:15:46 +00:00
|
|
|
|
2011-08-16 04:12:15 +00:00
|
|
|
if (statsi[j] != demo.statsi[i][j])
|
2004-08-23 00:15:46 +00:00
|
|
|
{
|
2011-08-16 04:12:15 +00:00
|
|
|
demo.statsi[i][j] = statsi[j];
|
|
|
|
demo.statsf[i][j] = statsi[j];
|
|
|
|
if (statsi[j] >=0 && statsi[j] <= 255)
|
2004-08-23 00:15:46 +00:00
|
|
|
{
|
2012-08-04 01:35:52 +00:00
|
|
|
dmsg = MVDWrite_Begin(dem_stats, i, 3);
|
2012-09-30 05:52:03 +00:00
|
|
|
MSG_WriteByte(dmsg, svcqw_updatestatbyte);
|
2012-08-04 01:35:52 +00:00
|
|
|
MSG_WriteByte(dmsg, j);
|
|
|
|
MSG_WriteByte(dmsg, statsi[j]);
|
2004-08-23 00:15:46 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2012-08-04 01:35:52 +00:00
|
|
|
dmsg = MVDWrite_Begin(dem_stats, i, 6);
|
2012-09-30 05:52:03 +00:00
|
|
|
MSG_WriteByte(dmsg, svcqw_updatestatlong);
|
2012-08-04 01:35:52 +00:00
|
|
|
MSG_WriteByte(dmsg, j);
|
|
|
|
MSG_WriteLong(dmsg, statsi[j]);
|
2004-08-23 00:15:46 +00:00
|
|
|
}
|
|
|
|
}
|
2011-08-16 04:12:15 +00:00
|
|
|
}
|
2004-08-23 00:15:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// send over all the objects that are in the PVS
|
|
|
|
// this will include clients, a packetentities, and
|
|
|
|
// possibly a nails update
|
|
|
|
msg.cursize = 0;
|
2010-11-20 22:01:16 +00:00
|
|
|
msg.prim = demo.recorder.netchan.netprim;
|
2004-08-23 00:15:46 +00:00
|
|
|
if (!demo.recorder.delta_sequence)
|
|
|
|
demo.recorder.delta_sequence = -1;
|
2007-09-10 14:55:36 +00:00
|
|
|
|
2004-08-23 00:15:46 +00:00
|
|
|
// copy the accumulated multicast datagram
|
|
|
|
// for this client out to the message
|
2013-03-12 22:44:00 +00:00
|
|
|
if (demo.datagram.cursize && sv.mvdrecording)
|
2012-08-04 01:35:52 +00:00
|
|
|
{
|
|
|
|
dmsg = MVDWrite_Begin(dem_all, 0, demo.datagram.cursize);
|
|
|
|
SZ_Write (dmsg, demo.datagram.data, demo.datagram.cursize);
|
2004-08-23 00:15:46 +00:00
|
|
|
SZ_Clear (&demo.datagram);
|
|
|
|
}
|
|
|
|
|
2013-03-12 22:44:00 +00:00
|
|
|
while (demo.lastwritten < demo.parsecount-1 && sv.mvdrecording)
|
|
|
|
{
|
|
|
|
SV_MVDWritePackets(1);
|
|
|
|
}
|
|
|
|
|
2004-08-23 00:15:46 +00:00
|
|
|
demo.recorder.delta_sequence = demo.recorder.netchan.incoming_sequence&255;
|
|
|
|
demo.recorder.netchan.incoming_sequence++;
|
|
|
|
demo.frames[demo.parsecount&DEMO_FRAMES_MASK].time = demo.time = sv.time;
|
|
|
|
|
2013-03-12 22:44:00 +00:00
|
|
|
if (sv.mvdrecording)
|
2004-08-23 00:15:46 +00:00
|
|
|
{
|
2013-03-12 22:44:00 +00:00
|
|
|
SV_WriteEntitiesToClient (&demo.recorder, &msg, true);
|
|
|
|
SV_WriteMVDMessage(&msg, dem_all, 0, sv.time);
|
|
|
|
// dmsg = MVDWrite_Begin(dem_all, 0, msg.cursize);
|
|
|
|
// SZ_Write (dmsg, msg.data, msg.cursize);
|
2004-08-23 00:15:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
demo.parsecount++;
|
2013-03-12 22:44:00 +00:00
|
|
|
|
2012-08-04 01:35:52 +00:00
|
|
|
// MVDSetMsgBuf(demo.dbuf,&demo.frames[demo.parsecount&DEMO_FRAMES_MASK].buf);
|
2004-08-23 00:15:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
=======================
|
|
|
|
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;
|
2005-10-23 17:57:20 +00:00
|
|
|
|
2004-08-23 00:15:46 +00:00
|
|
|
SV_SendClientMessages ();
|
|
|
|
}
|
|
|
|
|
2004-11-29 01:21:00 +00:00
|
|
|
#endif
|