Reworked networking a little, separating out common code for separate server/master processes.

Reworked glsl bones, so they work based upon the shader's version instead of the driver's version (more robust).
Fix te_teleport shader.
Track angles for antilag.


git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@5372 fc73d0e0-1445-4013-8a0c-d673dee63da5
This commit is contained in:
Spoike 2018-12-28 00:04:36 +00:00
parent 18280be6e9
commit c6ed692871
56 changed files with 2026 additions and 964 deletions

View file

@ -990,7 +990,7 @@ qboolean CL_GetMessage (void)
if (cls.demoplayback != DPB_NONE) if (cls.demoplayback != DPB_NONE)
return CL_GetDemoMessage (); return CL_GetDemoMessage ();
if (NET_GetPacket (NS_CLIENT, 0) < 0) if (NET_GetPacket (cls.sockets, 0) < 0)
return false; return false;
return true; return true;

View file

@ -301,11 +301,6 @@ qbyte *host_basepal;
qbyte *h2playertranslations; qbyte *h2playertranslations;
cvar_t host_speeds = CVAR("host_speeds","0"); // set for running times cvar_t host_speeds = CVAR("host_speeds","0"); // set for running times
#ifdef CRAZYDEBUGGING
cvar_t developer = CVAR("developer","1");
#else
cvar_t developer = CVAR("developer","0");
#endif
int fps_count; int fps_count;
qboolean forcesaveprompt; qboolean forcesaveprompt;
@ -455,7 +450,7 @@ void CL_ConnectToDarkPlaces(char *challenge, netadr_t *adr)
Q_snprintfz(data, sizeof(data), "%c%c%c%cconnect\\protocol\\darkplaces 3\\protocols\\DP7 DP6 DP5 RMQ FITZ NEHAHRABJP2 NEHAHRABJP NEHAHRABJP3 QUAKE\\challenge\\%s\\name\\%s", 255, 255, 255, 255, challenge, name.string); Q_snprintfz(data, sizeof(data), "%c%c%c%cconnect\\protocol\\darkplaces 3\\protocols\\DP7 DP6 DP5 RMQ FITZ NEHAHRABJP2 NEHAHRABJP NEHAHRABJP3 QUAKE\\challenge\\%s\\name\\%s", 255, 255, 255, 255, challenge, name.string);
NET_SendPacket (NS_CLIENT, strlen(data), data, adr); NET_SendPacket (cls.sockets, strlen(data), data, adr);
cl.splitclients = 0; cl.splitclients = 0;
} }
@ -724,7 +719,7 @@ void CL_SendConnectPacket (netadr_t *to, int mtu,
if (info) if (info)
Q_strncatz(data, va("0x%x \"%s\"\n", PROTOCOL_INFO_GUID, info), sizeof(data)); Q_strncatz(data, va("0x%x \"%s\"\n", PROTOCOL_INFO_GUID, info), sizeof(data));
NET_SendPacket (NS_CLIENT, strlen(data), data, to); NET_SendPacket (cls.sockets, strlen(data), data, to);
} }
char *CL_TryingToConnect(void) char *CL_TryingToConnect(void)
@ -752,7 +747,7 @@ void CL_CheckForResend (void)
char *host; char *host;
extern int r_blockvidrestart; extern int r_blockvidrestart;
#ifndef CLIENTONLY #ifdef HAVE_SERVER
if (!cls.state && (!connectinfo.trying || sv.state != ss_clustermode) && sv.state) if (!cls.state && (!connectinfo.trying || sv.state != ss_clustermode) && sv.state)
{ {
const char *lbp; const char *lbp;
@ -951,7 +946,7 @@ void CL_CheckForResend (void)
NET_AdrToString(data, sizeof(data), &connectinfo.adr); NET_AdrToString(data, sizeof(data), &connectinfo.adr);
/*eat up the server's packets, to clear any lingering loopback packets (like disconnect commands... yes this might cause packetloss for other clients)*/ /*eat up the server's packets, to clear any lingering loopback packets (like disconnect commands... yes this might cause packetloss for other clients)*/
while(NET_GetPacket (NS_SERVER, 0) >= 0) while(NET_GetPacket (svs.sockets, 0) >= 0)
{ {
} }
net_message.packing = SZ_RAWBYTES; net_message.packing = SZ_RAWBYTES;
@ -1119,7 +1114,7 @@ void CL_CheckForResend (void)
if (contype & 1) if (contype & 1)
{ {
Q_snprintfz (data, sizeof(data), "%c%c%c%cgetchallenge\n", 255, 255, 255, 255); Q_snprintfz (data, sizeof(data), "%c%c%c%cgetchallenge\n", 255, 255, 255, 255);
switch(NET_SendPacket (NS_CLIENT, strlen(data), data, &connectinfo.adr)) switch(NET_SendPacket (cls.sockets, strlen(data), data, &connectinfo.adr))
{ {
case NETERR_CLOGGED: //temporary failure case NETERR_CLOGGED: //temporary failure
case NETERR_SENT: //yay, works! case NETERR_SENT: //yay, works!
@ -1159,7 +1154,7 @@ void CL_CheckForResend (void)
MSG_WriteString(&sb, "getchallenge"); MSG_WriteString(&sb, "getchallenge");
*(int*)sb.data = LongSwap(NETFLAG_CTL | sb.cursize); *(int*)sb.data = LongSwap(NETFLAG_CTL | sb.cursize);
switch(NET_SendPacket (NS_CLIENT, sb.cursize, sb.data, &connectinfo.adr)) switch(NET_SendPacket (cls.sockets, sb.cursize, sb.data, &connectinfo.adr))
{ {
case NETERR_CLOGGED: //temporary failure case NETERR_CLOGGED: //temporary failure
case NETERR_SENT: //yay, works! case NETERR_SENT: //yay, works!
@ -1540,7 +1535,7 @@ void CL_Rcon_f (void)
} }
} }
NET_SendPacket (NS_CLIENT, strlen(message)+1, message, &to); NET_SendPacket (cls.sockets, strlen(message)+1, message, &to);
} }
void CL_BlendFog(fogstate_t *result, fogstate_t *oldf, float time, fogstate_t *newf) void CL_BlendFog(fogstate_t *result, fogstate_t *oldf, float time, fogstate_t *newf)
@ -2659,7 +2654,7 @@ void CL_Packet_f (void)
} }
*out = 0; *out = 0;
NET_SendPacket (NS_CLIENT, out-send, send, &adr); NET_SendPacket (cls.sockets, out-send, send, &adr);
if (Cmd_FromGamecode()) if (Cmd_FromGamecode())
{ {
@ -2905,7 +2900,7 @@ void CL_ConnectionlessPacket (void)
Q_snprintfz(data+6, sizeof(data)-6, "%i %i", atoi(MSG_ReadString()), cls.realip_ident); Q_snprintfz(data+6, sizeof(data)-6, "%i %i", atoi(MSG_ReadString()), cls.realip_ident);
len = strlen(data); len = strlen(data);
NET_SendPacket (NS_CLIENT, len, &data, &net_from); NET_SendPacket (cls.sockets, len, &data, &net_from);
return; return;
} }
@ -2954,7 +2949,7 @@ void CL_ConnectionlessPacket (void)
{ {
connectinfo.istransfer = true; connectinfo.istransfer = true;
connectinfo.adr = adr; connectinfo.adr = adr;
NET_SendPacket (NS_CLIENT, strlen(data), data, &adr); NET_SendPacket (cls.sockets, strlen(data), data, &adr);
} }
} }
return; return;
@ -3205,7 +3200,7 @@ void CL_ConnectionlessPacket (void)
//server says it can do tls. //server says it can do tls.
char *pkt = va("%c%c%c%cdtlsconnect %i", 255, 255, 255, 255, connectinfo.challenge); char *pkt = va("%c%c%c%cdtlsconnect %i", 255, 255, 255, 255, connectinfo.challenge);
NET_SendPacket (NS_CLIENT, strlen(pkt), pkt, &net_from); NET_SendPacket (cls.sockets, strlen(pkt), pkt, &net_from);
return; return;
} }
if (connectinfo.dtlsupgrade == DTLS_REQUIRE) if (connectinfo.dtlsupgrade == DTLS_REQUIRE)
@ -3730,7 +3725,7 @@ void CL_ReadPackets (void)
if (cls.state == ca_disconnected) if (cls.state == ca_disconnected)
{ //connect to nq servers, but don't get confused with sequenced packets. { //connect to nq servers, but don't get confused with sequenced packets.
if (NET_WasSpecialPacket(NS_CLIENT)) if (NET_WasSpecialPacket(cls.sockets))
continue; continue;
#ifdef NQPROT #ifdef NQPROT
CLNQ_ConnectionlessPacket (); CLNQ_ConnectionlessPacket ();
@ -3744,7 +3739,7 @@ void CL_ReadPackets (void)
if (!cls.demoplayback && if (!cls.demoplayback &&
!NET_CompareAdr (&net_from, &cls.netchan.remote_address)) !NET_CompareAdr (&net_from, &cls.netchan.remote_address))
{ {
if (NET_WasSpecialPacket(NS_CLIENT)) if (NET_WasSpecialPacket(cls.sockets))
continue; continue;
Con_DPrintf ("%s:sequenced packet from wrong server\n" Con_DPrintf ("%s:sequenced packet from wrong server\n"
,NET_AdrToString(adr, sizeof(adr), &net_from)); ,NET_AdrToString(adr, sizeof(adr), &net_from));
@ -4188,7 +4183,7 @@ void CL_FTP_f(void)
void CL_Fog_f(void) void CL_Fog_f(void)
{ {
int ftype = Q_strcasecmp(Cmd_Argv(0), "fog"); int ftype = Q_strcasecmp(Cmd_Argv(0), "fog");
if ((cl.fog_locked && !Cmd_FromGamecode()) || Cmd_Argc() <= 1) if ((cl.fog_locked && !Cmd_FromGamecode() && !cls.allow_cheats) || Cmd_Argc() <= 1)
{ {
if (Cmd_ExecLevel != RESTRICT_INSECURE) if (Cmd_ExecLevel != RESTRICT_INSECURE)
Con_Printf("Current fog %f (r:%f g:%f b:%f, a:%f bias:%f)\n", cl.fog[ftype].density, cl.fog[ftype].colour[0], cl.fog[ftype].colour[1], cl.fog[ftype].colour[2], cl.fog[ftype].alpha, cl.fog[ftype].depthbias); Con_Printf("Current fog %f (r:%f g:%f b:%f, a:%f bias:%f)\n", cl.fog[ftype].density, cl.fog[ftype].colour[0], cl.fog[ftype].colour[1], cl.fog[ftype].colour[2], cl.fog[ftype].alpha, cl.fog[ftype].depthbias);
@ -4420,7 +4415,6 @@ void CL_Init (void)
CSQC_RegisterCvarsAndThings(); CSQC_RegisterCvarsAndThings();
#endif #endif
Cvar_Register (&host_speeds, cl_controlgroup); Cvar_Register (&host_speeds, cl_controlgroup);
Cvar_Register (&developer, cl_controlgroup);
Cvar_Register (&cfg_save_name, cl_controlgroup); Cvar_Register (&cfg_save_name, cl_controlgroup);
@ -5307,7 +5301,9 @@ done:
// if (f->flags & HRF_DOWNLOADED) // if (f->flags & HRF_DOWNLOADED)
man->blockupdate = true; man->blockupdate = true;
BZ_Free(fdata); BZ_Free(fdata);
#ifdef PACKAGEMANAGER
PM_Shutdown(); PM_Shutdown();
#endif
FS_ChangeGame(man, true, true); FS_ChangeGame(man, true, true);
} }
else else
@ -6359,7 +6355,9 @@ Host_Init
*/ */
void Host_Init (quakeparms_t *parms) void Host_Init (quakeparms_t *parms)
{ {
#ifdef PACKAGEMANAGER
char engineupdated[MAX_OSPATH]; char engineupdated[MAX_OSPATH];
#endif
int man; int man;
com_parseutf8.ival = 1; //enable utf8 parsing even before cvars are registered. com_parseutf8.ival = 1; //enable utf8 parsing even before cvars are registered.
@ -6385,6 +6383,7 @@ void Host_Init (quakeparms_t *parms)
Cmd_Init (); Cmd_Init ();
COM_Init (); COM_Init ();
#ifdef PACKAGEMANAGER
//we have enough of the filesystem inited now that we can read the package list and figure out which engine was last installed. //we have enough of the filesystem inited now that we can read the package list and figure out which engine was last installed.
if (PM_FindUpdatedEngine(engineupdated, sizeof(engineupdated))) if (PM_FindUpdatedEngine(engineupdated, sizeof(engineupdated)))
{ {
@ -6402,6 +6401,8 @@ void Host_Init (quakeparms_t *parms)
} }
PM_Shutdown(); //will restart later as needed, but we need to be sure that no files are open or anything. PM_Shutdown(); //will restart later as needed, but we need to be sure that no files are open or anything.
} }
#endif
V_Init (); V_Init ();
NET_Init (); NET_Init ();
@ -6548,7 +6549,9 @@ void Host_Shutdown(void)
Validation_FlushFileList(); Validation_FlushFileList();
Cmd_Shutdown(); Cmd_Shutdown();
#ifdef PACKAGEMANAGER
PM_Shutdown(); PM_Shutdown();
#endif
Key_Unbindall_f(); Key_Unbindall_f();
#ifdef PLUGINS #ifdef PLUGINS

View file

@ -17,7 +17,7 @@ enum masterprotocol_e
MP_DPMASTER MP_DPMASTER
}; };
#if defined(CL_MASTER) && !defined(SERVERONLY) #if defined(CL_MASTER) && defined(HAVE_CLIENT)
#define SS_PROTOCOLMASK 0xf #define SS_PROTOCOLMASK 0xf
#define SS_UNKNOWN 0 #define SS_UNKNOWN 0
#define SS_QUAKEWORLD 1 #define SS_QUAKEWORLD 1
@ -134,7 +134,10 @@ typedef struct serverinfo_s
qbyte players; qbyte players;
qbyte maxplayers; qbyte maxplayers;
qbyte sends; qbyte sends;
qbyte status; //1=alive, 2=displayed qbyte status;
#define SRVSTATUS_ALIVE 1u //server is responding to pings
#define SRVSTATUS_DISPLAYED 2u //server passed all filters
#define SRVSTATUS_GLOBAL 4u //server was reported by one of the master servers (ie: global and not local)
qbyte numspectators; qbyte numspectators;
qbyte numhumans; qbyte numhumans;
@ -247,8 +250,6 @@ serverinfo_t *Master_SortedServer(int idx);
void Master_SetMaskString(qboolean or_, hostcachekey_t field, const char *param, slist_test_t testop); void Master_SetMaskString(qboolean or_, hostcachekey_t field, const char *param, slist_test_t testop);
void Master_SetMaskInteger(qboolean or_, hostcachekey_t field, int param, slist_test_t testop); void Master_SetMaskInteger(qboolean or_, hostcachekey_t field, int param, slist_test_t testop);
serverinfo_t *Master_FindRoute(netadr_t target); serverinfo_t *Master_FindRoute(netadr_t target);
#else
#define MasterInfo_WriteServers()
#endif #endif

View file

@ -541,7 +541,6 @@ typedef struct
#ifdef NQPROT #ifdef NQPROT
int signon; int signon;
#endif #endif
int language;
colourised_t *colourised; colourised_t *colourised;
qboolean nqexpectingstatusresponse; qboolean nqexpectingstatusresponse;

View file

@ -1028,7 +1028,7 @@ void CLQ3_SendAuthPacket(netadr_t *gameserver)
} }
MSG_WriteByte(&msg, 0); MSG_WriteByte(&msg, 0);
NET_SendPacket (NS_CLIENT, msg.cursize, msg.data, &authaddr); NET_SendPacket (cls.sockets, msg.cursize, msg.data, &authaddr);
} }
else else
Con_Printf(" failed\n"); Con_Printf(" failed\n");
@ -1062,7 +1062,7 @@ void CLQ3_SendConnectPacket(netadr_t *to, int challenge, int qport)
return; return;
} }
#endif #endif
NET_SendPacket (NS_CLIENT, msg.cursize, msg.data, to); NET_SendPacket (cls.sockets, msg.cursize, msg.data, to);
} }
#endif #endif

View file

@ -1061,7 +1061,7 @@ Handles cursor positioning, line wrapping, etc
================ ================
*/ */
#ifndef CLIENTONLY #ifdef HAVE_SERVER
extern redirect_t sv_redirected; extern redirect_t sv_redirected;
extern char sv_redirected_buf[8000]; extern char sv_redirected_buf[8000];
void SV_FlushRedirect (void); void SV_FlushRedirect (void);
@ -1103,7 +1103,7 @@ void VARGS Con_Printf (const char *fmt, ...)
return; return;
} }
#ifndef CLIENTONLY #ifdef HAVE_SERVER
// add to redirected message // add to redirected message
if (sv_redirected) if (sv_redirected)
{ {
@ -1147,7 +1147,7 @@ void VARGS Con_TPrintf (translation_t text, ...)
{ {
va_list argptr; va_list argptr;
char msg[MAXPRINTMSG]; char msg[MAXPRINTMSG];
const char *fmt = langtext(text, cls.language); const char *fmt = langtext(text, com_language);
va_start (argptr,text); va_start (argptr,text);
vsnprintf (msg,sizeof(msg), fmt,argptr); vsnprintf (msg,sizeof(msg), fmt,argptr);
@ -1161,7 +1161,7 @@ void VARGS Con_SafeTPrintf (translation_t text, ...)
{ {
va_list argptr; va_list argptr;
char msg[MAXPRINTMSG]; char msg[MAXPRINTMSG];
const char *fmt = langtext(text, cls.language); const char *fmt = langtext(text, com_language);
va_start (argptr,text); va_start (argptr,text);
vsnprintf (msg,sizeof(msg), fmt,argptr); vsnprintf (msg,sizeof(msg), fmt,argptr);

View file

@ -2946,22 +2946,12 @@ qboolean PM_CanInstall(const char *packagename)
{ {
return false; return false;
} }
void PM_Command_f (void)
{
Con_Printf("Package Manager is not implemented in this build\n");
}
void PM_LoadPackages(searchpath_t **oldpaths, const char *parent_pure, const char *parent_logical, searchpath_t *search, unsigned int loadstuff, int minpri, int maxpri)
{
}
void PM_EnumeratePlugins(void (*callback)(const char *name)) void PM_EnumeratePlugins(void (*callback)(const char *name))
{ {
} }
void PM_ManifestPackage(const char *metaname, int security) void PM_ManifestPackage(const char *metaname, int security)
{ {
} }
void PM_Shutdown(void)
{
}
int PM_IsApplying(qboolean listsonly) int PM_IsApplying(qboolean listsonly)
{ {
return false; return false;

View file

@ -577,6 +577,7 @@ qboolean MultiBeginGame (union menuoption_s *option,struct menu_s *menu, int key
if (cls.state) if (cls.state)
Cbuf_AddText("disconnect\n", RESTRICT_LOCAL); Cbuf_AddText("disconnect\n", RESTRICT_LOCAL);
Cbuf_AddText("sv_playerslots \"\"\n", RESTRICT_LOCAL); //just in case.
Cbuf_AddText(va("maxclients \"%s\"\n", numplayeroptions[info->numplayers->selectedoption]), RESTRICT_LOCAL); Cbuf_AddText(va("maxclients \"%s\"\n", numplayeroptions[info->numplayers->selectedoption]), RESTRICT_LOCAL);
if (info->rundedicated->value) if (info->rundedicated->value)
Cbuf_AddText("setrenderer dedicated\n", RESTRICT_LOCAL); Cbuf_AddText("setrenderer dedicated\n", RESTRICT_LOCAL);
@ -711,7 +712,7 @@ void M_Menu_GameOptions_f (void)
info->mapnameedit = MC_AddEdit (menu, 64, 160, y, "map", "start"); info->mapnameedit = MC_AddEdit (menu, 64, 160, y, "map", "start");
y += 16; y += 16;
menu->cursoritem = (menuoption_t*)MC_AddWhiteText(menu, 54, 0, 32, NULL, false); menu->cursoritem = (menuoption_t*)MC_AddWhiteText(menu, 54, 0, menu->selecteditem->common.posy, NULL, false);
info->lowercolour = bottomcolor.value; info->lowercolour = bottomcolor.value;

View file

@ -75,7 +75,7 @@ enum
ASPECT2D_CUSTOM, ASPECT2D_CUSTOM,
}; };
qboolean M_Vid_GetMode(int num, int *w, int *h) qboolean M_Vid_GetMode(qboolean forfullscreen, int num, int *w, int *h)
{ {
int i; int i;

View file

@ -82,6 +82,7 @@ static void SV_SetMaster_f (void);
extern cvar_t sv_public; extern cvar_t sv_public;
extern cvar_t sv_reportheartbeats; extern cvar_t sv_reportheartbeats;
extern cvar_t sv_heartbeat_interval;
extern cvar_t sv_listen_qw; extern cvar_t sv_listen_qw;
extern cvar_t sv_listen_nq; extern cvar_t sv_listen_nq;
@ -98,7 +99,7 @@ typedef struct {
qboolean resolving; //set any time the cvar is modified qboolean resolving; //set any time the cvar is modified
netadr_t adr[MAX_MASTER_ADDRESSES]; netadr_t adr[MAX_MASTER_ADDRESSES];
} net_masterlist_t; } net_masterlist_t;
net_masterlist_t net_masterlist[] = { static net_masterlist_t net_masterlist[] = {
#ifndef QUAKETC #ifndef QUAKETC
//user-specified master lists. //user-specified master lists.
{MP_QUAKEWORLD, CVARC("net_qwmaster1", "", Net_Masterlist_Callback)}, {MP_QUAKEWORLD, CVARC("net_qwmaster1", "", Net_Masterlist_Callback)},
@ -244,12 +245,14 @@ void SV_Master_SingleHeartbeat(net_masterlist_t *master)
char adr[MAX_ADR_SIZE]; char adr[MAX_ADR_SIZE];
netadr_t *na; netadr_t *na;
int i; int i;
int e;
for (i = 0; i < MAX_MASTER_ADDRESSES; i++) for (i = 0; i < MAX_MASTER_ADDRESSES; i++)
{ {
na = &master->adr[i]; na = &master->adr[i];
if (na->port) if (na->port)
{ {
e = -1;
switch(master->protocol) switch(master->protocol)
{ {
case MP_QUAKEWORLD: case MP_QUAKEWORLD:
@ -272,32 +275,26 @@ void SV_Master_SingleHeartbeat(net_masterlist_t *master)
madeqwstring = true; madeqwstring = true;
} }
if (sv_reportheartbeats.value) e = NET_SendPacket (svs.sockets, strlen(string), string, na);
{
if (sv_reportheartbeats.ival != 2 || !master->announced)
Con_TPrintf ("Sending heartbeat to %s (%s)\n", NET_AdrToString (adr, sizeof(adr), na), master->cv.string);
master->announced = true;
}
NET_SendPacket (NS_SERVER, strlen(string), string, na);
} }
break; break;
#ifdef Q2SERVER #ifdef Q2SERVER
case MP_QUAKE2: case MP_QUAKE2:
if (svs.gametype == GT_QUAKE2 && sv_listen_qw.value) //set listen to 1 to allow qw connections, 2 to allow nq connections too. if (svs.gametype == GT_QUAKE2 && sv_listen_qw.value) //sv_listen==sv_listen_qw, yes, weird.
{ {
if (sv_reportheartbeats.value) char *str = "\377\377\377\377heartbeat\n%s\n%s";
char info[8192];
char q2users[8192];
size_t i;
const char *infos[] = {"hostname", "*version", "deathmatch", "fraglimit", "timelimit", "gamedir", "mapname", "maxclients", "dmflags", NULL};
InfoBuf_ToString(&svs.info, info, sizeof(info), NULL, NULL, infos, NULL, NULL);
q2users[0] = 0;
for (i = 0; i < sv.allocated_client_slots; i++)
{ {
if (sv_reportheartbeats.ival != 2 || !master->announced) if (svs.clients[i].state >= cs_connected)
Con_TPrintf ("Sending heartbeat to %s (%s)\n", NET_AdrToString (adr, sizeof(adr), na), master->cv.string); Q_strncatz(q2users, va("%i %i \"%s\"\n", svs.clients[i].old_frags, SV_CalcPing(&svs.clients[i], false), svs.clients[i].name), sizeof(q2users));
master->announced = true;
}
{
char *str = "\377\377\377\377heartbeat\n%s";
char *q2statusresp = "";
NET_SendPacket (NS_SERVER, strlen(str), va(str, q2statusresp), na);
} }
e = NET_SendPacket (svs.sockets, strlen(str), va(str, info, q2users), na);
} }
break; break;
#endif #endif
@ -310,23 +307,56 @@ void SV_Master_SingleHeartbeat(net_masterlist_t *master)
#if defined(NQPROT) && !defined(QUAKETC) #if defined(NQPROT) && !defined(QUAKETC)
if (sv_listen_dp.value || sv_listen_nq.value) if (sv_listen_dp.value || sv_listen_nq.value)
#endif #endif
{
if (sv_reportheartbeats.value)
{
if (sv_reportheartbeats.ival != 2 || !master->announced)
Con_TPrintf ("Sending heartbeat to %s (%s)\n", NET_AdrToString (adr, sizeof(adr), na), master->cv.string);
master->announced = true;
}
{ {
//darkplaces here refers to the master server protocol, rather than the game protocol //darkplaces here refers to the master server protocol, rather than the game protocol
//(specifies that the server responds to infoRequest packets from the master) //(specifies that the server responds to infoRequest packets from the master)
char *str = "\377\377\377\377heartbeat DarkPlaces\x0A"; char *str = "\377\377\377\377heartbeat DarkPlaces\x0A";
NET_SendPacket (NS_SERVER, strlen(str), str, na); e = NET_SendPacket (svs.sockets, strlen(str), str, na);
}
} }
break; break;
default: default:
e = -2;
break;
}
switch(e)
{
case -1: //master not enabled for this game type
break;
case NETERR_SENT:
if (sv_reportheartbeats.value)
{
if (sv_reportheartbeats.ival != 2 || !master->announced)
{
COM_Parse(master->cv.string);
Con_TPrintf ("Sending heartbeat to %s (%s)\n", NET_AdrToString (adr, sizeof(adr), na), com_token);
}
master->announced = true;
}
break;
case NETERR_NOROUTE:
if (sv_reportheartbeats.value)
{
if (sv_reportheartbeats.ival != 2 || !master->announced)
{
COM_Parse(master->cv.string);
Con_TPrintf (CON_WARNING"No route for heartbeat to %s (%s)\n", NET_AdrToString (adr, sizeof(adr), na), com_token);
}
master->announced = true;
}
break;
default:
case NETERR_DISCONNECTED:
case NETERR_MTU:
case NETERR_CLOGGED:
if (sv_reportheartbeats.value)
{
if (sv_reportheartbeats.ival != 2 || !master->announced)
{
COM_Parse(master->cv.string);
Con_TPrintf (CON_ERROR"Failed to send heartbeat to %s (%s)\n", NET_AdrToString (adr, sizeof(adr), na), com_token);
}
master->announced = true;
}
break; break;
} }
} }
@ -395,12 +425,12 @@ void SV_Master_Worker_Resolved(void *ctx, void *data, size_t a, size_t b)
{ {
#ifdef Q2SERVER #ifdef Q2SERVER
case MP_QUAKE2: case MP_QUAKE2:
NET_SendPacket (NS_SERVER, 8, "\xff\xff\xff\xffping", na); NET_SendPacket (svs.sockets, 8, "\xff\xff\xff\xffping", na);
break; break;
#endif #endif
case MP_QUAKEWORLD: case MP_QUAKEWORLD:
//qw does this for some reason, keep the behaviour even though its unreliable thus pointless //qw does this for some reason, keep the behaviour even though its unreliable thus pointless
NET_SendPacket (NS_SERVER, 2, "k\0", na); NET_SendPacket (svs.sockets, 2, "k\0", na);
break; break;
default: default:
break; break;
@ -445,18 +475,18 @@ Send a message to the master every few minutes to
let it know we are alive, and log information let it know we are alive, and log information
================ ================
*/ */
#define HEARTBEAT_SECONDS 300
void SV_Master_Heartbeat (void) void SV_Master_Heartbeat (void)
{ {
int i; int i;
int interval = bound(90, sv_heartbeat_interval.ival, 600);
if (sv_public.ival<=0 || SSV_IsSubServer()) if (sv_public.ival<=0 || SSV_IsSubServer())
return; return;
if (realtime-HEARTBEAT_SECONDS - svs.last_heartbeat < HEARTBEAT_SECONDS) if (realtime-interval - svs.last_heartbeat < interval)
return; // not time to send yet return; // not time to send yet
svs.last_heartbeat = realtime-HEARTBEAT_SECONDS; svs.last_heartbeat = realtime-interval;
svs.heartbeat_sequence++; svs.heartbeat_sequence++;
@ -605,7 +635,7 @@ void SV_Master_Shutdown (void)
if (sv_reportheartbeats.value) if (sv_reportheartbeats.value)
Con_TPrintf ("Sending shutdown to %s\n", NET_AdrToString (adr, sizeof(adr), na)); Con_TPrintf ("Sending shutdown to %s\n", NET_AdrToString (adr, sizeof(adr), na));
NET_SendPacket (NS_SERVER, strlen(string), string, na); NET_SendPacket (svs.sockets, strlen(string), string, na);
break; break;
//dp has no shutdown //dp has no shutdown
default: default:
@ -736,7 +766,7 @@ void Master_HideServer(serverinfo_t *server)
else else
i++; i++;
} }
server->status &= ~2u; server->status &= ~SRVSTATUS_DISPLAYED;
} }
void Master_InsertAt(serverinfo_t *server, int pos) void Master_InsertAt(serverinfo_t *server, int pos)
@ -754,7 +784,7 @@ void Master_InsertAt(serverinfo_t *server, int pos)
visibleservers[pos] = server; visibleservers[pos] = server;
numvisibleservers++; numvisibleservers++;
server->status |= 2u; server->status |= SRVSTATUS_DISPLAYED;
} }
qboolean Master_CompareInteger(int a, int b, slist_test_t rule) qboolean Master_CompareInteger(int a, int b, slist_test_t rule)
@ -907,8 +937,8 @@ qboolean Master_PassesMasks(serverinfo_t *a)
qboolean val, res; qboolean val, res;
// qboolean enabled; // qboolean enabled;
//always filter out dead unresponsive servers. //always filter out dead/unresponsive servers.
if (!(a->status & 1)) if (!(a->status & SRVSTATUS_ALIVE))
return false; return false;
val = 1; val = 1;
@ -1066,7 +1096,7 @@ void Master_ShowServer(serverinfo_t *server)
void Master_ResortServer(serverinfo_t *server) void Master_ResortServer(serverinfo_t *server)
{ {
if (server->status&2u) if (server->status&SRVSTATUS_DISPLAYED)
{ {
if (!Master_PassesMasks(server)) if (!Master_PassesMasks(server))
Master_HideServer(server); Master_HideServer(server);
@ -1092,7 +1122,7 @@ int Master_SortServers(void)
{ {
numvisibleservers = 0; numvisibleservers = 0;
for (server = firstserver; server; server = server->next) for (server = firstserver; server; server = server->next)
server->status &= ~2u; server->status &= ~SRVSTATUS_DISPLAYED;
} }
for (server = firstserver; server; server = server->next) for (server = firstserver; server; server = server->next)
@ -2343,6 +2373,7 @@ void MasterInfo_ProcessHTTP(struct dl_download *dl)
Master_ResortServer(info); Master_ResortServer(info);
} }
info->status |= SRVSTATUS_GLOBAL;
} }
} }
@ -2450,6 +2481,7 @@ char *jsonnode(int level, char *node)
Master_ResortServer(info); Master_ResortServer(info);
} }
info->status |= SRVSTATUS_GLOBAL;
} }
return node; return node;
@ -2655,7 +2687,7 @@ void MasterInfo_Refresh(qboolean doreset)
if (doreset) if (doreset)
{ {
for (info = firstserver; info; info = info->next) for (info = firstserver; info; info = info->next)
info->status &= ~1; //hide until we get a new response from it. info->status &= ~SRVSTATUS_ALIVE; //hide until we get a new response from it.
} }
loadedone = false; loadedone = false;
@ -2675,7 +2707,7 @@ void MasterInfo_Refresh(qboolean doreset)
#ifndef QUAKETC #ifndef QUAKETC
Master_AddMaster("255.255.255.255:"STRINGIFY(PORT_QWSERVER), MT_BCAST, MP_QUAKEWORLD, "Nearby QuakeWorld UDP servers."); Master_AddMaster("255.255.255.255:"STRINGIFY(PORT_QWSERVER), MT_BCAST, MP_QUAKEWORLD, "Nearby QuakeWorld UDP servers.");
// Master_AddMasterHTTP("http://www.gameaholic.com/servers/qspy-quakeworld", MT_MASTERHTTP, MP_QUAKEWORLD, "gameaholic's QW master"); // Master_AddMasterHTTP("http://www.gameaholic.com/servers/qspy-quakeworld", MT_MASTERHTTP, MP_QUAKEWORLD, "gameaholic's QW master");
Master_AddMasterHTTP("https://www.quakeservers.net/lists/servers/global.txt",MT_MASTERHTTP, MP_QUAKEWORLD, "QuakeServers.net (http)"); // Master_AddMasterHTTP("https://www.quakeservers.net/lists/servers/global.txt",MT_MASTERHTTP, MP_QUAKEWORLD, "QuakeServers.net (http)");
#endif #endif
#ifdef NQPROT #ifdef NQPROT
// Master_AddMasterHTTP("http://www.gameaholic.com/servers/qspy-quake", MT_MASTERHTTP, MP_NETQUAKE, "gameaholic's NQ master"); // Master_AddMasterHTTP("http://www.gameaholic.com/servers/qspy-quake", MT_MASTERHTTP, MP_NETQUAKE, "gameaholic's NQ master");
@ -2904,7 +2936,7 @@ unsigned int Master_NumAlive(void)
for (info = firstserver; info; info = info->next) for (info = firstserver; info; info = info->next)
{ {
if (info->status&1u) if (info->status&SRVSTATUS_ALIVE)
count++; count++;
} }
return count; return count;
@ -3032,7 +3064,7 @@ int CL_ReadServerInfo(char *msg, enum masterprotocol_e prototype, qboolean favor
info->refreshtime = 0; info->refreshtime = 0;
} }
info->status |= 1u; info->status |= SRVSTATUS_ALIVE;
nl = strchr(msg, '\n'); nl = strchr(msg, '\n');
if (nl) if (nl)
@ -3484,6 +3516,7 @@ void CL_MasterListParse(netadrtype_t adrtype, int type, qboolean slashpad)
if ((old->special & (SS_PROTOCOLMASK)) != (type & (SS_PROTOCOLMASK))) if ((old->special & (SS_PROTOCOLMASK)) != (type & (SS_PROTOCOLMASK)))
old->special = type | (old->special & (SS_FAVORITE|SS_LOCAL)); old->special = type | (old->special & (SS_FAVORITE|SS_LOCAL));
old->sends = 1; //reset. old->sends = 1; //reset.
old->status |= SRVSTATUS_GLOBAL;
Z_Free(info); Z_Free(info);
} }
else else
@ -3492,6 +3525,7 @@ void CL_MasterListParse(netadrtype_t adrtype, int type, qboolean slashpad)
info->special = type; info->special = type;
info->refreshtime = 0; info->refreshtime = 0;
info->status |= SRVSTATUS_GLOBAL;
Q_snprintfz(info->name, sizeof(info->name), "%s (via %s)", NET_AdrToString(adr, sizeof(adr), &info->adr), madr); Q_snprintfz(info->name, sizeof(info->name), "%s (via %s)", NET_AdrToString(adr, sizeof(adr), &info->adr), madr);

View file

@ -707,14 +707,15 @@ void QCBUILTIN PF_soundlength (pubprogfuncs_t *prinst, struct globalvars_s *pr_g
} }
} }
qboolean M_Vid_GetMode(int num, int *w, int *h); qboolean M_Vid_GetMode(qboolean forfullscreen, int num, int *w, int *h);
//a bit pointless really //a bit pointless really
void QCBUILTIN PF_cl_getresolution (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) void QCBUILTIN PF_cl_getresolution (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{ {
float mode = G_FLOAT(OFS_PARM0); float mode = G_FLOAT(OFS_PARM0);
// qboolean fixedmodes = (prinst->callargc >= 2)?!G_FLOAT(OFS_PARM1):false; //if true, we should return sane-sized modes suitable for a window... or the mod could make up its own, but whatever. qboolean forfullscreen = (prinst->callargc >= 2)?G_FLOAT(OFS_PARM1):true; //if true, we should return queried video modes... or the mod could make up its own, but whatever.
float *ret = G_VECTOR(OFS_RETURN); float *ret = G_VECTOR(OFS_RETURN);
int w, h; int w, h;
float pixelheight = 0;
w=h=0; w=h=0;
if (mode == -1) if (mode == -1)
@ -723,11 +724,11 @@ void QCBUILTIN PF_cl_getresolution (pubprogfuncs_t *prinst, struct globalvars_s
Sys_GetDesktopParameters(&w, &h, &bpp, &rate); Sys_GetDesktopParameters(&w, &h, &bpp, &rate);
} }
else else
M_Vid_GetMode(mode, &w, &h); M_Vid_GetMode(forfullscreen, mode, &w, &h);
ret[0] = w; ret[0] = w;
ret[1] = h; ret[1] = h;
ret[2] = (w&&h)?1:0; ret[2] = pixelheight?pixelheight:((w&&h)?1:0); //pixelheight
} }
#ifdef CL_MASTER #ifdef CL_MASTER
@ -988,7 +989,7 @@ static struct modlist_s
static size_t nummods; static size_t nummods;
static qboolean modsinited; static qboolean modsinited;
static qboolean Mods_AddManifest(void *usr, ftemanifest_t *man) /*static qboolean Mods_AddManifest(void *usr, ftemanifest_t *man)
{ {
int i = nummods; int i = nummods;
modlist = BZ_Realloc(modlist, (i+1) * sizeof(*modlist)); modlist = BZ_Realloc(modlist, (i+1) * sizeof(*modlist));
@ -997,7 +998,7 @@ static qboolean Mods_AddManifest(void *usr, ftemanifest_t *man)
modlist[i].description = man->formalname; modlist[i].description = man->formalname;
nummods = i+1; nummods = i+1;
return true; return true;
} }*/
static int QDECL Mods_AddGamedir(const char *fname, qofs_t fsize, time_t mtime, void *usr, searchpathfuncs_t *spath) static int QDECL Mods_AddGamedir(const char *fname, qofs_t fsize, time_t mtime, void *usr, searchpathfuncs_t *spath)
{ {
char *f; char *f;
@ -1027,7 +1028,7 @@ static int QDECL Mods_AddGamedir(const char *fname, qofs_t fsize, time_t mtime,
return true; return true;
} }
} }
f = FS_MallocFile(va("%s%s/modinfo.txt", usr, gamedir), FS_SYSTEM, NULL); f = FS_MallocFile(va("%s%s/modinfo.txt", (const char*)usr, gamedir), FS_SYSTEM, NULL);
if (f) if (f)
{ {
modlist = BZ_Realloc(modlist, (i+1) * sizeof(*modlist)); modlist = BZ_Realloc(modlist, (i+1) * sizeof(*modlist));
@ -1070,7 +1071,6 @@ void QCBUILTIN PF_cl_getgamedirinfo(pubprogfuncs_t *prinst, struct globalvars_s
if (modlist[diridx].description) if (modlist[diridx].description)
RETURN_TSTRING(modlist[diridx].description); RETURN_TSTRING(modlist[diridx].description);
break; break;
//fallthrough
case 0: //name case 0: //name
RETURN_TSTRING(modlist[diridx].gamedir); RETURN_TSTRING(modlist[diridx].gamedir);
break; break;
@ -1091,8 +1091,8 @@ void QCBUILTIN PF_cl_SendPacket(pubprogfuncs_t *prinst, struct globalvars_s *pr_
char *send = Z_Malloc(4+strlen(contents)); char *send = Z_Malloc(4+strlen(contents));
send[0] = send[1] = send[2] = send[3] = 0xff; send[0] = send[1] = send[2] = send[3] = 0xff;
memcpy(send+4, contents, strlen(contents)); memcpy(send+4, contents, strlen(contents));
//FIXME: NS_CLIENT is likely to change its port randomly... //FIXME: this is likely to change its port randomly...
G_FLOAT(OFS_RETURN) = NET_SendPacket(NS_CLIENT, 4+strlen(contents), send, &to); G_FLOAT(OFS_RETURN) = NET_SendPacket(cls.sockets, 4+strlen(contents), send, &to);
Z_Free(send); Z_Free(send);
} }
} }

View file

@ -99,13 +99,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#define QUAKEDEF_H__ #define QUAKEDEF_H__
#ifdef SERVERONLY
#define isDedicated true
#endif
#ifdef CLIENTONLY
#define isDedicated false
#endif
#ifdef __linux__ #ifdef __linux__
#define PNG_SUCKS_WITH_SETJMP //cos it does. #define PNG_SUCKS_WITH_SETJMP //cos it does.
#endif #endif
@ -154,8 +147,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
extern "C" { extern "C" {
#endif #endif
#include "translate.h"
#include "common.h" #include "common.h"
#include "bspfile.h" #include "bspfile.h"
#include "vid.h" #include "vid.h"
@ -163,6 +154,7 @@ extern "C" {
#include "zone.h" #include "zone.h"
#include "mathlib.h" #include "mathlib.h"
#include "cvar.h" #include "cvar.h"
#include "translate.h"
#include "net.h" #include "net.h"
#ifndef WEBSVONLY #ifndef WEBSVONLY
#include "protocol.h" #include "protocol.h"
@ -375,8 +367,11 @@ void COM_AssertMainThread(const char *msg);
extern qboolean msg_suppress_1; // suppresses resolution and cache size console output extern qboolean msg_suppress_1; // suppresses resolution and cache size console output
// an fullscreen DIB focus gain/loss // an fullscreen DIB focus gain/loss
#ifndef HAVE_CLIENT
#if !defined(SERVERONLY) && !defined(CLIENTONLY) #define isDedicated true
#elif !defined(HAVE_SERVER)
#define isDedicated false
#else
extern qboolean isDedicated; extern qboolean isDedicated;
#endif #endif
extern qboolean wantquit; //flagged if we want to force a quit, safely breaking out of any modal stuff extern qboolean wantquit; //flagged if we want to force a quit, safely breaking out of any modal stuff

View file

@ -1711,6 +1711,7 @@ char *particle_set_high =
"surfaceparm nodlight\n" "surfaceparm nodlight\n"
"glslprogram\n" "glslprogram\n"
"{\n" "{\n"
"!!samps screen=0\n"
"varying vec2 tcoord;\n" "varying vec2 tcoord;\n"
"varying vec4 scoord;\n" "varying vec4 scoord;\n"
"varying float alph;\n" "varying float alph;\n"
@ -1738,7 +1739,7 @@ char *particle_set_high =
// f = 1.0 - tcoord*tcoord; // f = 1.0 - tcoord*tcoord;
"if (f < 0.0) discard;\n" "if (f < 0.0) discard;\n"
"f *= alph;\n" "f *= alph;\n"
"gl_FragColor = texture2D(s_t0, nst - tcoord*f);\n" "gl_FragColor = texture2D(s_screen, nst - tcoord*f);\n"
"}\n" "}\n"
"#endif\n" "#endif\n"
"}\n" "}\n"

View file

@ -127,7 +127,7 @@ cvar_t r_refractreflect_scale = CVARD ("r_refractreflect_scale", "0.5", "Use
cvar_t r_drawviewmodel = CVARF ("r_drawviewmodel", "1", CVAR_ARCHIVE); cvar_t r_drawviewmodel = CVARF ("r_drawviewmodel", "1", CVAR_ARCHIVE);
cvar_t r_drawviewmodelinvis = CVAR ("r_drawviewmodelinvis", "0"); cvar_t r_drawviewmodelinvis = CVAR ("r_drawviewmodelinvis", "0");
cvar_t r_dynamic = CVARFD ("r_dynamic", IFMINIMAL("0","1"), cvar_t r_dynamic = CVARFD ("r_dynamic", IFMINIMAL("0","1"),
CVAR_ARCHIVE, "-1: the engine will bypass dlights completely, allowing for better batching.\n0: no standard dlights at all.\n1: coloured dlights will be used, they may show through walls. These are not realtime things.\n2: The dlights will be forced to monochrome (this does not affect coronas/flashblends/rtlights attached to the same light)."); CVAR_ARCHIVE, "-1: the engine will use only pvs to determine which surfaces are visible. This can significantly reduce CPU time, but only if there are many surfaces with few textures visible from the camera.\n0: no standard dlights at all.\n1: coloured dlights will be used, they may show through walls. These are not realtime things.\n2: The dlights will be forced to monochrome (this does not affect coronas/flashblends/rtlights attached to the same light).");
cvar_t r_fastturb = CVARF ("r_fastturb", "0", cvar_t r_fastturb = CVARF ("r_fastturb", "0",
CVAR_SHADERSYSTEM); CVAR_SHADERSYSTEM);
cvar_t r_fastsky = CVARF ("r_fastsky", "0", cvar_t r_fastsky = CVARF ("r_fastsky", "0",

View file

@ -104,7 +104,7 @@ cvar_t snd_khz = CVARAFD( "s_khz", DEFAULT_SND_KHZ,
"snd_khz", CVAR_ARCHIVE, "Sound speed, in kilohertz. Common values are 11, 22, 44, 48. Values above 1000 are explicitly in hertz."); "snd_khz", CVAR_ARCHIVE, "Sound speed, in kilohertz. Common values are 11, 22, 44, 48. Values above 1000 are explicitly in hertz.");
cvar_t snd_inactive = CVARAFD( "s_inactive", "1", cvar_t snd_inactive = CVARAFD( "s_inactive", "1",
"snd_inactive", CVAR_ARCHIVE, "snd_inactive", CVAR_ARCHIVE,
"Play sound while application is inactive (ex. tabbed out). Needs a snd_restart if changed." "Play sound while application is inactive (ie: tabbed out). Needs a snd_restart if changed."
); //set if you want sound even when tabbed out. ); //set if you want sound even when tabbed out.
cvar_t _snd_mixahead = CVARAFD( "s_mixahead", "0.1", cvar_t _snd_mixahead = CVARAFD( "s_mixahead", "0.1",
"_snd_mixahead", CVAR_ARCHIVE, "Specifies how many seconds to prebuffer audio. Lower values give less latency, but might result in crackling. Different hardware/drivers have different tolerances, and this setting may be ignored completely where drivers are expected to provide their own tolerances."); "_snd_mixahead", CVAR_ARCHIVE, "Specifies how many seconds to prebuffer audio. Lower values give less latency, but might result in crackling. Different hardware/drivers have different tolerances, and this setting may be ignored completely where drivers are expected to provide their own tolerances.");
@ -152,7 +152,7 @@ cvar_t snd_voip_send = CVARFD("cl_voip_send", "0", CVAR_ARCHIVE, "Sends voice-
cvar_t snd_voip_test = CVARD("cl_voip_test", "0", "If 1, enables you to hear your own voice directly, bypassing the server and thus without networking latency, but is fine for checking audio levels. Note that sv_voip_echo can be set if you want to include latency and packetloss considerations, but setting that cvar requires server admin access and is thus much harder to use."); cvar_t snd_voip_test = CVARD("cl_voip_test", "0", "If 1, enables you to hear your own voice directly, bypassing the server and thus without networking latency, but is fine for checking audio levels. Note that sv_voip_echo can be set if you want to include latency and packetloss considerations, but setting that cvar requires server admin access and is thus much harder to use.");
cvar_t snd_voip_vad_threshhold = CVARFD("cl_voip_vad_threshhold", "15", CVAR_ARCHIVE, "This is the threshhold for voice-activation-detection when sending voip data"); cvar_t snd_voip_vad_threshhold = CVARFD("cl_voip_vad_threshhold", "15", CVAR_ARCHIVE, "This is the threshhold for voice-activation-detection when sending voip data");
cvar_t snd_voip_vad_delay = CVARD("cl_voip_vad_delay", "0.3", "Keeps sending voice data for this many seconds after voice activation would normally stop"); cvar_t snd_voip_vad_delay = CVARD("cl_voip_vad_delay", "0.3", "Keeps sending voice data for this many seconds after voice activation would normally stop");
cvar_t snd_voip_capturingvol = CVARAFD("cl_voip_capturingvol", "0.5", NULL, CVAR_ARCHIVE, "Volume multiplier applied while capturing, to avoid your audio from being heard by others. Does not affect game volume when other speak (minimum of cl_voip_capturingvol and cl_voip_ducking is used)."); cvar_t snd_voip_capturingvol = CVARAFD("cl_voip_capturingvol", "0.5", NULL, CVAR_ARCHIVE, "Volume multiplier applied while capturing, to avoid your audio from being heard by others. Does not affect game volume when others speak (minimum of cl_voip_capturingvol and cl_voip_ducking is used).");
cvar_t snd_voip_showmeter = CVARAFD("cl_voip_showmeter", "1", NULL, CVAR_ARCHIVE, "Shows your speech volume above the standard hud. 0=hide, 1=show when transmitting, 2=ignore voice-activation disable"); cvar_t snd_voip_showmeter = CVARAFD("cl_voip_showmeter", "1", NULL, CVAR_ARCHIVE, "Shows your speech volume above the standard hud. 0=hide, 1=show when transmitting, 2=ignore voice-activation disable");
cvar_t snd_voip_play = CVARAFCD("cl_voip_play", "1", NULL, CVAR_ARCHIVE, S_Voip_Play_Callback, "Enables voip playback. Value is a volume scaler."); cvar_t snd_voip_play = CVARAFCD("cl_voip_play", "1", NULL, CVAR_ARCHIVE, S_Voip_Play_Callback, "Enables voip playback. Value is a volume scaler.");
@ -286,7 +286,11 @@ enum
VOIP_INVALID = 16 //not currently generating audio. VOIP_INVALID = 16 //not currently generating audio.
}; };
#ifdef NOLEGACY
#define VOIP_DEFAULT_CODEC VOIP_OPUS
#else
#define VOIP_DEFAULT_CODEC (cls.protocol==CP_QUAKEWORLD?VOIP_SPEEX_OLD:VOIP_OPUS) //opus is preferred, but ezquake is still common and only supports my first attempt at voice compression so favour that for quakeworld. #define VOIP_DEFAULT_CODEC (cls.protocol==CP_QUAKEWORLD?VOIP_SPEEX_OLD:VOIP_OPUS) //opus is preferred, but ezquake is still common and only supports my first attempt at voice compression so favour that for quakeworld.
#endif
static struct static struct
{ {
struct struct

View file

@ -114,16 +114,33 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#endif #endif
#endif #endif
#if defined(SERVERONLY) && defined(CLIENTONLY) #ifdef MASTERONLY
#define SV_MASTER
#undef SUBSERVERS
#undef PLUGINS
#undef HUFFNETWORK
#undef SUPPORT_ICE
#undef WEBCLIENT
#undef LOADERTHREAD
#undef PACKAGEMANAGER
#undef PACKAGE_PK3
#undef PACKAGE_Q1PAK
#undef PACKAGE_DOOMWAD
#undef PACKAGE_VPK
#undef PACKAGE_DZIP
#undef AVAIL_GZDEC
#else
#if defined(SERVERONLY) && defined(CLIENTONLY)
#undef CLIENTONLY //impossible build. assume the config had CLIENTONLY and they tried building a dedicated server #undef CLIENTONLY //impossible build. assume the config had CLIENTONLY and they tried building a dedicated server
#endif #endif
#ifndef WEBSVONLY #ifndef WEBSVONLY
#ifndef CLIENTONLY #ifndef CLIENTONLY
#define HAVE_SERVER #define HAVE_SERVER
#endif #endif
#ifndef SERVERONLY #ifndef SERVERONLY
#define HAVE_CLIENT #define HAVE_CLIENT
#endif #endif
#endif
#endif #endif
#ifndef HAVE_SERVER #ifndef HAVE_SERVER

View file

@ -65,7 +65,9 @@ cvar_t cfg_save_buttons = CVARFD("cfg_save_buttons", "0", CVAR_ARCHIVE|CVAR_NOTF
cvar_t cl_warncmd = CVARF("cl_warncmd", "1", CVAR_NOSAVE|CVAR_NORESET); cvar_t cl_warncmd = CVARF("cl_warncmd", "1", CVAR_NOSAVE|CVAR_NORESET);
cvar_t cl_aliasoverlap = CVARF("cl_aliasoverlap", "1", CVAR_NOTFROMSERVER); cvar_t cl_aliasoverlap = CVARF("cl_aliasoverlap", "1", CVAR_NOTFROMSERVER);
#ifdef HAVE_CLIENT
cvar_t tp_disputablemacros = CVARF("tp_disputablemacros", "1", CVAR_SEMICHEAT); cvar_t tp_disputablemacros = CVARF("tp_disputablemacros", "1", CVAR_SEMICHEAT);
#endif
//============================================================================= //=============================================================================
@ -120,9 +122,11 @@ static char *TP_MacroString (char *s, int *newaccesslevel, int *len)
macro = &macro_commands[i]; macro = &macro_commands[i];
if (!Q_strcasecmp(s, macro->name)) if (!Q_strcasecmp(s, macro->name))
{ {
#ifdef HAVE_CLIENT
if (macro->disputableintentions) if (macro->disputableintentions)
if (!tp_disputablemacros.ival) if (!tp_disputablemacros.ival)
*newaccesslevel = 0; *newaccesslevel = 0;
#endif
if (len) if (len)
*len = strlen(macro->name); *len = strlen(macro->name);
return macro->func(); return macro->func();
@ -187,7 +191,7 @@ static void Cmd_Wait_f (void)
if (cmd_blockwait) if (cmd_blockwait)
return; return;
#ifndef CLIENTONLY #ifdef HAVE_SERVER
if (cmd_didwait && sv.state) if (cmd_didwait && sv.state)
Con_DPrintf("waits without server frames\n"); Con_DPrintf("waits without server frames\n");
#endif #endif
@ -531,7 +535,7 @@ void Cbuf_Execute (void)
{ {
int level; int level;
#ifndef SERVERONLY #ifdef HAVE_CLIENT
if (cmd_text[RESTRICT_LOCAL].waitattime && cls.state == ca_active) if (cmd_text[RESTRICT_LOCAL].waitattime && cls.state == ca_active)
{ {
//keep binds blocked until after the next input frame was sent to the server (at which point it will be cleared //keep binds blocked until after the next input frame was sent to the server (at which point it will be cleared
@ -876,7 +880,7 @@ static void Cmd_Echo_f (void)
//echo text is often quoted, so expand the text again now that we're no longer in quotes. //echo text is often quoted, so expand the text again now that we're no longer in quotes.
t = Cmd_ExpandString(text, extext, sizeof(extext), &level, !Cmd_IsInsecure()?true:false, true); t = Cmd_ExpandString(text, extext, sizeof(extext), &level, !Cmd_IsInsecure()?true:false, true);
#ifdef SERVERONLY #ifndef HAVE_CLIENT
Con_Printf ("%s", t); Con_Printf ("%s", t);
#else #else
t = TP_ParseFunChars(t); t = TP_ParseFunChars(t);
@ -1163,7 +1167,7 @@ static void Cmd_Alias_f (void)
} }
} }
#ifndef SERVERONLY #ifdef HAVE_CLIENT
static void Cmd_AliasEdit_f (void) static void Cmd_AliasEdit_f (void)
{ {
char *alias = Cmd_AliasExist(Cmd_Argv(1), RESTRICT_LOCAL); char *alias = Cmd_AliasExist(Cmd_Argv(1), RESTRICT_LOCAL);
@ -2579,7 +2583,7 @@ static void Cmd_Apropos_f (void)
//FIXME: add aliases. //FIXME: add aliases.
} }
#ifndef SERVERONLY // FIXME #ifdef HAVE_CLIENT // FIXME
/* /*
=================== ===================
Cmd_ForwardToServer Cmd_ForwardToServer
@ -2731,29 +2735,29 @@ void Cmd_ExecuteString (const char *text, int level)
Con_TPrintf("cmd '%s' was restricted.\n", cmd_argv[0]); Con_TPrintf("cmd '%s' was restricted.\n", cmd_argv[0]);
else if (!cmd->function) else if (!cmd->function)
{ {
#ifdef VM_CG #if defined(VM_CG) && defined(HAVE_CLIENT)
if (CG_Command()) if (CG_Command())
return; return;
#endif #endif
#ifdef Q3SERVER #if defined(Q3SERVER) && defined(HAVE_SERVER)
if (SVQ3_Command()) if (SVQ3_Command())
return; return;
#endif #endif
#ifdef VM_UI #if defined(VM_UI) && defined(HAVE_CLIENT)
if (UI_Command()) if (UI_Command())
return; return;
#endif #endif
if (Cmd_AliasExist(cmd_argv[0], level)) if (Cmd_AliasExist(cmd_argv[0], level))
break; //server stuffed an alias for a command that it would already have received. use that instead. break; //server stuffed an alias for a command that it would already have received. use that instead.
#if defined(CSQC_DAT) && !defined(SERVERONLY) #if defined(CSQC_DAT) && defined(HAVE_CLIENT)
if (CSQC_ConsoleCommand(-1, text)) if (CSQC_ConsoleCommand(-1, text))
return; //let the csqc handle it if it wants. return; //let the csqc handle it if it wants.
#endif #endif
#if defined(MENU_DAT) && !defined(SERVERONLY) #if defined(MENU_DAT) && defined(HAVE_CLIENT)
if (MP_ConsoleCommand(text)) if (MP_ConsoleCommand(text))
return; //let the csqc handle it if it wants. return; //let the csqc handle it if it wants.
#endif #endif
#if defined(MENU_NATIVECODE) && !defined(SERVERONLY) #if defined(MENU_NATIVECODE) && defined(HAVE_CLIENT)
if (mn_entry && mn_entry->ConsoleCommand(text, cmd_argc, (char const*const*)cmd_argv)) if (mn_entry && mn_entry->ConsoleCommand(text, cmd_argc, (char const*const*)cmd_argv))
return; return;
#endif #endif
@ -2777,11 +2781,11 @@ void Cmd_ExecuteString (const char *text, int level)
{ {
int execlevel; int execlevel;
#ifndef SERVERONLY //an emergency escape mechansim, to avoid infinatly recursing aliases. #ifdef HAVE_CLIENT //an emergency escape mechansim, to avoid infinatly recursing aliases.
extern qboolean keydown[]; extern qboolean keydown[];
extern unsigned int con_splitmodifier; extern unsigned int con_splitmodifier;
if (keydown[K_SHIFT] && (keydown[K_LCTRL]||keydown[K_RCTRL]) && (keydown[K_LALT]||keydown[K_RALT])) if (keydown[K_SHIFT] && (keydown[K_LCTRL]||keydown[K_RCTRL]) && (keydown[K_LALT]||keydown[K_RALT]) && !isDedicated)
return; return;
#endif #endif
@ -2837,7 +2841,7 @@ void Cmd_ExecuteString (const char *text, int level)
Q_strncpyz(dest, a->value, sizeof(dest)); Q_strncpyz(dest, a->value, sizeof(dest));
Cbuf_InsertText (dest, execlevel, false); Cbuf_InsertText (dest, execlevel, false);
#ifndef SERVERONLY #ifdef HAVE_CLIENT
if (con_splitmodifier > 0) if (con_splitmodifier > 0)
{ //if the alias was execed via p1/p2 etc, make sure that propagates properly (at least for simple aliases like impulses) { //if the alias was execed via p1/p2 etc, make sure that propagates properly (at least for simple aliases like impulses)
//fixme: should probably prefix each line. that may have different issues however. //fixme: should probably prefix each line. that may have different issues however.
@ -2910,15 +2914,15 @@ void Cmd_ExecuteString (const char *text, int level)
return; return;
} }
#if defined(CSQC_DAT) && !defined(SERVERONLY) #if defined(CSQC_DAT) && defined(HAVE_CLIENT)
if (CSQC_ConsoleCommand(-1, text)) if (CSQC_ConsoleCommand(-1, text))
return; return;
#endif #endif
#if defined(MENU_DAT) && !defined(SERVERONLY) #if defined(MENU_DAT) && defined(HAVE_CLIENT)
if (MP_ConsoleCommand(text)) if (MP_ConsoleCommand(text))
return; //let the csqc handle it if it wants. return; //let the csqc handle it if it wants.
#endif #endif
#if defined(MENU_NATIVECODE) && !defined(SERVERONLY) #if defined(MENU_NATIVECODE) && defined(HAVE_CLIENT)
if (mn_entry && mn_entry->ConsoleCommand(text, cmd_argc, (char const*const*)cmd_argv)) if (mn_entry && mn_entry->ConsoleCommand(text, cmd_argc, (char const*const*)cmd_argv))
return; return;
#endif #endif
@ -2928,7 +2932,7 @@ void Cmd_ExecuteString (const char *text, int level)
return; return;
#endif #endif
#ifndef CLIENTONLY #ifdef HAVE_SERVER
if (sv.state) if (sv.state)
{ {
if (PR_ConsoleCmd(text)) if (PR_ConsoleCmd(text))
@ -2936,19 +2940,19 @@ void Cmd_ExecuteString (const char *text, int level)
} }
#endif #endif
#ifdef VM_CG #if defined(VM_CG) && defined(HAVE_CLIENT)
if (CG_Command()) if (CG_Command())
return; return;
#endif #endif
#ifdef Q3SERVER #if defined(Q3SERVER) && defined(HAVE_SERVER)
if (SVQ3_Command()) if (SVQ3_Command())
return; return;
#endif #endif
#ifdef VM_UI #if defined(VM_UI) && defined(HAVE_CLIENT)
if (UI_Command()) if (UI_Command())
return; return;
#endif #endif
#ifdef Q2CLIENT #if defined(Q2CLIENT) && defined(HAVE_CLIENT)
if (cls.protocol == CP_QUAKE2 || cls.protocol == CP_QUAKE3) if (cls.protocol == CP_QUAKE2 || cls.protocol == CP_QUAKE3)
{ //q2 servers convert unknown commands to text. { //q2 servers convert unknown commands to text.
Cmd_ForwardToServer(); Cmd_ForwardToServer();
@ -3192,7 +3196,7 @@ static const char *If_Token_Term(const char *func, const char **end)
else if (!strcmp(com_token, "vid")) //mostly for use with the menu system. else if (!strcmp(com_token, "vid")) //mostly for use with the menu system.
{ {
s = COM_ParseToken(s, IFPUNCT); s = COM_ParseToken(s, IFPUNCT);
#ifndef SERVERONLY #ifdef HAVE_CLIENT
if (qrenderer == QR_NONE) if (qrenderer == QR_NONE)
s2 = ""; s2 = "";
else if (!strcmp(com_token, "width")) else if (!strcmp(com_token, "width"))
@ -3978,7 +3982,9 @@ static void Cmd_WriteConfig_f(void)
snprintf(fname, sizeof(fname), "fte.cfg"); snprintf(fname, sizeof(fname), "fte.cfg");
#endif #endif
#if defined(CL_MASTER) && defined(HAVE_CLIENT)
MasterInfo_WriteServers(); MasterInfo_WriteServers();
#endif
f = FS_OpenWithFriends(fname, sysname, sizeof(sysname), 3, "quake.rc", "hexen.rc", "*.cfg", "configs/*.cfg"); f = FS_OpenWithFriends(fname, sysname, sizeof(sysname), 3, "quake.rc", "hexen.rc", "*.cfg", "configs/*.cfg");
@ -4007,7 +4013,7 @@ static void Cmd_WriteConfig_f(void)
} }
VFS_PRINTF(f, "// %s config file\n\n", *fs_gamename.string?fs_gamename.string:FULLENGINENAME); VFS_PRINTF(f, "// %s config file\n\n", *fs_gamename.string?fs_gamename.string:FULLENGINENAME);
#ifndef SERVERONLY #ifdef HAVE_CLIENT
if (cfg_save_binds.ival) if (cfg_save_binds.ival)
Key_WriteBindings (f); Key_WriteBindings (f);
if (cfg_save_buttons.ival) if (cfg_save_buttons.ival)
@ -4022,11 +4028,11 @@ static void Cmd_WriteConfig_f(void)
#else #else
VFS_WRITE(f, "// Dedicated Server config\n\n", 28); VFS_WRITE(f, "// Dedicated Server config\n\n", 28);
#endif #endif
#ifdef CLIENTONLY #ifdef HAVE_SERVER
VFS_WRITE(f, "// no local/server infos\n\n", 26);
#else
if (cfg_save_infos.ival) if (cfg_save_infos.ival)
SV_SaveInfos(f); SV_SaveInfos(f);
#else
VFS_WRITE(f, "// no local/server infos\n\n", 26);
#endif #endif
if (cfg_save_aliases.ival) if (cfg_save_aliases.ival)
Alias_WriteAliases (f); Alias_WriteAliases (f);
@ -4042,7 +4048,7 @@ static void Cmd_Reset_f(void)
{ {
} }
#ifndef SERVERONLY #ifdef HAVE_CLIENT
// dumps current console contents to a text file // dumps current console contents to a text file
static void Cmd_Condump_f(void) static void Cmd_Condump_f(void)
{ {
@ -4231,7 +4237,7 @@ void Cmd_Init (void)
Cmd_AddCommand ("alias",Cmd_Alias_f); Cmd_AddCommand ("alias",Cmd_Alias_f);
Cmd_AddCommand ("newalias",Cmd_Alias_f); Cmd_AddCommand ("newalias",Cmd_Alias_f);
Cmd_AddCommand ("wait", Cmd_Wait_f); Cmd_AddCommand ("wait", Cmd_Wait_f);
#ifndef SERVERONLY #ifdef HAVE_CLIENT
Cmd_AddCommand ("cmd", Cmd_ForwardToServer_f); Cmd_AddCommand ("cmd", Cmd_ForwardToServer_f);
Cmd_AddCommand ("condump", Cmd_Condump_f); Cmd_AddCommand ("condump", Cmd_Condump_f);
Cmd_AddCommandAD ("aliasedit", Cmd_AliasEdit_f, Key_Alias_c, NULL); Cmd_AddCommandAD ("aliasedit", Cmd_AliasEdit_f, Key_Alias_c, NULL);
@ -4279,7 +4285,9 @@ void Cmd_Init (void)
Cmd_AddMacro("qt", Macro_Quote, false); Cmd_AddMacro("qt", Macro_Quote, false);
Cmd_AddMacro("dedicated", Macro_Dedicated, false); Cmd_AddMacro("dedicated", Macro_Dedicated, false);
#ifdef HAVE_CLIENT
Cvar_Register(&tp_disputablemacros, "Teamplay"); Cvar_Register(&tp_disputablemacros, "Teamplay");
#endif
Cvar_Register(&ruleset_allow_in, "Console"); Cvar_Register(&ruleset_allow_in, "Console");
Cmd_AddCommandD ("in", Cmd_In_f, "Issues the given command after a time delay. Disabled if ruleset_allow_in is 0."); Cmd_AddCommandD ("in", Cmd_In_f, "Issues the given command after a time delay. Disabled if ruleset_allow_in is 0.");
@ -4296,7 +4304,7 @@ void Cmd_Init (void)
Cvar_Register (&cfg_save_binds, "client operation options"); Cvar_Register (&cfg_save_binds, "client operation options");
Cvar_Register (&cfg_save_buttons, "client operation options"); Cvar_Register (&cfg_save_buttons, "client operation options");
#ifndef SERVERONLY #ifdef HAVE_CLIENT
rcon_level.ival = atof(rcon_level.enginevalue); //client is restricted to not be allowed to change restrictions. rcon_level.ival = atof(rcon_level.enginevalue); //client is restricted to not be allowed to change restrictions.
#else #else
Cvar_Register(&rcon_level, "Access controls"); //server gains versatility. Cvar_Register(&rcon_level, "Access controls"); //server gains versatility.

View file

@ -25,6 +25,15 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include <ctype.h> #include <ctype.h>
#include <errno.h> #include <errno.h>
#ifndef HAVE_CLIENT
double host_frametime;
double realtime; // without any filtering or bounding
qboolean host_initialized; // true if into command execution (compatability)
quakeparms_t host_parms;
int host_hunklevel;
#endif
//by adding 'extern' to one definition of a function in a translation unit, then the definition in that TU is NOT considered an inline definition. meaning non-inlined references in other TUs can link to it instead of their own if needed. //by adding 'extern' to one definition of a function in a translation unit, then the definition in that TU is NOT considered an inline definition. meaning non-inlined references in other TUs can link to it instead of their own if needed.
fte_inlinebody conchar_t *Font_Decode(conchar_t *start, unsigned int *codeflags, unsigned int *codepoint); fte_inlinebody conchar_t *Font_Decode(conchar_t *start, unsigned int *codeflags, unsigned int *codepoint);
fte_inlinebody float M_SRGBToLinear(float x, float mag); fte_inlinebody float M_SRGBToLinear(float x, float mag);
@ -103,6 +112,12 @@ static char *safeargvs[] =
static const char *largv[MAX_NUM_ARGVS + countof(safeargvs) + 1]; static const char *largv[MAX_NUM_ARGVS + countof(safeargvs) + 1];
static char *argvdummy = " "; static char *argvdummy = " ";
#ifdef CRAZYDEBUGGING
cvar_t developer = CVAR("developer","1");
#else
cvar_t developer = CVARD("developer","0", "Enables the spewing of additional developer/debugging messages. 2 will give even more spam, much of it unwanted.");
#endif
cvar_t registered = CVARD("registered","0","Set if quake's pak1.pak is available"); cvar_t registered = CVARD("registered","0","Set if quake's pak1.pak is available");
cvar_t gameversion = CVARFD("gameversion","", CVAR_SERVERINFO, "gamecode version for server browsers"); cvar_t gameversion = CVARFD("gameversion","", CVAR_SERVERINFO, "gamecode version for server browsers");
cvar_t gameversion_min = CVARD("gameversion_min","", "gamecode version for server browsers"); cvar_t gameversion_min = CVARD("gameversion_min","", "gamecode version for server browsers");
@ -111,7 +126,7 @@ cvar_t fs_gamename = CVARAFD("com_fullgamename", NULL, "fs_gamename", CVAR_NOSET
cvar_t com_protocolname = CVARAD("com_protocolname", NULL, "com_gamename", "The protocol game name used for dpmaster queries. For compatibility with DP, you can set this to 'DarkPlaces-Quake' in order to be listed in DP's master server, and to list DP servers."); cvar_t com_protocolname = CVARAD("com_protocolname", NULL, "com_gamename", "The protocol game name used for dpmaster queries. For compatibility with DP, you can set this to 'DarkPlaces-Quake' in order to be listed in DP's master server, and to list DP servers.");
cvar_t com_protocolversion = CVARAD("com_protocolversion", "3", NULL, "The protocol version used for dpmaster queries."); //3 by default, for compat with DP/NQ, even if our QW protocol uses different versions entirely. really it only matters for master servers. cvar_t com_protocolversion = CVARAD("com_protocolversion", "3", NULL, "The protocol version used for dpmaster queries."); //3 by default, for compat with DP/NQ, even if our QW protocol uses different versions entirely. really it only matters for master servers.
cvar_t com_parseutf8 = CVARD("com_parseutf8", "1", "Interpret console messages/playernames/etc as UTF-8. Requires special fonts. -1=iso 8859-1. 0=quakeascii(chat uses high chars). 1=utf8, revert to ascii on decode errors. 2=utf8 ignoring errors"); //1 parse. 2 parse, but stop parsing that string if a char was malformed. cvar_t com_parseutf8 = CVARD("com_parseutf8", "1", "Interpret console messages/playernames/etc as UTF-8. Requires special fonts. -1=iso 8859-1. 0=quakeascii(chat uses high chars). 1=utf8, revert to ascii on decode errors. 2=utf8 ignoring errors"); //1 parse. 2 parse, but stop parsing that string if a char was malformed.
#ifndef NOLEGACY #if !defined(NOLEGACY) && defined(HAVE_CLIENT)
cvar_t com_parseezquake = CVARD("com_parseezquake", "0", "Treat chevron chars from configs as a per-character flag. You should use this only for compat with nquake's configs."); cvar_t com_parseezquake = CVARD("com_parseezquake", "0", "Treat chevron chars from configs as a per-character flag. You should use this only for compat with nquake's configs.");
#endif #endif
cvar_t com_highlightcolor = CVARD("com_highlightcolor", STRINGIFY(COLOR_RED), "ANSI colour to be used for highlighted text, used when com_parseutf8 is active."); cvar_t com_highlightcolor = CVARD("com_highlightcolor", STRINGIFY(COLOR_RED), "ANSI colour to be used for highlighted text, used when com_parseutf8 is active.");
@ -1131,7 +1146,7 @@ static unsigned int MSG_ReadEntity(void)
return num; return num;
} }
//we use the high bit of the entity number to state that this is a large entity. //we use the high bit of the entity number to state that this is a large entity.
#ifndef CLIENTONLY #ifdef HAVE_SERVER
unsigned int MSGSV_ReadEntity(client_t *fromclient) unsigned int MSGSV_ReadEntity(client_t *fromclient)
{ {
unsigned int num; unsigned int num;
@ -1148,7 +1163,7 @@ unsigned int MSGSV_ReadEntity(client_t *fromclient)
return num; return num;
} }
#endif #endif
#ifndef SERVERONLY #ifdef HAVE_CLIENT
unsigned int MSGCL_ReadEntity(void) unsigned int MSGCL_ReadEntity(void)
{ {
unsigned int num; unsigned int num;
@ -1159,6 +1174,7 @@ unsigned int MSGCL_ReadEntity(void)
return num; return num;
} }
#endif #endif
#if defined(HAVE_CLIENT) || defined(HAVE_SERVER)
void MSG_WriteEntity(sizebuf_t *sb, unsigned int entnum) void MSG_WriteEntity(sizebuf_t *sb, unsigned int entnum)
{ {
if (entnum > MAX_EDICTS) if (entnum > MAX_EDICTS)
@ -1172,6 +1188,7 @@ void MSG_WriteEntity(sizebuf_t *sb, unsigned int entnum)
else else
MSG_WriteShort(sb, entnum); MSG_WriteShort(sb, entnum);
} }
#endif
void MSG_WriteDeltaUsercmd (sizebuf_t *buf, usercmd_t *from, usercmd_t *cmd) void MSG_WriteDeltaUsercmd (sizebuf_t *buf, usercmd_t *from, usercmd_t *cmd)
{ {
@ -1181,8 +1198,8 @@ void MSG_WriteDeltaUsercmd (sizebuf_t *buf, usercmd_t *from, usercmd_t *cmd)
// send the movement message // send the movement message
// //
bits = 0; bits = 0;
#ifdef Q2CLIENT #if defined(Q2CLIENT) && defined(HAVE_CLIENT)
if (cls.protocol == CP_QUAKE2) if (cls_state && cls.protocol == CP_QUAKE2)
{ {
unsigned char buttons = 0; unsigned char buttons = 0;
if (cmd->angles[0] != from->angles[0]) if (cmd->angles[0] != from->angles[0])
@ -1715,7 +1732,7 @@ vec3_t bytedirs[Q2NUMVERTEXNORMALS] =
#include "../client/q2anorms.h" #include "../client/q2anorms.h"
}; };
#endif #endif
#ifndef SERVERONLY #ifdef HAVE_CLIENT
void MSG_ReadDir (vec3_t dir) void MSG_ReadDir (vec3_t dir)
{ {
int b; int b;
@ -1774,7 +1791,7 @@ float MSG_ReadAngle (void)
case 1: case 1:
return MSG_ReadChar() * (360.0/256); return MSG_ReadChar() * (360.0/256);
default: default:
Host_Error("Bad angle size\n"); Sys_Error("Bad angle size\n");
return 0; return 0;
} }
} }
@ -5720,7 +5737,9 @@ void COM_Init (void)
COM_InitWorkerThread(); COM_InitWorkerThread();
#endif #endif
#ifdef PACKAGEMANAGER
Cmd_AddCommandD("pkg", PM_Command_f, "Provides a way to install / list / disable / purge packages via the console."); Cmd_AddCommandD("pkg", PM_Command_f, "Provides a way to install / list / disable / purge packages via the console.");
#endif
Cmd_AddCommandD("version", COM_Version_f, "Reports engine revision and optional compile-time settings."); //prints the pak or whatever where this file can be found. Cmd_AddCommandD("version", COM_Version_f, "Reports engine revision and optional compile-time settings."); //prints the pak or whatever where this file can be found.
#ifdef _DEBUG #ifdef _DEBUG
@ -5730,6 +5749,7 @@ void COM_Init (void)
#endif #endif
COM_InitFilesystem (); COM_InitFilesystem ();
Cvar_Register (&developer, "Debugging");
Cvar_Register (&sys_platform, "Gamecode"); Cvar_Register (&sys_platform, "Gamecode");
Cvar_Register (&registered, "Copy protection"); Cvar_Register (&registered, "Copy protection");
Cvar_Register (&gameversion, "Gamecode"); Cvar_Register (&gameversion, "Gamecode");
@ -5737,14 +5757,12 @@ void COM_Init (void)
Cvar_Register (&gameversion_max, "Gamecode"); Cvar_Register (&gameversion_max, "Gamecode");
Cvar_Register (&com_nogamedirnativecode, "Gamecode"); Cvar_Register (&com_nogamedirnativecode, "Gamecode");
Cvar_Register (&com_parseutf8, "Internationalisation"); Cvar_Register (&com_parseutf8, "Internationalisation");
#ifndef NOLEGACY #if !defined(NOLEGACY) && defined(HAVE_CLIENT)
Cvar_Register (&com_parseezquake, NULL); Cvar_Register (&com_parseezquake, NULL);
#endif #endif
Cvar_Register (&com_highlightcolor, "Internationalisation"); Cvar_Register (&com_highlightcolor, "Internationalisation");
com_parseutf8.ival = 1; com_parseutf8.ival = 1;
Cvar_Register (&r_meshpitch, "Gamecode");
TranslateInit(); TranslateInit();
COM_BiDi_Setup(); COM_BiDi_Setup();
@ -7115,7 +7133,7 @@ void Info_Print (const char *s, const char *lineprefix)
} }
}*/ }*/
#if defined(HAVE_CLIENT) || defined(HAVE_SERVER)
static qbyte chktbl[1024 + 4] = { static qbyte chktbl[1024 + 4] = {
0x78,0xd2,0x94,0xe3,0x41,0xec,0xd6,0xd5,0xcb,0xfc,0xdb,0x8a,0x4b,0xcc,0x85,0x01, 0x78,0xd2,0x94,0xe3,0x41,0xec,0xd6,0xd5,0xcb,0xfc,0xdb,0x8a,0x4b,0xcc,0x85,0x01,
0x23,0xd2,0xe5,0xf2,0x29,0xa7,0x45,0x94,0x4a,0x62,0xe3,0xa5,0x6f,0x3f,0xe1,0x7a, 0x23,0xd2,0xe5,0xf2,0x29,0xa7,0x45,0x94,0x4a,0x62,0xe3,0xa5,0x6f,0x3f,0xe1,0x7a,
@ -7350,6 +7368,7 @@ qbyte Q2COM_BlockSequenceCRCByte (qbyte *base, int length, int sequence)
return crc; return crc;
} }
#endif
#endif #endif
#ifdef _WIN32 #ifdef _WIN32
@ -7465,3 +7484,220 @@ void COM_TimeOfDay(date_t *date)
strftime( date->str, 128, strftime( date->str, 128,
"%a %b %d, %H:%M:%S %Y", newtime); "%a %b %d, %H:%M:%S %Y", newtime);
} }
/*
================
Con_Printf
Handles cursor positioning, line wrapping, etc
================
*/
#define MAXPRINTMSG 4096
// FIXME: make a buffer size safe vsprintf?
void SV_FlushRedirect (void);
#ifndef HAVE_CLIENT
vfsfile_t *con_pipe;
#ifdef HAVE_SERVER
vfsfile_t *Con_POpen(char *conname)
{
if (!conname || !*conname)
{
if (con_pipe)
VFS_CLOSE(con_pipe);
con_pipe = VFSPIPE_Open(2, false);
return con_pipe;
}
return NULL;
}
#endif
static void Con_PrintFromThread (void *ctx, void *data, size_t a, size_t b)
{
Con_Printf("%s", (char*)data);
BZ_Free(data);
}
void VARGS Con_Printf (const char *fmt, ...)
{
va_list argptr;
char msg[MAXPRINTMSG];
va_start (argptr,fmt);
vsnprintf (msg,sizeof(msg)-1, fmt,argptr);
va_end (argptr);
if (!Sys_IsMainThread())
{
COM_AddWork(WG_MAIN, Con_PrintFromThread, NULL, Z_StrDup(msg), 0, 0);
return;
}
#ifdef HAVE_SERVER
// add to redirected message
if (sv_redirected)
{
if (strlen (msg) + strlen(sv_redirected_buf) > sizeof(sv_redirected_buf) - 1)
SV_FlushRedirect ();
strcat (sv_redirected_buf, msg);
if (sv_redirected != -1)
return;
}
#endif
Sys_Printf ("%s", msg); // also echo to debugging console
Con_Log(msg); // log to console
if (con_pipe)
VFS_PUTS(con_pipe, msg);
}
void Con_TPrintf (translation_t stringnum, ...)
{
va_list argptr;
char msg[MAXPRINTMSG];
const char *fmt;
if (!Sys_IsMainThread())
{ //shouldn't be redirected anyway...
fmt = langtext(stringnum,com_language);
va_start (argptr,stringnum);
vsnprintf (msg,sizeof(msg)-1, fmt,argptr);
va_end (argptr);
COM_AddWork(WG_MAIN, Con_PrintFromThread, NULL, Z_StrDup(msg), 0, 0);
return;
}
#ifdef HAVE_SERVER
// add to redirected message
if (sv_redirected)
{
fmt = langtext(stringnum,sv_redirectedlang);
va_start (argptr,stringnum);
vsnprintf (msg,sizeof(msg)-1, fmt,argptr);
va_end (argptr);
if (strlen (msg) + strlen(sv_redirected_buf) > sizeof(sv_redirected_buf) - 1)
SV_FlushRedirect ();
strcat (sv_redirected_buf, msg);
return;
}
#endif
fmt = langtext(stringnum,com_language);
va_start (argptr,stringnum);
vsnprintf (msg,sizeof(msg)-1, fmt,argptr);
va_end (argptr);
Sys_Printf ("%s", msg); // also echo to debugging console
Con_Log(msg); // log to console
if (con_pipe)
VFS_PUTS(con_pipe, msg);
}
/*
================
Con_DPrintf
A Con_Printf that only shows up if the "developer" cvar is set
================
*/
static void Con_DPrintFromThread (void *ctx, void *data, size_t a, size_t b)
{
Con_DLPrintf(a, "%s", (char*)data);
BZ_Free(data);
}
void Con_DPrintf (const char *fmt, ...)
{
va_list argptr;
char msg[MAXPRINTMSG];
extern cvar_t log_developer;
if (!developer.value && !log_developer.value)
return;
va_start (argptr,fmt);
vsnprintf (msg,sizeof(msg)-1, fmt,argptr);
va_end (argptr);
if (!Sys_IsMainThread())
{
COM_AddWork(WG_MAIN, Con_DPrintFromThread, NULL, Z_StrDup(msg), 0, 0);
return;
}
#ifdef HAVE_SERVER
// add to redirected message
if (sv_redirected)
{
if (strlen (msg) + strlen(sv_redirected_buf) > sizeof(sv_redirected_buf) - 1)
SV_FlushRedirect ();
strcat (sv_redirected_buf, msg);
if (sv_redirected != -1)
return;
}
#endif
if (developer.value)
Sys_Printf ("%s", msg); // also echo to debugging console
if (log_developer.value)
Con_Log(msg); // log to console
}
void Con_DLPrintf (int level, const char *fmt, ...)
{
va_list argptr;
char msg[MAXPRINTMSG];
extern cvar_t log_developer;
if (developer.ival < level && !log_developer.value)
return;
va_start (argptr,fmt);
vsnprintf (msg,sizeof(msg)-1, fmt,argptr);
va_end (argptr);
if (!Sys_IsMainThread())
{
COM_AddWork(WG_MAIN, Con_DPrintFromThread, NULL, Z_StrDup(msg), level, 0);
return;
}
#ifdef HAVE_SERVER
// add to redirected message
if (sv_redirected)
{
if (strlen (msg) + strlen(sv_redirected_buf) > sizeof(sv_redirected_buf) - 1)
SV_FlushRedirect ();
strcat (sv_redirected_buf, msg);
if (sv_redirected != -1)
return;
}
#endif
if (developer.ival >= level)
Sys_Printf ("%s", msg); // also echo to debugging console
if (log_developer.value)
Con_Log(msg); // log to console
}
//for spammed warnings, so they don't spam prints with every single frame/call. the timer arg should be a static local.
void VARGS Con_ThrottlePrintf (float *timer, int developerlevel, const char *fmt, ...)
{
va_list argptr;
char msg[MAXPRINTMSG];
va_start (argptr,fmt);
vsnprintf (msg,sizeof(msg)-1, fmt,argptr);
va_end (argptr);
if (developerlevel)
Con_DLPrintf (developerlevel, "%s", msg);
else
Con_Printf("%s", msg);
}
#endif

View file

@ -129,16 +129,16 @@ typedef enum {false, true} qboolean;
#define MAX_SERVERINFO_STRING 1024 //standard quake has 512 here. #define MAX_SERVERINFO_STRING 1024 //standard quake has 512 here.
#define MAX_LOCALINFO_STRING 32768 #define MAX_LOCALINFO_STRING 32768
#ifdef SERVERONLY #ifdef HAVE_CLIENT
#define cls_state 0
#else
#define cls_state cls.state #define cls_state cls.state
#else
#define cls_state 0
#endif #endif
#ifdef CLIENTONLY #ifdef HAVE_SERVER
#define sv_state 0
#else
#define sv_state sv.state #define sv_state sv.state
#else
#define sv_state 0
#endif #endif
struct netprim_s struct netprim_s

View file

@ -746,13 +746,15 @@ static cvar_t *Cvar_SetCore (cvar_t *var, const char *value, qboolean force)
latch = "variable %s is latched and will be applied for the start of the next map\n"; latch = "variable %s is latched and will be applied for the start of the next map\n";
// else if (var->flags & CVAR_LATCHFLUSH) // else if (var->flags & CVAR_LATCHFLUSH)
// latch = "variable %s is latched (type flush)\n"; // latch = "variable %s is latched (type flush)\n";
#ifdef HAVE_CLIENT
else if (var->flags & CVAR_VIDEOLATCH && qrenderer != QR_NONE) else if (var->flags & CVAR_VIDEOLATCH && qrenderer != QR_NONE)
latch = "variable %s will be changed after a vid_restart\n"; latch = "variable %s will be changed after a vid_restart\n";
else if (var->flags & CVAR_RENDERERLATCH && qrenderer != QR_NONE) else if (var->flags & CVAR_RENDERERLATCH && qrenderer != QR_NONE)
latch = "variable %s will be changed after a vid_reload\n"; latch = "variable %s will be changed after a vid_reload\n";
#endif
else if (var->flags & CVAR_RULESETLATCH) else if (var->flags & CVAR_RULESETLATCH)
latch = "variable %s is latched due to current ruleset\n"; latch = "variable %s is latched due to current ruleset\n";
#ifndef SERVERONLY #ifdef HAVE_CLIENT
else if (var->flags & CVAR_CHEAT && !cls.allow_cheats && cls.state) else if (var->flags & CVAR_CHEAT && !cls.allow_cheats && cls.state)
latch = "variable %s is a cheat variable - latched\n"; latch = "variable %s is a cheat variable - latched\n";
else if (var->flags & CVAR_SEMICHEAT && !cls.allow_semicheats && cls.state) else if (var->flags & CVAR_SEMICHEAT && !cls.allow_semicheats && cls.state)
@ -791,13 +793,13 @@ static cvar_t *Cvar_SetCore (cvar_t *var, const char *value, qboolean force)
return NULL; return NULL;
} }
#ifndef CLIENTONLY #ifdef HAVE_SERVER
if (var->flags & CVAR_SERVERINFO) if (var->flags & CVAR_SERVERINFO)
{ {
InfoBuf_SetKey (&svs.info, var->name, value); InfoBuf_SetKey (&svs.info, var->name, value);
} }
#endif #endif
#ifndef SERVERONLY #ifdef HAVE_CLIENT
if (var->flags & CVAR_SHADERSYSTEM) if (var->flags & CVAR_SHADERSYSTEM)
{ {
if (var->string && value) if (var->string && value)
@ -849,10 +851,10 @@ static cvar_t *Cvar_SetCore (cvar_t *var, const char *value, qboolean force)
if (var->flags & CVAR_TELLGAMECODE) if (var->flags & CVAR_TELLGAMECODE)
{ {
#ifndef CLIENTONLY #ifdef HAVE_SERVER
SVQ1_CvarChanged(var); SVQ1_CvarChanged(var);
#endif #endif
#ifndef SERVERONLY #ifdef HAVE_CLIENT
#ifdef MENU_DAT #ifdef MENU_DAT
MP_CvarChanged(var); MP_CvarChanged(var);
#endif #endif
@ -1338,7 +1340,7 @@ qboolean Cvar_Command (int level)
return true; return true;
} }
#ifndef SERVERONLY #ifdef HAVE_CLIENT
if (v->flags & CVAR_USERINFO) if (v->flags & CVAR_USERINFO)
{ {
int seat = CL_TargettedSplit(true); int seat = CL_TargettedSplit(true);

View file

@ -12,6 +12,10 @@
#include "winquake.h" #include "winquake.h"
#endif #endif
#if (defined(HAVE_CLIENT) || defined(HAVE_SERVER)) && defined(WEBCLIENT)
#define MANIFESTDOWNLOADS
#endif
void FS_BeginManifestUpdates(void); void FS_BeginManifestUpdates(void);
static void QDECL fs_game_callback(cvar_t *var, char *oldvalue); static void QDECL fs_game_callback(cvar_t *var, char *oldvalue);
static void COM_InitHomedir(ftemanifest_t *man); static void COM_InitHomedir(ftemanifest_t *man);
@ -2614,7 +2618,9 @@ static void FS_AddDataFiles(searchpath_t **oldpaths, const char *purepath, const
BZ_Free(buffer); BZ_Free(buffer);
} }
#ifdef PACKAGEMANAGER
PM_LoadPackages(oldpaths, purepath, logicalpaths, search, loadstuff, 0x80000000, -1); PM_LoadPackages(oldpaths, purepath, logicalpaths, search, loadstuff, 0x80000000, -1);
#endif
for (j = 0; j < sizeof(searchpathformats)/sizeof(searchpathformats[0]); j++) for (j = 0; j < sizeof(searchpathformats)/sizeof(searchpathformats[0]); j++)
{ {
@ -2661,7 +2667,9 @@ static void FS_AddDataFiles(searchpath_t **oldpaths, const char *purepath, const
//now load ones from the manifest //now load ones from the manifest
FS_AddManifestPackages(oldpaths, purepath, logicalpaths, search, loadstuff); FS_AddManifestPackages(oldpaths, purepath, logicalpaths, search, loadstuff);
#ifdef PACKAGEMANAGER
PM_LoadPackages(oldpaths, purepath, logicalpaths, search, loadstuff, 0x0, 1000-1); PM_LoadPackages(oldpaths, purepath, logicalpaths, search, loadstuff, 0x0, 1000-1);
#endif
//now load the random ones //now load the random ones
for (j = 0; j < sizeof(searchpathformats)/sizeof(searchpathformats[0]); j++) for (j = 0; j < sizeof(searchpathformats)/sizeof(searchpathformats[0]); j++)
@ -2678,7 +2686,9 @@ static void FS_AddDataFiles(searchpath_t **oldpaths, const char *purepath, const
} }
} }
#ifdef PACKAGEMANAGER
PM_LoadPackages(oldpaths, purepath, logicalpaths, search, loadstuff, 1000, 0x7ffffffe); PM_LoadPackages(oldpaths, purepath, logicalpaths, search, loadstuff, 1000, 0x7ffffffe);
#endif
} }
static searchpath_t *FS_AddPathHandle(searchpath_t **oldpaths, const char *purepath, const char *logicalpath, searchpathfuncs_t *handle, const char *prefix, unsigned int flags, unsigned int loadstuff) static searchpath_t *FS_AddPathHandle(searchpath_t **oldpaths, const char *purepath, const char *logicalpath, searchpathfuncs_t *handle, const char *prefix, unsigned int flags, unsigned int loadstuff)
@ -3057,7 +3067,7 @@ void COM_Gamedir (const char *dir, const struct gamepacks *packagespaths)
FS_ChangeGame(man, cfg_reload_on_gamedir.ival, false); FS_ChangeGame(man, cfg_reload_on_gamedir.ival, false);
} }
#if defined(NOLEGACY) || defined(SERVERONLY) #if defined(NOLEGACY) || !defined(HAVE_CLIENT)
#define ZFIXHACK #define ZFIXHACK
#elif defined(ANDROID) //on android, these numbers seem to be generating major weirdness, so disable these. #elif defined(ANDROID) //on android, these numbers seem to be generating major weirdness, so disable these.
#define ZFIXHACK #define ZFIXHACK
@ -3267,6 +3277,7 @@ qboolean FS_GenCachedPakName(const char *pname, const char *crc, char *local, in
return true; return true;
} }
#ifdef HAVE_CLIENT
#if 0 #if 0
qboolean FS_LoadPackageFromFile(vfsfile_t *vfs, char *pname, char *localname, int *crc, unsigned int flags) qboolean FS_LoadPackageFromFile(vfsfile_t *vfs, char *pname, char *localname, int *crc, unsigned int flags)
{ {
@ -3511,7 +3522,7 @@ void FS_PureMode(int puremode, char *purenamelist, char *purecrclist, char *refn
{ {
qboolean pureflush; qboolean pureflush;
#ifndef CLIENTONLY #ifdef HAVE_SERVER
//if we're the server, we can't be impure. //if we're the server, we can't be impure.
if (sv.state) if (sv.state)
return; return;
@ -3543,7 +3554,7 @@ void FS_PureMode(int puremode, char *purenamelist, char *purecrclist, char *refn
if (pureflush) if (pureflush)
{ {
#ifndef SERVERONLY #ifdef HAVE_CLIENT
Shader_NeedReload(true); Shader_NeedReload(true);
#endif #endif
Mod_ClearAll(); Mod_ClearAll();
@ -3551,7 +3562,6 @@ void FS_PureMode(int puremode, char *purenamelist, char *purecrclist, char *refn
} }
} }
#ifndef SERVERONLY
int FS_PureOkay(void) int FS_PureOkay(void)
{ {
qboolean ret = true; qboolean ret = true;
@ -3629,6 +3639,7 @@ int FS_PureOkay(void)
} }
#endif #endif
#ifdef Q3CLIENT
char *FSQ3_GenerateClientPacksList(char *buffer, int maxlen, int basechecksum) char *FSQ3_GenerateClientPacksList(char *buffer, int maxlen, int basechecksum)
{ //this is for q3 compatibility. { //this is for q3 compatibility.
@ -3667,6 +3678,7 @@ char *FSQ3_GenerateClientPacksList(char *buffer, int maxlen, int basechecksum)
return buffer; return buffer;
} }
#endif
/* /*
================ ================
@ -4014,7 +4026,7 @@ static void FS_ReloadPackFilesFlags(unsigned int reloadflags)
if (next || i != orderkey)//some path changed. make sure the fs cache is flushed. if (next || i != orderkey)//some path changed. make sure the fs cache is flushed.
FS_FlushFSHashReally(false); FS_FlushFSHashReally(false);
#ifndef SERVERONLY #ifdef HAVE_CLIENT
Shader_NeedReload(true); Shader_NeedReload(true);
#endif #endif
// Mod_ClearAll(); // Mod_ClearAll();
@ -4095,7 +4107,7 @@ static qboolean Sys_SteamHasFile(char *basepath, int basepathlen, char *steamdir
return false; return false;
} }
#ifndef SERVERONLY #ifdef HAVE_CLIENT
static INT CALLBACK StupidBrowseCallbackProc(HWND hwnd, UINT uMsg, LPARAM lp, LPARAM pData) static INT CALLBACK StupidBrowseCallbackProc(HWND hwnd, UINT uMsg, LPARAM lp, LPARAM pData)
{ //'stolen' from microsoft's knowledge base. { //'stolen' from microsoft's knowledge base.
//required to work around microsoft being annoying. //required to work around microsoft being annoying.
@ -4139,7 +4151,7 @@ int MessageBoxU(HWND hWnd, char *lpText, char *lpCaption, UINT uType);
qboolean Sys_DoDirectoryPrompt(char *basepath, size_t basepathsize, const char *poshname, const char *savedname) qboolean Sys_DoDirectoryPrompt(char *basepath, size_t basepathsize, const char *poshname, const char *savedname)
{ {
#ifndef SERVERONLY #ifdef HAVE_CLIENT
wchar_t resultpath[MAX_OSPATH]; wchar_t resultpath[MAX_OSPATH];
wchar_t title[MAX_OSPATH]; wchar_t title[MAX_OSPATH];
BROWSEINFOW bi; BROWSEINFOW bi;
@ -4305,7 +4317,7 @@ qboolean Sys_FindGameData(const char *poshname, const char *gamename, char *base
return true; return true;
} }
#if !defined(NPFTE) && !defined(SERVERONLY) //this is *really* unfortunate, but doing this crashes the browser #if !defined(NPFTE) && defined(HAVE_CLIENT) //this is *really* unfortunate, but doing this crashes the browser
if (allowprompts && poshname && *gamename && !COM_CheckParm("-manifest")) if (allowprompts && poshname && *gamename && !COM_CheckParm("-manifest"))
{ {
if (Sys_DoDirectoryPrompt(basepath, basepathlen, poshname, gamename)) if (Sys_DoDirectoryPrompt(basepath, basepathlen, poshname, gamename))
@ -4411,7 +4423,7 @@ qboolean Sys_FindGameData(const char *poshname, const char *gamename, char *base
} }
} }
#if !defined(NPFTE) && !defined(SERVERONLY) //this is *really* unfortunate, but doing this crashes the browser #if !defined(NPFTE) && defined(HAVE_CLIENT) //this is *really* unfortunate, but doing this crashes the browser
if (allowprompts && poshname && *gamename && !COM_CheckParm("-manifest")) if (allowprompts && poshname && *gamename && !COM_CheckParm("-manifest"))
{ {
if (Sys_DoDirectoryPrompt(basepath, basepathlen, poshname, gamename)) if (Sys_DoDirectoryPrompt(basepath, basepathlen, poshname, gamename))
@ -4458,7 +4470,9 @@ void FS_Shutdown(void)
if (!fs_thread_mutex) if (!fs_thread_mutex)
return; return;
#ifdef PACKAGEMANAGER
PM_ManifestPackage(NULL, false); PM_ManifestPackage(NULL, false);
#endif
FS_FreePaths(); FS_FreePaths();
Sys_DestroyMutex(fs_thread_mutex); Sys_DestroyMutex(fs_thread_mutex);
fs_thread_mutex = NULL; fs_thread_mutex = NULL;
@ -4659,7 +4673,7 @@ static void FS_AppendManifestGameArguments(ftemanifest_t *man)
} }
} }
#ifdef WEBCLIENT #ifdef MANIFESTDOWNLOADS
static char *FS_RelativeURL(char *base, char *file, char *buffer, int bufferlen) static char *FS_RelativeURL(char *base, char *file, char *buffer, int bufferlen)
{ {
//fixme: cope with windows paths //fixme: cope with windows paths
@ -4841,7 +4855,11 @@ static void FS_PackageDownloaded(struct dl_download *dl)
if (fspdl_extracttype == X_UNZIP || fspdl_extracttype == X_MULTIUNZIP) //if zip... if (fspdl_extracttype == X_UNZIP || fspdl_extracttype == X_MULTIUNZIP) //if zip...
{ //archive { //archive
#ifdef PACKAGE_PK3
searchpathfuncs_t *archive = FSZIP_LoadArchive(VFSOS_Open(fspdl_temppath, "rb"), NULL, dl->url, dl->url, ""); searchpathfuncs_t *archive = FSZIP_LoadArchive(VFSOS_Open(fspdl_temppath, "rb"), NULL, dl->url, dl->url, "");
#else
searchpathfuncs_t *archive = NULL;
#endif
if (archive) if (archive)
{ {
flocation_t loc; flocation_t loc;
@ -5416,17 +5434,20 @@ qboolean FS_ChangeGame(ftemanifest_t *man, qboolean allowreloadconfigs, qboolean
qboolean reloadconfigs = false; qboolean reloadconfigs = false;
qboolean builtingame = false; qboolean builtingame = false;
flocation_t loc; flocation_t loc;
qboolean allowvidrestart = true;
#ifdef HAVE_CLIENT
qboolean allowvidrestart = true;
char *vidfile[] = {"gfx.wad", "gfx/conback.lmp", //misc stuff char *vidfile[] = {"gfx.wad", "gfx/conback.lmp", //misc stuff
"gfx/palette.lmp", "pics/colormap.pcx"}; //palettes "gfx/palette.lmp", "pics/colormap.pcx"}; //palettes
searchpathfuncs_t *vidpath[countof(vidfile)]; searchpathfuncs_t *vidpath[countof(vidfile)];
#endif
//if any of these files change location, the configs will be re-execed. //if any of these files change location, the configs will be re-execed.
//note that we reuse path handles if they're still valid, so we can just check the pointer to see if it got unloaded/replaced. //note that we reuse path handles if they're still valid, so we can just check the pointer to see if it got unloaded/replaced.
char *conffile[] = {"quake.rc", "hexen.rc", "default.cfg", "server.cfg"}; char *conffile[] = {"quake.rc", "hexen.rc", "default.cfg", "server.cfg"};
searchpathfuncs_t *confpath[countof(conffile)]; searchpathfuncs_t *confpath[countof(conffile)];
#ifdef HAVE_CLIENT
for (i = 0; i < countof(vidfile); i++) for (i = 0; i < countof(vidfile); i++)
{ {
if (allowvidrestart) if (allowvidrestart)
@ -5437,6 +5458,7 @@ qboolean FS_ChangeGame(ftemanifest_t *man, qboolean allowreloadconfigs, qboolean
else else
vidpath[i] = NULL; vidpath[i] = NULL;
} }
#endif
if (allowreloadconfigs && fs_noreexec.ival) if (allowreloadconfigs && fs_noreexec.ival)
allowreloadconfigs = false; allowreloadconfigs = false;
@ -5600,7 +5622,7 @@ qboolean FS_ChangeGame(ftemanifest_t *man, qboolean allowreloadconfigs, qboolean
{ {
if (Sys_FindGameData(man->formalname, man->installation, realpath, sizeof(realpath), man->security != MANIFEST_SECURITY_INSTALLER) && FS_FixPath(realpath, sizeof(realpath)) && FS_DirHasAPackage(realpath, man)) if (Sys_FindGameData(man->formalname, man->installation, realpath, sizeof(realpath), man->security != MANIFEST_SECURITY_INSTALLER) && FS_FixPath(realpath, sizeof(realpath)) && FS_DirHasAPackage(realpath, man))
Q_strncpyz (newbasedir, realpath, sizeof(newbasedir)); Q_strncpyz (newbasedir, realpath, sizeof(newbasedir));
#ifndef SERVERONLY #ifdef HAVE_CLIENT
else else
{ {
Z_Free(man->updatefile); Z_Free(man->updatefile);
@ -5614,7 +5636,9 @@ qboolean FS_ChangeGame(ftemanifest_t *man, qboolean allowreloadconfigs, qboolean
{ {
if (strcmp(com_gamepath, newbasedir)) if (strcmp(com_gamepath, newbasedir))
{ {
#ifdef PACKAGEMANAGER
PM_Shutdown(); PM_Shutdown();
#endif
Q_strncpyz (com_gamepath, newbasedir, sizeof(com_gamepath)); Q_strncpyz (com_gamepath, newbasedir, sizeof(com_gamepath));
} }
} }
@ -5664,7 +5688,9 @@ qboolean FS_ChangeGame(ftemanifest_t *man, qboolean allowreloadconfigs, qboolean
if (Sys_LockMutex(fs_thread_mutex)) if (Sys_LockMutex(fs_thread_mutex))
{ {
#ifdef HAVE_CLIENT
qboolean vidrestart = false; qboolean vidrestart = false;
#endif
FS_ReloadPackFilesFlags(~0); FS_ReloadPackFilesFlags(~0);
@ -5672,14 +5698,14 @@ qboolean FS_ChangeGame(ftemanifest_t *man, qboolean allowreloadconfigs, qboolean
FS_BeginManifestUpdates(); FS_BeginManifestUpdates();
#ifdef WEBCLIENT #ifdef MANIFESTDOWNLOADS
if (curpackagedownload && fs_loadedcommand) if (curpackagedownload && fs_loadedcommand)
allowreloadconfigs = false; allowreloadconfigs = false;
#endif #endif
COM_CheckRegistered(); COM_CheckRegistered();
#ifdef HAVE_CLIENT
if (qrenderer != QR_NONE && allowvidrestart) if (qrenderer != QR_NONE && allowvidrestart)
{ {
for (i = 0; i < countof(vidfile); i++) for (i = 0; i < countof(vidfile); i++)
@ -5692,6 +5718,7 @@ qboolean FS_ChangeGame(ftemanifest_t *man, qboolean allowreloadconfigs, qboolean
} }
} }
} }
#endif
if (allowreloadconfigs) if (allowreloadconfigs)
{ {
@ -5714,28 +5741,30 @@ qboolean FS_ChangeGame(ftemanifest_t *man, qboolean allowreloadconfigs, qboolean
Cvar_ForceSet(&fs_gamename, fs_gamename.enginevalue); Cvar_ForceSet(&fs_gamename, fs_gamename.enginevalue);
Cvar_ForceSet(&pm_downloads_url, pm_downloads_url.enginevalue); Cvar_ForceSet(&pm_downloads_url, pm_downloads_url.enginevalue);
Cvar_ForceSet(&com_protocolname, com_protocolname.enginevalue); Cvar_ForceSet(&com_protocolname, com_protocolname.enginevalue);
#ifdef HAVE_CLIENT
vidrestart = false; vidrestart = false;
#endif
if (isDedicated) if (isDedicated)
{ {
#ifndef CLIENTONLY #ifdef HAVE_SERVER
SV_ExecInitialConfigs(man->defaultexec?man->defaultexec:""); SV_ExecInitialConfigs(man->defaultexec?man->defaultexec:"");
#endif #endif
} }
else else
{ {
#ifndef SERVERONLY #ifdef HAVE_CLIENT
CL_ExecInitialConfigs(man->defaultexec?man->defaultexec:""); CL_ExecInitialConfigs(man->defaultexec?man->defaultexec:"");
#endif #endif
} }
} }
#ifdef HAVE_CLIENT
else if (vidrestart) else if (vidrestart)
{ {
#ifndef SERVERONLY
Cbuf_AddText ("vid_reload\n", RESTRICT_LOCAL); Cbuf_AddText ("vid_reload\n", RESTRICT_LOCAL);
#endif
vidrestart = false; vidrestart = false;
} }
#endif
if (fs_loadedcommand) if (fs_loadedcommand)
{ {
Cbuf_AddText(fs_loadedcommand, RESTRICT_INSECURE); Cbuf_AddText(fs_loadedcommand, RESTRICT_INSECURE);
@ -5743,19 +5772,19 @@ qboolean FS_ChangeGame(ftemanifest_t *man, qboolean allowreloadconfigs, qboolean
fs_loadedcommand = NULL; fs_loadedcommand = NULL;
} }
} }
#ifdef HAVE_CLIENT
if (vidrestart) if (vidrestart)
{ {
#ifndef SERVERONLY
Cbuf_AddText ("vid_reload\n", RESTRICT_LOCAL); Cbuf_AddText ("vid_reload\n", RESTRICT_LOCAL);
#endif
vidrestart = false; vidrestart = false;
} }
#endif
//rebuild the cache now, should be safe to waste some cycles on it //rebuild the cache now, should be safe to waste some cycles on it
COM_FlushFSCache(false, true); COM_FlushFSCache(false, true);
} }
#ifndef SERVERONLY #ifdef HAVE_CLIENT
Validation_FlushFileList(); //prevent previous hacks from making a difference. Validation_FlushFileList(); //prevent previous hacks from making a difference.
#endif #endif
@ -6051,13 +6080,15 @@ static void FS_ChangeGame_f(void)
if (!Q_strcasecmp(gamemode_info[i].argname+1, arg)) if (!Q_strcasecmp(gamemode_info[i].argname+1, arg))
{ {
Con_Printf("Switching to %s\n", gamemode_info[i].argname+1); Con_Printf("Switching to %s\n", gamemode_info[i].argname+1);
#ifdef PACKAGEMANAGER
PM_Shutdown(); PM_Shutdown();
#endif
FS_ChangeGame(FS_GenerateLegacyManifest(NULL, 0, true, i), true, true); FS_ChangeGame(FS_GenerateLegacyManifest(NULL, 0, true, i), true, true);
return; return;
} }
} }
#ifndef SERVERONLY #ifdef HAVE_CLIENT
if (!Host_RunFile(arg, strlen(arg), NULL)) if (!Host_RunFile(arg, strlen(arg), NULL))
Con_Printf("Game unknown\n"); Con_Printf("Game unknown\n");
#endif #endif

View file

@ -520,7 +520,7 @@ static void IPLog_Identify_f(void)
//treading carefully here, to avoid dns name lookups weirding everything out. //treading carefully here, to avoid dns name lookups weirding everything out.
IPLog_Identify(&adr, &mask, "Identity of %s", NET_AdrToStringMasked(clean, sizeof(clean), &adr, &mask)); IPLog_Identify(&adr, &mask, "Identity of %s", NET_AdrToStringMasked(clean, sizeof(clean), &adr, &mask));
} }
#ifndef CLIENTONLY #ifdef HAVE_SERVER
else if (sv.active) else if (sv.active)
{ //if server is active, walk players to see if there's a name match to get their address and guess an address mask { //if server is active, walk players to see if there's a name match to get their address and guess an address mask
client_t *cl; client_t *cl;
@ -537,7 +537,7 @@ static void IPLog_Identify_f(void)
} }
} }
#endif #endif
#ifndef SERVERONLY #ifdef HAVE_CLIENT
else if (cls.state >= ca_connected) else if (cls.state >= ca_connected)
{ //else if client is active, walk players to see if there's a name match, to get their address+mask if known via nq hacks { //else if client is active, walk players to see if there's a name match, to get their address+mask if known via nq hacks
int slot; int slot;
@ -630,7 +630,7 @@ static void IPLog_Merge_f(void)
} }
#endif #endif
#ifndef SERVERONLY #ifdef HAVE_CLIENT //requires UI prompts
struct certlog_s struct certlog_s
{ {
link_t l; link_t l;
@ -849,7 +849,7 @@ void Log_Init(void)
if (COM_CheckParm("-condebug")) if (COM_CheckParm("-condebug"))
Cvar_ForceSet(&log_enable[LOG_CONSOLE], "1"); Cvar_ForceSet(&log_enable[LOG_CONSOLE], "1");
#ifndef SERVERONLY #ifdef HAVE_CLIENT
ClearLink(&certlog); ClearLink(&certlog);
Cmd_AddCommand("dtls_untrustall", CertLog_UntrustAll_f); Cmd_AddCommand("dtls_untrustall", CertLog_UntrustAll_f);
Cmd_AddCommand("dtls_importtrust", CertLog_Import_f); Cmd_AddCommand("dtls_importtrust", CertLog_Import_f);

View file

@ -131,14 +131,14 @@ void SVNET_RegisterCvars(void);
void NET_InitClient (qboolean loopbackonly); void NET_InitClient (qboolean loopbackonly);
void NET_CloseClient(void); void NET_CloseClient(void);
void NET_InitServer (void); void NET_InitServer (void);
qboolean NET_WasSpecialPacket(netsrc_t netsrc); qboolean NET_WasSpecialPacket(struct ftenet_connections_s *col);
void NET_CloseServer (void); void NET_CloseServer (void);
void UDP_CloseSocket (int socket); void UDP_CloseSocket (int socket);
void NET_Shutdown (void); void NET_Shutdown (void);
qboolean NET_GetRates(struct ftenet_connections_s *collection, float *pi, float *po, float *bi, float *bo); qboolean NET_GetRates(struct ftenet_connections_s *collection, float *pi, float *po, float *bi, float *bo);
qboolean NET_UpdateRates(struct ftenet_connections_s *collection, qboolean inbound, size_t size); //for demos to not be weird qboolean NET_UpdateRates(struct ftenet_connections_s *collection, qboolean inbound, size_t size); //for demos to not be weird
int NET_GetPacket (netsrc_t netsrc, int firstsock); int NET_GetPacket (struct ftenet_connections_s *col, int firstsock);
neterr_t NET_SendPacket (netsrc_t socket, int length, const void *data, netadr_t *to); neterr_t NET_SendPacket (struct ftenet_connections_s *col, int length, const void *data, netadr_t *to);
int NET_LocalAddressForRemote(struct ftenet_connections_s *collection, netadr_t *remote, netadr_t *local, int idx); int NET_LocalAddressForRemote(struct ftenet_connections_s *collection, netadr_t *remote, netadr_t *local, int idx);
void NET_PrintAddresses(struct ftenet_connections_s *collection); void NET_PrintAddresses(struct ftenet_connections_s *collection);
qboolean NET_AddressSmellsFunny(netadr_t *a); qboolean NET_AddressSmellsFunny(netadr_t *a);

View file

@ -91,6 +91,14 @@ cvar_t pext_infoblobs = CVARD("_pext_infoblobs", "0", "RENAME ME WHEN STABLE. En
cvar_t pext_replacementdeltas = CVARD("pext_replacementdeltas", "1", "Enables the use of alternative nack-based entity deltas"); cvar_t pext_replacementdeltas = CVARD("pext_replacementdeltas", "1", "Enables the use of alternative nack-based entity deltas");
cvar_t pext_predinfo = CVARD("pext_predinfo", "1", "Enables some extra things to support prediction over NQ protocols."); cvar_t pext_predinfo = CVARD("pext_predinfo", "1", "Enables some extra things to support prediction over NQ protocols.");
#if defined(HAVE_CLIENT) && defined(HAVE_SERVER)
#define NET_SendPacket(c,s,d,t) NET_SendPacket(((c)!=NS_CLIENT)?svs.sockets:cls.sockets,s,d,t)
#elif defined(HAVE_SERVER)
#define NET_SendPacket(c,s,d,t) NET_SendPacket(svs.sockets,s,d,t)
#else
#define NET_SendPacket(c,s,d,t) NET_SendPacket(cls.sockets,s,d,t)
#endif
/*returns the entire bitmask of supported+enabled extensions*/ /*returns the entire bitmask of supported+enabled extensions*/
unsigned int Net_PextMask(int maskset, qboolean fornq) unsigned int Net_PextMask(int maskset, qboolean fornq)
{ {

View file

@ -209,7 +209,7 @@ qboolean NET_RTP_Transmit(unsigned int sequence, unsigned int timestamp, const c
if (buf.overflowed) if (buf.overflowed)
return built; return built;
} }
NET_SendPacket(NS_CLIENT, buf.cursize, buf.data, &con->chosenpeer); NET_SendPacket(cls.sockets, buf.cursize, buf.data, &con->chosenpeer);
break; break;
} }
} }
@ -525,7 +525,7 @@ void ICE_ToStunServer(struct icestate_s *con)
data[2] = ((buf.cursize-20)>>8)&0xff; data[2] = ((buf.cursize-20)>>8)&0xff;
data[3] = ((buf.cursize-20)>>0)&0xff; data[3] = ((buf.cursize-20)>>0)&0xff;
NET_SendPacket((con->proto==ICEP_QWSERVER)?NS_SERVER:NS_CLIENT, buf.cursize, data, &con->pubstunserver); NET_SendPacket(collection, buf.cursize, data, &con->pubstunserver);
} }
void QDECL ICE_AddRCandidateInfo(struct icestate_s *con, struct icecandinfo_s *n) void QDECL ICE_AddRCandidateInfo(struct icestate_s *con, struct icecandinfo_s *n)
@ -1129,10 +1129,10 @@ icefuncs_t iceapi =
ICE_GetLCandidateSDP ICE_GetLCandidateSDP
}; };
qboolean ICE_WasStun(netsrc_t netsrc) qboolean ICE_WasStun(ftenet_connections_t *col)
{ {
#if !defined(SERVERONLY) && defined(VOICECHAT) #if defined(HAVE_CLIENT) && defined(VOICECHAT)
if (netsrc == NS_CLIENT) if (col == cls.sockets)
{ {
if (NET_RTP_Parse()) if (NET_RTP_Parse())
return true; return true;
@ -1528,7 +1528,7 @@ qboolean ICE_WasStun(netsrc_t netsrc)
data[2] = ((buf.cursize-20)>>8)&0xff; data[2] = ((buf.cursize-20)>>8)&0xff;
data[3] = ((buf.cursize-20)>>0)&0xff; data[3] = ((buf.cursize-20)>>0)&0xff;
NET_SendPacket(netsrc, buf.cursize, data, &net_from); NET_SendPacket(col, buf.cursize, data, &net_from);
} }
} }

View file

@ -463,7 +463,7 @@ static struct
static int SSL_CheckUserTrust(gnutls_session_t session, gnutlsfile_t *file, int ret) static int SSL_CheckUserTrust(gnutls_session_t session, gnutlsfile_t *file, int ret)
{ {
#ifndef SERVERONLY #ifdef HAVE_CLIENT
//when using dtls, we expect self-signed certs and persistent trust. //when using dtls, we expect self-signed certs and persistent trust.
if (file->datagram) if (file->datagram)
{ {

View file

@ -108,10 +108,14 @@ void (*pfreeaddrinfo) (struct addrinfo*);
#endif #endif
#endif #endif
#if defined(HAVE_IPV4) && !defined(CLIENTONLY) #if defined(HAVE_IPV4) && defined(HAVE_SERVER)
#define HAVE_NATPMP #define HAVE_NATPMP
#endif #endif
#if defined(HAVE_SERVER) || defined(MASTERONLY)
#define HAVE_HTTPSV
#endif
void NET_GetLocalAddress (int socket, netadr_t *out); void NET_GetLocalAddress (int socket, netadr_t *out);
//int TCP_OpenListenSocket (const char *localip, int port); //int TCP_OpenListenSocket (const char *localip, int port);
#ifdef HAVE_IPV6 #ifdef HAVE_IPV6
@ -124,17 +128,23 @@ cvar_t timeout = CVARD("timeout","65", "Connections will time out if no pack
cvar_t net_hybriddualstack = CVARD("net_hybriddualstack", "1", "Uses hybrid ipv4+ipv6 sockets where possible. Not supported on xp or below."); cvar_t net_hybriddualstack = CVARD("net_hybriddualstack", "1", "Uses hybrid ipv4+ipv6 sockets where possible. Not supported on xp or below.");
cvar_t net_fakeloss = CVARFD("net_fakeloss", "0", CVAR_CHEAT, "Simulates packetloss in both receiving and sending, on a scale from 0 to 1."); cvar_t net_fakeloss = CVARFD("net_fakeloss", "0", CVAR_CHEAT, "Simulates packetloss in both receiving and sending, on a scale from 0 to 1.");
cvar_t net_enabled = CVARD("net_enabled", "1", "If 0, disables all network access, including name resolution and socket creation. Does not affect loopback/internal connections."); cvar_t net_enabled = CVARD("net_enabled", "1", "If 0, disables all network access, including name resolution and socket creation. Does not affect loopback/internal connections.");
#if defined(TCPCONNECT) && !defined(CLIENTONLY) #if defined(TCPCONNECT) && (defined(HAVE_SERVER) || defined(HAVE_HTTPSV))
#ifdef HAVE_SERVER
cvar_t net_enable_qizmo = CVARD("net_enable_qizmo", "1", "Enables compatibility with qizmo's tcp connections serverside. Frankly, using sv_port_tcp without this is a bit pointless."); cvar_t net_enable_qizmo = CVARD("net_enable_qizmo", "1", "Enables compatibility with qizmo's tcp connections serverside. Frankly, using sv_port_tcp without this is a bit pointless.");
cvar_t net_enable_qtv = CVARD("net_enable_qtv", "1", "Listens for qtv proxies, or clients using the qtvplay command."); cvar_t net_enable_qtv = CVARD("net_enable_qtv", "1", "Listens for qtv proxies, or clients using the qtvplay command.");
#endif
#if defined(HAVE_SSL) #if defined(HAVE_SSL)
cvar_t net_enable_tls = CVARD("net_enable_tls", "1", "If enabled, binary data sent to a non-tls tcp port will be interpretted as a tls handshake (enabling https or wss over the same tcp port."); cvar_t net_enable_tls = CVARD("net_enable_tls", "1", "If enabled, binary data sent to a non-tls tcp port will be interpretted as a tls handshake (enabling https or wss over the same tcp port.");
#endif #endif
#ifdef SV_MASTER
cvar_t net_enable_http = CVARD("net_enable_http", "1", "If enabled, tcp ports will accept http clients, potentially serving large files which could distrupt gameplay.");
#else
cvar_t net_enable_http = CVARD("net_enable_http", "0", "If enabled, tcp ports will accept http clients, potentially serving large files which could distrupt gameplay."); cvar_t net_enable_http = CVARD("net_enable_http", "0", "If enabled, tcp ports will accept http clients, potentially serving large files which could distrupt gameplay.");
#endif
cvar_t net_enable_websockets = CVARD("net_enable_websockets", "1", "If enabled, tcp ports will accept websocket game clients."); cvar_t net_enable_websockets = CVARD("net_enable_websockets", "1", "If enabled, tcp ports will accept websocket game clients.");
cvar_t net_enable_webrtcbroker = CVARD("net_enable_webrtcbroker", "0", "If 1, tcp ports will accept websocket connections from clients trying to broker direct webrtc connections. This should be low traffic, but might involve a lot of mostly-idle connections."); cvar_t net_enable_webrtcbroker = CVARD("net_enable_webrtcbroker", "0", "If 1, tcp ports will accept websocket connections from clients trying to broker direct webrtc connections. This should be low traffic, but might involve a lot of mostly-idle connections.");
#endif #endif
#if defined(HAVE_DTLS) && !defined(CLIENTONLY) #if defined(HAVE_DTLS) && defined(HAVE_SERVER)
static void QDECL NET_Enable_DTLS_Changed(struct cvar_s *var, char *oldvalue) static void QDECL NET_Enable_DTLS_Changed(struct cvar_s *var, char *oldvalue)
{ {
//set up the default value //set up the default value
@ -156,7 +166,7 @@ static void QDECL NET_Enable_DTLS_Changed(struct cvar_s *var, char *oldvalue)
cvar_t net_enable_dtls = CVARAFCD("net_enable_dtls", "", "sv_listen_dtls", 0, NET_Enable_DTLS_Changed, "Controls serverside dtls support.\n0: dtls blocked, not advertised.\n1: available in desired.\n2: used where possible (recommended setting).\n3: disallow non-dtls clients (sv_port_tcp should be eg tls://[::]:27500 to also disallow unencrypted tcp connections)."); cvar_t net_enable_dtls = CVARAFCD("net_enable_dtls", "", "sv_listen_dtls", 0, NET_Enable_DTLS_Changed, "Controls serverside dtls support.\n0: dtls blocked, not advertised.\n1: available in desired.\n2: used where possible (recommended setting).\n3: disallow non-dtls clients (sv_port_tcp should be eg tls://[::]:27500 to also disallow unencrypted tcp connections).");
#endif #endif
#ifndef SERVERONLY #ifdef HAVE_CLIENT
static void QDECL cl_delay_packets_Announce(cvar_t *var, char *oldval) static void QDECL cl_delay_packets_Announce(cvar_t *var, char *oldval)
{ {
if (cls.state >= ca_connected && cl.fpd & FPD_ANOUNCE_FAKE_LAG) if (cls.state >= ca_connected && cl.fpd & FPD_ANOUNCE_FAKE_LAG)
@ -2079,7 +2089,7 @@ int TLS_GetChannelBinding(vfsfile_t *stream, qbyte *data, size_t *datasize)
///////////////////////////////////////////// /////////////////////////////////////////////
//loopback stuff //loopback stuff
#if !defined(CLIENTONLY) && !defined(SERVERONLY) #if defined(HAVE_SERVER) && defined(HAVE_CLIENT)
qboolean NET_GetLoopPacket (int sock, netadr_t *from, sizebuf_t *message) qboolean NET_GetLoopPacket (int sock, netadr_t *from, sizebuf_t *message)
{ {
@ -2240,7 +2250,7 @@ ftenet_connections_t *FTENET_CreateCollection(qboolean listen)
col->islisten = listen; col->islisten = listen;
return col; return col;
} }
#if !defined(SERVERONLY) && !defined(CLIENTONLY) #if defined(HAVE_CLIENT) && defined(HAVE_SERVER)
static ftenet_generic_connection_t *FTENET_Loop_EstablishConnection(qboolean isserver, const char *address, netadr_t adr); static ftenet_generic_connection_t *FTENET_Loop_EstablishConnection(qboolean isserver, const char *address, netadr_t adr);
#endif #endif
#ifdef HAVE_PACKET #ifdef HAVE_PACKET
@ -2438,11 +2448,11 @@ static void FTENET_NATPMP_Refresh(pmpcon_t *pmp, short oldport, ftenet_connectio
//get the public ip. //get the public ip.
pmpreqmsg.op = 0; pmpreqmsg.op = 0;
NET_SendPacket(NS_SERVER, 2, &pmpreqmsg, &pmp->pmpaddr); NET_SendPacket(collection, 2, &pmpreqmsg, &pmp->pmpaddr);
//open the firewall/nat. //open the firewall/nat.
pmpreqmsg.op = 1; pmpreqmsg.op = 1;
NET_SendPacket(NS_SERVER, sizeof(pmpreqmsg), &pmpreqmsg, &pmp->pmpaddr); NET_SendPacket(collection, sizeof(pmpreqmsg), &pmpreqmsg, &pmp->pmpaddr);
break; break;
} }
@ -2837,7 +2847,7 @@ qboolean FTENET_AddToCollection(ftenet_connections_t *col, const char *name, con
#ifdef HAVE_NATPMP #ifdef HAVE_NATPMP
if (adr[i].prot == NP_NATPMP&& adr[i].type == NA_IP) establish[i] = FTENET_NATPMP_EstablishConnection; else if (adr[i].prot == NP_NATPMP&& adr[i].type == NA_IP) establish[i] = FTENET_NATPMP_EstablishConnection; else
#endif #endif
#if !defined(CLIENTONLY) && !defined(SERVERONLY) #if defined(HAVE_CLIENT) && defined(HAVE_SERVER)
if (adr[i].prot == NP_DGRAM && adr[i].type == NA_LOOPBACK) establish[i] = FTENET_Loop_EstablishConnection; else if (adr[i].prot == NP_DGRAM && adr[i].type == NA_LOOPBACK) establish[i] = FTENET_Loop_EstablishConnection; else
#endif #endif
#ifdef HAVE_IPV4 #ifdef HAVE_IPV4
@ -3231,7 +3241,7 @@ qboolean FTENET_Datagram_GetPacket(ftenet_generic_connection_t *con)
else else
Con_TPrintf ("Connection lost or aborted\n"); //server died/connection lost. Con_TPrintf ("Connection lost or aborted\n"); //server died/connection lost.
resettime = curtime; resettime = curtime;
#ifndef SERVERONLY #ifdef HAVE_CLIENT
//fixme: synthesise a reset packet for the caller to handle? "\xff\xff\xff\xffreset" ? //fixme: synthesise a reset packet for the caller to handle? "\xff\xff\xff\xffreset" ?
if (cls.state != ca_disconnected && !con->islisten) if (cls.state != ca_disconnected && !con->islisten)
{ {
@ -3324,6 +3334,9 @@ neterr_t FTENET_Datagram_SendPacket(ftenet_generic_connection_t *con, int length
if (ecode == NET_EMSGSIZE) if (ecode == NET_EMSGSIZE)
return NETERR_MTU; return NETERR_MTU;
if (ecode == EADDRNOTAVAIL)
return NETERR_NOROUTE; //this interface doesn't actually support that (eg: happens when ipv6 is disabled on a specific interface).
if (ecode == NET_EACCES) if (ecode == NET_EACCES)
{ {
Con_Printf("Access denied: check firewall\n"); Con_Printf("Access denied: check firewall\n");
@ -3340,7 +3353,7 @@ neterr_t FTENET_Datagram_SendPacket(ftenet_generic_connection_t *con, int length
default: prot = ""; break; default: prot = ""; break;
} }
#ifndef SERVERONLY #ifdef HAVE_CLIENT
if (ecode == NET_EADDRNOTAVAIL) if (ecode == NET_EADDRNOTAVAIL)
Con_DPrintf("NET_Send%sPacket Warning: %i\n", prot, ecode); Con_DPrintf("NET_Send%sPacket Warning: %i\n", prot, ecode);
else else
@ -3652,7 +3665,7 @@ typedef struct ftenet_tcpconnect_stream_s {
TCPC_WEBSOCKETU, //utf-8 encoded data. TCPC_WEBSOCKETU, //utf-8 encoded data.
TCPC_WEBSOCKETB, //binary encoded data (subprotocol = 'binary') TCPC_WEBSOCKETB, //binary encoded data (subprotocol = 'binary')
TCPC_WEBSOCKETNQ, //raw nq msg buffers with no encapsulation or handshake TCPC_WEBSOCKETNQ, //raw nq msg buffers with no encapsulation or handshake
#ifndef CLIENTONLY #ifdef HAVE_HTTPSV
TCPC_HTTPCLIENT, //we're sending a file to this victim. TCPC_HTTPCLIENT, //we're sending a file to this victim.
TCPC_WEBRTC_CLIENT, //for brokering webrtc connections, doesn't carry any actual game data itself. TCPC_WEBRTC_CLIENT, //for brokering webrtc connections, doesn't carry any actual game data itself.
TCPC_WEBRTC_HOST //for brokering webrtc connections, doesn't carry any actual game data itself. TCPC_WEBRTC_HOST //for brokering webrtc connections, doesn't carry any actual game data itself.
@ -3670,7 +3683,7 @@ typedef struct ftenet_tcpconnect_stream_s {
int fakesequence; //TCPC_WEBSOCKETNQ int fakesequence; //TCPC_WEBSOCKETNQ
#ifndef CLIENTONLY #ifdef HAVE_HTTPSV
struct struct
{ {
qboolean connection_close; qboolean connection_close;
@ -3810,7 +3823,7 @@ neterr_t FTENET_TCPConnect_WebSocket_Splurge(ftenet_tcpconnect_stream_t *st, qby
return NETERR_SENT; return NETERR_SENT;
} }
#ifndef CLIENTONLY #ifdef HAVE_HTTPSV
enum enum
{ {
WCATTR_METHOD, WCATTR_METHOD,
@ -3866,7 +3879,9 @@ qboolean FTENET_TCPConnect_HTTPResponse(ftenet_tcpconnect_stream_t *st, httparg_
char *extraheaders = ""; char *extraheaders = "";
time_t modificationtime = 0; time_t modificationtime = 0;
char *query = strchr(arg[WCATTR_URL]+1, '?'); char *query = strchr(arg[WCATTR_URL]+1, '?');
#ifdef HAVE_SERVER
func_t func = 0; func_t func = 0;
#endif
if (query) if (query)
*query++ = 0; *query++ = 0;
@ -3875,6 +3890,7 @@ qboolean FTENET_TCPConnect_HTTPResponse(ftenet_tcpconnect_stream_t *st, httparg_
if (!*name) if (!*name)
name = "index.html"; name = "index.html";
#ifdef HAVE_SERVER
if (sv.state && svs.gametype == GT_PROGS && svprogfuncs) if (sv.state && svs.gametype == GT_PROGS && svprogfuncs)
func = svprogfuncs->FindFunction(svprogfuncs, "HTTP_GeneratePage", PR_ANY); func = svprogfuncs->FindFunction(svprogfuncs, "HTTP_GeneratePage", PR_ANY);
@ -3898,42 +3914,12 @@ qboolean FTENET_TCPConnect_HTTPResponse(ftenet_tcpconnect_stream_t *st, httparg_
resp = va("%s%s", *body?"HTTP/1.1 200 Ok\r\n":"HTTP/1.1 404 File Not Found\r\n", resp); resp = va("%s%s", *body?"HTTP/1.1 200 Ok\r\n":"HTTP/1.1 404 File Not Found\r\n", resp);
} }
} }
#endif
//FIXME: provide some resource->filename mapping that allows various misc files. //FIXME: provide some resource->filename mapping that allows various misc files.
if (body) if (body)
; ;
else if (!strcmp(name, "index.html"))
{
resp = "HTTP/1.1 200 Ok\r\n"
"Content-Type: text/html\r\n";
body = va(
"<html lang='en-us'>"
"<head>"
"<meta charset='utf-8'>"
"<meta http-equiv='Content-Type' content='text/html; charset=utf-8'>"
"<meta name=viewport content='width=device-width, initial-scale=1'>"
#ifdef _WIN32
"<link rel='icon' type='image/vnd.microsoft.icon' href='/favicon.ico' />"
#else
"<link rel='icon' type='image/vnd.microsoft.icon' href='"ENGINEWEBSITE"/favicon.ico' />"
#endif
"<title>%s - %s</title>"
"<style>"
"body { background-color:#000000; color:#808080; height:100%%;width:100%%;margin:0;padding:0;}"
"</style>"
"</head>"
"<body>"
"<iframe name='steve'"
" src='%s/%s?+connect%%20%s%s' allowfullscreen=true"
" frameborder='0' scrolling='no' marginheight='0' marginwidth='0' width='100%%' height='100%%'"
" onerror=\"alert('Failed to load engine')\">"
"</iframe>"
"</body>"
"</html>"
,fs_manifest->formalname, hostname.string, ENGINEWEBSITE, fs_manifest->installation, (st->remoteaddr.prot==NP_TLS)?"wss://":"ws://", arg[WCATTR_HOST]);
}
#ifdef _WIN32 #ifdef _WIN32
else if (!strcmp(name, "favicon.ico")) else if (!strcmp(name, "favicon.ico"))
{ //we can serve up the icon from the exe. we just have to reformat it a little. { //we can serve up the icon from the exe. we just have to reformat it a little.
@ -4001,6 +3987,42 @@ qboolean FTENET_TCPConnect_HTTPResponse(ftenet_tcpconnect_stream_t *st, httparg_
} }
} }
#endif #endif
#if defined(SV_MASTER) && !defined(HAVE_SERVER)
else if ((st->dlfile=SVM_GenerateIndex(name)))
;
#endif
#ifdef HAVE_SERVER
else if (!strcmp(name, "index.html"))
{
resp = "HTTP/1.1 200 Ok\r\n"
"Content-Type: text/html\r\n";
body = va(
"<html lang='en-us'>"
"<head>"
"<meta charset='utf-8'>"
"<meta http-equiv='Content-Type' content='text/html; charset=utf-8'>"
"<meta name=viewport content='width=device-width, initial-scale=1'>"
#ifdef _WIN32
"<link rel='icon' type='image/vnd.microsoft.icon' href='/favicon.ico' />"
#else
"<link rel='icon' type='image/vnd.microsoft.icon' href='"ENGINEWEBSITE"/favicon.ico' />"
#endif
"<title>%s - %s</title>"
"<style>"
"body { background-color:#000000; color:#808080; height:100%%;width:100%%;margin:0;padding:0;}"
"</style>"
"</head>"
"<body>"
"<iframe name='steve'"
" src='%s/%s?+connect%%20%s%s' allowfullscreen=true"
" frameborder='0' scrolling='no' marginheight='0' marginwidth='0' width='100%%' height='100%%'"
" onerror=\"alert('Failed to load engine')\">"
"</iframe>"
"</body>"
"</html>"
,fs_manifest->formalname, hostname.string, ENGINEWEBSITE, fs_manifest->installation, (st->remoteaddr.prot==NP_TLS)?"wss://":"ws://", arg[WCATTR_HOST]);
}
/*else if (!strcmp(name, "default.fmf") && (st->dlfile = FS_OpenVFS("default.fmf", "rb", FS_ROOT))) /*else if (!strcmp(name, "default.fmf") && (st->dlfile = FS_OpenVFS("default.fmf", "rb", FS_ROOT)))
{ {
resp = "HTTP/1.1 200 Ok\r\n" resp = "HTTP/1.1 200 Ok\r\n"
@ -4095,6 +4117,7 @@ qboolean FTENET_TCPConnect_HTTPResponse(ftenet_tcpconnect_stream_t *st, httparg_
else else
st->dlfile = NULL; st->dlfile = NULL;
} }
#endif
if (st->dlfile) if (st->dlfile)
{ {
char etag[64]; char etag[64];
@ -4700,7 +4723,7 @@ void FTENET_TCPConnect_PrintStatus(ftenet_generic_connection_t *gcon)
case TCPC_WEBSOCKETNQ: case TCPC_WEBSOCKETNQ:
Con_Printf("websocket %s\n", adr); Con_Printf("websocket %s\n", adr);
break; break;
#ifndef CLIENTONLY #ifdef HAVE_HTTPSV
case TCPC_HTTPCLIENT: case TCPC_HTTPCLIENT:
Con_Printf("http %s\n", adr); Con_Printf("http %s\n", adr);
break; break;
@ -4750,7 +4773,7 @@ qboolean FTENET_TCPConnect_GetPacket(ftenet_generic_connection_t *gcon)
if (st->timeouttime < timeval) if (st->timeouttime < timeval)
{ {
#ifndef CLIENTONLY #ifdef HAVE_HTTPSV
if (!st->pinging && (st->clienttype==TCPC_WEBRTC_CLIENT||st->clienttype==TCPC_WEBRTC_HOST) && *st->webrtc.resource) if (!st->pinging && (st->clienttype==TCPC_WEBRTC_CLIENT||st->clienttype==TCPC_WEBRTC_HOST) && *st->webrtc.resource)
{ //ping broker clients. there usually shouldn't be any data flow to keep it active otherwise. { //ping broker clients. there usually shouldn't be any data flow to keep it active otherwise.
st->timeouttime = timeval + 30; st->timeouttime = timeval + 30;
@ -4761,7 +4784,7 @@ qboolean FTENET_TCPConnect_GetPacket(ftenet_generic_connection_t *gcon)
else else
#endif #endif
{ {
Con_Printf ("tcp peer %s timed out\n", NET_AdrToString (adr, sizeof(adr), &st->remoteaddr)); Con_DPrintf ("tcp peer %s timed out\n", NET_AdrToString (adr, sizeof(adr), &st->remoteaddr));
goto closesvstream; goto closesvstream;
} }
} }
@ -4784,10 +4807,11 @@ closesvstream:
if (st->inlen < 6) if (st->inlen < 6)
continue; continue;
#if defined(HAVE_SSL) && !defined(CLIENTONLY) //if its non-ascii, then try and upgrade the connection to tls #if defined(HAVE_SSL) && (defined(HAVE_SERVER) || defined(HAVE_HTTPSV)) //if its non-ascii, then try and upgrade the connection to tls
if (net_enable_tls.ival && con->generic.islisten && st->remoteaddr.prot == NP_STREAM && st->clientstream && !((st->inbuffer[0] >= 'a' && st->inbuffer[0] <= 'z') || (st->inbuffer[0] >= 'A' && st->inbuffer[0] <= 'Z'))) if (net_enable_tls.ival && con->generic.islisten && st->remoteaddr.prot == NP_STREAM && st->clientstream && !((st->inbuffer[0] >= 'a' && st->inbuffer[0] <= 'z') || (st->inbuffer[0] >= 'A' && st->inbuffer[0] <= 'Z')))
{ {
//copy off our buffer so we can read it into the tls stream's buffer instead. //copy off our buffer so we can read it into the tls stream's buffer instead.
char tmpbuf[256];
vfsfile_t *stream = st->clientstream; vfsfile_t *stream = st->clientstream;
int (QDECL *realread) (struct vfsfile_s *file, void *buffer, int bytestoread); int (QDECL *realread) (struct vfsfile_s *file, void *buffer, int bytestoread);
realread = stream->ReadBytes; realread = stream->ReadBytes;
@ -4806,6 +4830,8 @@ closesvstream:
} }
if (!st->clientstream || net_message.cursize) if (!st->clientstream || net_message.cursize)
goto closesvstream; //something cocked up. we didn't give the tls stream all the data. goto closesvstream; //something cocked up. we didn't give the tls stream all the data.
if (developer.ival)
Con_Printf("promoted peer to tls: %s\n", NET_AdrToString(tmpbuf, sizeof(tmpbuf), &st->remoteaddr));
net_message.cursize = 0; net_message.cursize = 0;
continue; continue;
} }
@ -4813,11 +4839,11 @@ closesvstream:
if (!strncmp(st->inbuffer, "qizmo\n", 6)) if (!strncmp(st->inbuffer, "qizmo\n", 6))
{ {
#ifdef CLIENTONLY if (
if (1) #ifdef HAVE_SERVER
#else net_enable_qizmo.ival ||
if (net_enable_qizmo.ival || !con->generic.islisten)
#endif #endif
!con->generic.islisten)
{ {
memmove(st->inbuffer, st->inbuffer+6, st->inlen - (6)); memmove(st->inbuffer, st->inbuffer+6, st->inlen - (6));
st->inlen -= 6; st->inlen -= 6;
@ -4830,9 +4856,9 @@ closesvstream:
} }
else else
goto closesvstream; goto closesvstream;
} }else
#ifndef CLIENTONLY #ifdef HAVE_HTTPSV
else if (con->generic.islisten)// && !strncmp(st->inbuffer, "GET ", 4)) if (con->generic.islisten)// && !strncmp(st->inbuffer, "GET ", 4))
{ {
//qtv or http request header. these terminate with a blank line. //qtv or http request header. these terminate with a blank line.
int i = 0; int i = 0;
@ -4889,16 +4915,15 @@ closesvstream:
} }
continue; continue;
} }
} }else
#endif #endif
else
{ {
Con_Printf ("Unknown TCP handshake from %s\n", NET_AdrToString (adr, sizeof(adr), &st->remoteaddr)); Con_DPrintf ("Unknown TCP handshake from %s\n", NET_AdrToString (adr, sizeof(adr), &st->remoteaddr));
goto closesvstream; goto closesvstream;
} }
break; break;
#ifndef CLIENTONLY #ifdef HAVE_HTTPSV
case TCPC_HTTPCLIENT: case TCPC_HTTPCLIENT:
if (st->outlen) if (st->outlen)
{ /*try and flush the old data*/ { /*try and flush the old data*/
@ -4924,7 +4949,7 @@ closesvstream:
VFS_CLOSE(st->dlfile); VFS_CLOSE(st->dlfile);
st->dlfile = NULL; st->dlfile = NULL;
st->clienttype = TCPC_UNKNOWN; st->clienttype = TCPC_UNKNOWN;
Con_Printf ("Outgoing file transfer complete\n"); Con_DPrintf ("Outgoing file transfer complete\n");
if (st->httpstate.connection_close) if (st->httpstate.connection_close)
goto closesvstream; goto closesvstream;
} }
@ -4958,7 +4983,7 @@ closesvstream:
case TCPC_WEBSOCKETU: case TCPC_WEBSOCKETU:
case TCPC_WEBSOCKETB: case TCPC_WEBSOCKETB:
case TCPC_WEBSOCKETNQ: case TCPC_WEBSOCKETNQ:
#ifndef CLIENTONLY #ifdef HAVE_HTTPSV
case TCPC_WEBRTC_HOST: case TCPC_WEBRTC_HOST:
case TCPC_WEBRTC_CLIENT: case TCPC_WEBRTC_CLIENT:
#endif #endif
@ -5108,7 +5133,7 @@ closesvstream:
Con_TPrintf ("Warning: Oversize packet from %s\n", NET_AdrToString (adr, sizeof(adr), &st->remoteaddr)); Con_TPrintf ("Warning: Oversize packet from %s\n", NET_AdrToString (adr, sizeof(adr), &st->remoteaddr));
goto closesvstream; goto closesvstream;
} }
#ifndef CLIENTONLY #ifdef HAVE_HTTPSV
#ifdef SUPPORT_RTC_ICE #ifdef SUPPORT_RTC_ICE
if (st->clienttype == TCPC_WEBRTC_CLIENT && !*st->webrtc.resource) if (st->clienttype == TCPC_WEBRTC_CLIENT && !*st->webrtc.resource)
{ //this is a client that's corrected directly to us via webrtc. { //this is a client that's corrected directly to us via webrtc.
@ -5211,6 +5236,8 @@ closesvstream:
st = Z_Malloc(sizeof(*con->tcpstreams)); st = Z_Malloc(sizeof(*con->tcpstreams));
/*grab the net address*/ /*grab the net address*/
SockadrToNetadr(&from, fromlen, &st->remoteaddr); SockadrToNetadr(&from, fromlen, &st->remoteaddr);
if (developer.ival)
Con_Printf("new TCP connection from %s\n", NET_AdrToString(tmpbuf, sizeof(tmpbuf), &st->remoteaddr));
st->clienttype = TCPC_UNKNOWN; st->clienttype = TCPC_UNKNOWN;
st->next = con->tcpstreams; st->next = con->tcpstreams;
con->tcpstreams = st; con->tcpstreams = st;
@ -5489,7 +5516,7 @@ int FTENET_TCPConnect_SetFDSets(ftenet_generic_connection_t *gcon, fd_set *readf
#endif #endif
if (st->clientstream == NULL || st->socketnum == INVALID_SOCKET) if (st->clientstream == NULL || st->socketnum == INVALID_SOCKET)
continue; continue;
#ifndef CLIENTONLY #ifdef HAVE_HTTPSV
if (st->clienttype == TCPC_HTTPCLIENT) if (st->clienttype == TCPC_HTTPCLIENT)
FD_SET(st->socketnum, writefdset); // network socket FD_SET(st->socketnum, writefdset); // network socket
#endif #endif
@ -6839,7 +6866,7 @@ qboolean NET_GetRates(ftenet_connections_t *collection, float *pi, float *po, fl
return true; return true;
} }
#ifndef SERVERONLY #ifdef HAVE_CLIENT
//for demo playback //for demo playback
qboolean NET_UpdateRates(ftenet_connections_t *collection, qboolean inbound, size_t size) qboolean NET_UpdateRates(ftenet_connections_t *collection, qboolean inbound, size_t size)
{ {
@ -6877,29 +6904,10 @@ qboolean NET_UpdateRates(ftenet_connections_t *collection, qboolean inbound, siz
#endif #endif
/*firstsock is a cookie*/ /*firstsock is a cookie*/
int NET_GetPacket (netsrc_t netsrc, int firstsock) int NET_GetPacket (ftenet_connections_t *collection, int firstsock)
{ {
struct ftenet_delayed_packet_s *p; struct ftenet_delayed_packet_s *p;
ftenet_connections_t *collection;
unsigned int ctime; unsigned int ctime;
if (netsrc == NS_SERVER)
{
#ifdef CLIENTONLY
Sys_Error("NET_GetPacket: Bad netsrc");
collection = NULL;
#else
collection = svs.sockets;
#endif
}
else
{
#ifdef SERVERONLY
Sys_Error("NET_GetPacket: Bad netsrc");
collection = NULL;
#else
collection = cls.sockets;
#endif
}
if (!collection) if (!collection)
return -1; return -1;
@ -7032,28 +7040,13 @@ static neterr_t NET_SendPacketCol (ftenet_connections_t *collection, int length,
return NETERR_NOROUTE; return NETERR_NOROUTE;
} }
neterr_t NET_SendPacket (netsrc_t netsrc, int length, const void *data, netadr_t *to) neterr_t NET_SendPacket (ftenet_connections_t *collection, int length, const void *data, netadr_t *to)
{ {
ftenet_connections_t *collection; if (!collection)
if (netsrc == NS_SERVER)
{
#ifdef CLIENTONLY
Sys_Error("NET_GetPacket: Bad netsrc");
return NETERR_NOROUTE; return NETERR_NOROUTE;
#else
collection = svs.sockets;
#endif
}
else
{
#ifdef SERVERONLY
Sys_Error("NET_GetPacket: Bad netsrc");
return NETERR_NOROUTE;
#else
collection = cls.sockets;
if (cl_delay_packets.ival >= 1 && !(cl.fpd & FPD_NO_FAKE_LAG)) #ifdef HAVE_CLIENT
if (collection == cls.sockets && cl_delay_packets.ival >= 1 && !(cl.fpd & FPD_NO_FAKE_LAG))
{ {
struct ftenet_delayed_packet_s *p, **l; struct ftenet_delayed_packet_s *p, **l;
if (!collection) if (!collection)
@ -7070,7 +7063,7 @@ neterr_t NET_SendPacket (netsrc_t netsrc, int length, const void *data, netadr_t
return NETERR_SENT; //fixme: mtu, noroute, etc... panic? only allow if udp dest? return NETERR_SENT; //fixme: mtu, noroute, etc... panic? only allow if udp dest?
} }
#endif #endif
}
#ifdef HAVE_DTLS #ifdef HAVE_DTLS
if (to->prot == NP_DTLS) if (to->prot == NP_DTLS)
return FTENET_DTLS_SendPacket(collection, length, data, to); return FTENET_DTLS_SendPacket(collection, length, data, to);
@ -7592,7 +7585,6 @@ void IPX_CloseSocket (int socket)
// sleeps msec or until net socket is ready // sleeps msec or until net socket is ready
//stdin can sometimes be a socket. As a result, //stdin can sometimes be a socket. As a result,
//we give the option to select it for nice console imput with timeouts. //we give the option to select it for nice console imput with timeouts.
#ifndef CLIENTONLY
qboolean NET_Sleep(float seconds, qboolean stdinissocket) qboolean NET_Sleep(float seconds, qboolean stdinissocket)
{ {
#ifdef HAVE_PACKET #ifdef HAVE_PACKET
@ -7613,6 +7605,34 @@ qboolean NET_Sleep(float seconds, qboolean stdinissocket)
maxfd = sock; maxfd = sock;
} }
#ifdef SV_MASTER
{
extern ftenet_connections_t *svm_sockets;
if (svm_sockets)
for (con = 0; con < MAX_CONNECTIONS; con++)
{
if (!svm_sockets->conn[con])
continue;
if (svm_sockets->conn[con]->SetFDSets)
{
sock = svm_sockets->conn[con]->SetFDSets(svm_sockets->conn[con], &readfdset, &writefdset);
if (sock > maxfd)
maxfd = sock;
}
else
{
sock = svm_sockets->conn[con]->thesocket;
if (sock != INVALID_SOCKET)
{
FD_SET(sock, &readfdset); // network socket
if (sock > maxfd)
maxfd = sock;
}
}
}
}
#endif
#ifdef HAVE_SERVER
if (svs.sockets) if (svs.sockets)
for (con = 0; con < MAX_CONNECTIONS; con++) for (con = 0; con < MAX_CONNECTIONS; con++)
{ {
@ -7635,6 +7655,7 @@ qboolean NET_Sleep(float seconds, qboolean stdinissocket)
} }
} }
} }
#endif
if (seconds > 4.0) //realy? oh well. if (seconds > 4.0) //realy? oh well.
seconds = 4.0; seconds = 4.0;
@ -7654,7 +7675,6 @@ qboolean NET_Sleep(float seconds, qboolean stdinissocket)
#endif #endif
return true; return true;
} }
#endif
//this function is used to determine the 'default' local address. //this function is used to determine the 'default' local address.
//this is used for compat with gamespy which insists on sending us a packet via that interface and not something more sensible like 127.0.0.1 //this is used for compat with gamespy which insists on sending us a packet via that interface and not something more sensible like 127.0.0.1
@ -7725,7 +7745,7 @@ void NET_GetLocalAddress (int socket, netadr_t *out)
out->type = NA_INVALID; out->type = NA_INVALID;
} }
#ifndef CLIENTONLY #ifdef HAVE_SERVER
void SVNET_AddPort_f(void) void SVNET_AddPort_f(void)
{ {
char *s = Cmd_Argv(1); char *s = Cmd_Argv(1);
@ -7745,7 +7765,7 @@ void SVNET_AddPort_f(void)
if (!svs.sockets) if (!svs.sockets)
{ {
svs.sockets = FTENET_CreateCollection(true); svs.sockets = FTENET_CreateCollection(true);
#ifndef SERVERONLY #ifdef HAVE_CLIENT
FTENET_AddToCollection(svs.sockets, "SVLoopback", STRINGIFY(PORT_DEFAULTSERVER), NA_LOOPBACK, NP_DGRAM); FTENET_AddToCollection(svs.sockets, "SVLoopback", STRINGIFY(PORT_DEFAULTSERVER), NA_LOOPBACK, NP_DGRAM);
#endif #endif
} }
@ -7754,7 +7774,7 @@ void SVNET_AddPort_f(void)
} }
#endif #endif
#ifndef SERVERONLY #ifdef HAVE_CLIENT
void NET_ClientPort_f(void) void NET_ClientPort_f(void)
{ {
Con_Printf("Active Client ports:\n"); Con_Printf("Active Client ports:\n");
@ -7763,31 +7783,15 @@ void NET_ClientPort_f(void)
} }
#endif #endif
qboolean NET_WasSpecialPacket(netsrc_t netsrc) qboolean NET_WasSpecialPacket(ftenet_connections_t *collection)
{ {
#if defined(HAVE_NATPMP)
ftenet_connections_t *collection = NULL;
if (netsrc == NS_SERVER)
{
#ifndef CLIENTONLY
collection = svs.sockets;
#endif
}
else
{
#ifndef SERVERONLY
collection = cls.sockets;
#endif
}
#ifdef HAVE_NATPMP #ifdef HAVE_NATPMP
if (NET_Was_NATPMP(collection)) if (NET_Was_NATPMP(collection))
return true; return true;
#endif #endif
#endif
#ifdef SUPPORT_ICE #ifdef SUPPORT_ICE
if (ICE_WasStun(netsrc)) if (ICE_WasStun(collection))
return true; return true;
#endif #endif
@ -7833,10 +7837,25 @@ void NET_Init (void)
Cvar_Register(&net_hybriddualstack, "networking"); Cvar_Register(&net_hybriddualstack, "networking");
Cvar_Register(&net_fakeloss, "networking"); Cvar_Register(&net_fakeloss, "networking");
#ifndef CLIENTONLY #if defined(TCPCONNECT) && (defined(HAVE_SERVER) || defined(HAVE_HTTPSV))
#ifdef HAVE_SERVER
Cvar_Register(&net_enable_qizmo, "networking");
Cvar_Register(&net_enable_qtv, "networking");
#endif
#if defined(HAVE_SSL)
Cvar_Register(&net_enable_tls, "networking");
#endif
Cvar_Register(&net_enable_http, "networking");
Cvar_Register(&net_enable_websockets, "networking");
Cvar_Register(&net_enable_webrtcbroker, "networking");
#endif
#ifdef HAVE_SERVER
Cmd_AddCommand("sv_addport", SVNET_AddPort_f); Cmd_AddCommand("sv_addport", SVNET_AddPort_f);
#endif #endif
#ifndef SERVERONLY #ifdef HAVE_CLIENT
Cvar_Register(&cl_delay_packets, "networking"); Cvar_Register(&cl_delay_packets, "networking");
Cmd_AddCommand("cl_addport", NET_ClientPort_f); Cmd_AddCommand("cl_addport", NET_ClientPort_f);
#endif #endif
@ -7854,9 +7873,11 @@ void NET_Init (void)
SSL_Init(); SSL_Init();
#endif #endif
#if defined(HAVE_CLIENT)||defined(HAVE_SERVER)
Net_Master_Init(); Net_Master_Init();
#endif
} }
#ifndef SERVERONLY #ifdef HAVE_CLIENT
void NET_CloseClient(void) void NET_CloseClient(void)
{ //called by disconnect console command { //called by disconnect console command
FTENET_CloseCollection(cls.sockets); FTENET_CloseCollection(cls.sockets);
@ -7881,7 +7902,7 @@ void NET_InitClient(qboolean loopbackonly)
if (!cls.sockets) if (!cls.sockets)
cls.sockets = FTENET_CreateCollection(false); cls.sockets = FTENET_CreateCollection(false);
#ifndef CLIENTONLY #ifdef HAVE_SERVER
FTENET_AddToCollection(cls.sockets, "CLLoopback", "1", NA_LOOPBACK, NP_DGRAM); FTENET_AddToCollection(cls.sockets, "CLLoopback", "1", NA_LOOPBACK, NP_DGRAM);
#endif #endif
if (loopbackonly) if (loopbackonly)
@ -7909,7 +7930,7 @@ void NET_InitClient(qboolean loopbackonly)
} }
#endif #endif
#ifndef CLIENTONLY #ifdef HAVE_SERVER
#ifdef HAVE_IPV4 #ifdef HAVE_IPV4
static void QDECL SV_Tcpport_Callback(struct cvar_s *var, char *oldvalue) static void QDECL SV_Tcpport_Callback(struct cvar_s *var, char *oldvalue)
{ {
@ -8018,18 +8039,7 @@ void SVNET_RegisterCvars(void)
// Cvar_Register (&sv_port_unix, "networking"); // Cvar_Register (&sv_port_unix, "networking");
#endif #endif
#if defined(HAVE_DTLS) && defined(HAVE_SERVER)
#if defined(TCPCONNECT) && !defined(CLIENTONLY)
Cvar_Register (&net_enable_qizmo, "networking");
Cvar_Register (&net_enable_qtv, "networking");
#if defined(HAVE_SSL)
Cvar_Register (&net_enable_tls, "networking");
#endif
Cvar_Register (&net_enable_http, "networking");
Cvar_Register (&net_enable_websockets, "networking");
Cvar_Register (&net_enable_webrtcbroker, "networking");
#endif
#if defined(HAVE_DTLS) && !defined(CLIENTONLY)
Cvar_Register (&net_enable_dtls, "networking"); Cvar_Register (&net_enable_dtls, "networking");
#endif #endif
} }
@ -8052,7 +8062,7 @@ void NET_InitServer(void)
if (!svs.sockets) if (!svs.sockets)
{ {
svs.sockets = FTENET_CreateCollection(true); svs.sockets = FTENET_CreateCollection(true);
#ifndef SERVERONLY #ifdef HAVE_CLIENT
FTENET_AddToCollection(svs.sockets, "SVLoopback", STRINGIFY(PORT_DEFAULTSERVER), NA_LOOPBACK, NP_DGRAM); FTENET_AddToCollection(svs.sockets, "SVLoopback", STRINGIFY(PORT_DEFAULTSERVER), NA_LOOPBACK, NP_DGRAM);
#endif #endif
} }
@ -8092,7 +8102,7 @@ void NET_InitServer(void)
{ {
NET_CloseServer(); NET_CloseServer();
#ifndef SERVERONLY #ifdef HAVE_CLIENT
svs.sockets = FTENET_CreateCollection(true); svs.sockets = FTENET_CreateCollection(true);
FTENET_AddToCollection(svs.sockets, "SVLoopback", STRINGIFY(PORT_DEFAULTSERVER), NA_LOOPBACK, NP_DGRAM); FTENET_AddToCollection(svs.sockets, "SVLoopback", STRINGIFY(PORT_DEFAULTSERVER), NA_LOOPBACK, NP_DGRAM);
#endif #endif
@ -8113,10 +8123,10 @@ NET_Shutdown
*/ */
void NET_Shutdown (void) void NET_Shutdown (void)
{ {
#ifndef CLIENTONLY #ifdef HAVE_SERVER
NET_CloseServer(); NET_CloseServer();
#endif #endif
#ifndef SERVERONLY #ifdef HAVE_CLIENT
FTENET_CloseCollection(cls.sockets); FTENET_CloseCollection(cls.sockets);
cls.sockets = NULL; cls.sockets = NULL;
#endif #endif

View file

@ -365,7 +365,7 @@ typedef struct ftenet_connections_s
} ftenet_connections_t; } ftenet_connections_t;
void ICE_Tick(void); void ICE_Tick(void);
qboolean ICE_WasStun(netsrc_t netsrc); qboolean ICE_WasStun(ftenet_connections_t *col);
void QDECL ICE_AddLCandidateConn(ftenet_connections_t *col, netadr_t *addr, int type); void QDECL ICE_AddLCandidateConn(ftenet_connections_t *col, netadr_t *addr, int type);
void QDECL ICE_AddLCandidateInfo(struct icestate_s *con, netadr_t *adr, int adrno, int type); void QDECL ICE_AddLCandidateInfo(struct icestate_s *con, netadr_t *adr, int adrno, int type);

View file

@ -1463,8 +1463,12 @@ static qintptr_t VARGS Plug_Net_SendTo(void *offset, quintptr_t mask, const qint
struct sockaddr_qstorage sockaddr; struct sockaddr_qstorage sockaddr;
if (handle == -1) if (handle == -1)
{ {
NET_SendPacket(NS_CLIENT, srclen, src, address); #ifdef HAVE_CLIENT
NET_SendPacket(cls.sockets, srclen, src, address);
return srclen; return srclen;
#else
return -2;
#endif
} }
NetadrToSockadr(address, &sockaddr); NetadrToSockadr(address, &sockaddr);

View file

@ -1404,7 +1404,7 @@ cvar_t *PF_Cvar_FindOrGet(const char *var_name)
var = Cvar_Get(var_name, def, 0, "Implicit QC variables"); var = Cvar_Get(var_name, def, 0, "Implicit QC variables");
if (var) if (var)
Con_Printf("^3Created QC Cvar %s\n", var_name); Con_DPrintf("^3Created QC Cvar %s\n", var_name);
else else
Con_Printf(CON_ERROR"Unable to create QC Cvar %s\n", var_name); Con_Printf(CON_ERROR"Unable to create QC Cvar %s\n", var_name);
} }

View file

@ -4,6 +4,14 @@
//field info, netchan, and the WriteBits stuff (which should probably be moved to common.c with the others) //field info, netchan, and the WriteBits stuff (which should probably be moved to common.c with the others)
//also contains vm filesystem //also contains vm filesystem
#if defined(HAVE_CLIENT) && defined(HAVE_SERVER)
#define NET_SendPacket(c,s,d,t) NET_SendPacket(((c)!=NS_CLIENT)?svs.sockets:cls.sockets,s,d,t)
#elif defined(HAVE_SERVER)
#define NET_SendPacket(c,s,d,t) NET_SendPacket(svs.sockets,s,d,t)
#else
#define NET_SendPacket(c,s,d,t) NET_SendPacket(cls.sockets,s,d,t)
#endif
#define MAX_VM_FILES 8 #define MAX_VM_FILES 8
typedef struct { typedef struct {

View file

@ -8,26 +8,21 @@
//untranslate is lang->english for console commands. //untranslate is lang->english for console commands.
int com_language;
char sys_language[64] = ""; char sys_language[64] = "";
static char langpath[MAX_OSPATH] = ""; static char langpath[MAX_OSPATH] = "";
struct language_s languages[MAX_LANGUAGES]; struct language_s languages[MAX_LANGUAGES];
static void QDECL TL_LanguageChanged(struct cvar_s *var, char *oldvalue) static void QDECL TL_LanguageChanged(struct cvar_s *var, char *oldvalue)
{ {
#ifndef CLIENTONLY com_language = TL_FindLanguage(var->string);
svs.language = TL_FindLanguage(var->string);
#endif
#ifndef SERVERONLY
cls.language = TL_FindLanguage(var->string);
#endif
} }
cvar_t language = CVARAFC("lang", sys_language, "prvm_language", CVAR_USERINFO, TL_LanguageChanged); cvar_t language = CVARAFC("lang", sys_language, "prvm_language", CVAR_USERINFO, TL_LanguageChanged);
void TranslateInit(void) void TranslateInit(void)
{ {
Cvar_Register(&language, "International variables"); Cvar_Register(&language, "Internationalisation");
} }
void TL_Shutdown(void) void TL_Shutdown(void)
@ -145,12 +140,7 @@ void TL_InitLanguages(const char *newlangpath)
*lang = 0; *lang = 0;
//but we do support territories. //but we do support territories.
#ifndef CLIENTONLY com_language = TL_FindLanguage(sys_language);
svs.language = TL_FindLanguage(sys_language);
#endif
#ifndef SERVERONLY
cls.language = TL_FindLanguage(sys_language);
#endif
//make sure a fallback exists, but not as language 0 //make sure a fallback exists, but not as language 0
TL_FindLanguage(""); TL_FindLanguage("");
@ -226,7 +216,7 @@ char *T_GetString(int num)
return strings_table[num]; return strings_table[num];
} }
#ifndef SERVERONLY #ifdef HAVE_CLIENT
//for hexen2's objectives and stuff. //for hexen2's objectives and stuff.
static char *info_strings_list; static char *info_strings_list;
static char **info_strings_table; static char **info_strings_table;

View file

@ -14,6 +14,8 @@ struct language_s
struct po_s *po; struct po_s *po;
}; };
extern struct language_s languages[MAX_LANGUAGES]; extern struct language_s languages[MAX_LANGUAGES];
extern int com_language;
extern cvar_t language;
#define langtext(t,l) PO_GetText(languages[l].po, t) #define langtext(t,l) PO_GetText(languages[l].po, t)
int TL_FindLanguage(const char *lang); int TL_FindLanguage(const char *lang);

View file

@ -174,7 +174,8 @@ typedef struct wedict_s wedict_t;
typedef struct typedef struct
{ {
qboolean present; qboolean present;
vec3_t laggedpos; vec3_t origin;
vec3_t angles;
} laggedentinfo_t; } laggedentinfo_t;
#ifdef USERBE #ifdef USERBE
@ -206,6 +207,7 @@ struct world_s
qboolean (QDECL *Event_ContentsTransition) (struct world_s *w, wedict_t *ent, int oldwatertype, int newwatertype); qboolean (QDECL *Event_ContentsTransition) (struct world_s *w, wedict_t *ent, int oldwatertype, int newwatertype);
model_t *(QDECL *Get_CModel)(struct world_s *w, int modelindex); model_t *(QDECL *Get_CModel)(struct world_s *w, int modelindex);
void (QDECL *Get_FrameState)(struct world_s *w, wedict_t *s, framestate_t *fstate); void (QDECL *Get_FrameState)(struct world_s *w, wedict_t *s, framestate_t *fstate);
void (QDECL *Event_Backdate)(struct world_s *w, wedict_t *s, float timestamp); //called for MOVE_LAGGED+MOVE_HITMODEL traces
unsigned int keydestmask; //menu:kdm_menu, csqc:kdm_game, server:0 unsigned int keydestmask; //menu:kdm_menu, csqc:kdm_game, server:0
unsigned int max_edicts; //limiting factor... 1024 fields*4*MAX_EDICTS == a heck of a lot. unsigned int max_edicts; //limiting factor... 1024 fields*4*MAX_EDICTS == a heck of a lot.
@ -242,6 +244,7 @@ struct world_s
/*antilag*/ /*antilag*/
float lagentsfrac; float lagentsfrac;
float lagentstime;
laggedentinfo_t *lagents; laggedentinfo_t *lagents;
unsigned int maxlagents; unsigned int maxlagents;

View file

@ -641,14 +641,16 @@ CACHE MEMORY
void Cache_Flush(void) void Cache_Flush(void)
{ {
//this generically named function is hyjacked to flush models and sounds, as well as ragdolls etc //this generically named function is hyjacked to flush models and sounds, as well as ragdolls etc
#ifdef HAVE_CLIENT
S_Purge(false);
#endif
#if defined(HAVE_CLIENT) || defined(HAVE_SERVER)
#ifdef RAGDOLL #ifdef RAGDOLL
rag_flushdolls(true); rag_flushdolls(true);
#endif
#ifndef SERVERONLY
S_Purge(false);
#endif #endif
Mod_Purge(MP_FLUSH); Mod_Purge(MP_FLUSH);
#ifndef SERVERONLY #endif
#ifdef HAVE_CLIENT
Image_Purge(); Image_Purge();
#endif #endif
} }

View file

@ -3450,13 +3450,11 @@ static void BE_Program_Set_Attributes(const program_t *prog, struct programpermu
case SP_M_MODEL: case SP_M_MODEL:
qglUniformMatrix4fvARB(ph, 1, false, shaderstate.modelmatrix); qglUniformMatrix4fvARB(ph, 1, false, shaderstate.modelmatrix);
break; break;
case SP_M_ENTBONES: case SP_M_ENTBONES_PACKED:
{
if (sh_config.maxver>=120)
qglUniformMatrix3x4fv(ph, shaderstate.sourcevbo->numbones, false, shaderstate.sourcevbo->bones);
else
qglUniform4fvARB(ph, shaderstate.sourcevbo->numbones*3, shaderstate.sourcevbo->bones); qglUniform4fvARB(ph, shaderstate.sourcevbo->numbones*3, shaderstate.sourcevbo->bones);
} break;
case SP_M_ENTBONES_MAT3X4:
qglUniformMatrix3x4fv(ph, shaderstate.sourcevbo->numbones, false, shaderstate.sourcevbo->bones);
break; break;
case SP_M_INVVIEWPROJECTION: case SP_M_INVVIEWPROJECTION:
{ {
@ -4561,7 +4559,7 @@ static void DrawMeshes(void)
#endif #endif
break; break;
case BEM_DEPTHDARK: case BEM_DEPTHDARK:
if ((shaderstate.curshader->flags & SHADER_HASLIGHTMAP) && !TEXVALID(shaderstate.curtexnums->fullbright)) if ((shaderstate.curshader->flags & (SHADER_HASLIGHTMAP|SHADER_NODLIGHT))==SHADER_HASLIGHTMAP && !TEXVALID(shaderstate.curtexnums->fullbright))
{ {
if (gl_config.arb_shader_objects) if (gl_config.arb_shader_objects)
{ {

View file

@ -777,6 +777,7 @@ void Mod_Init (qboolean initial)
Cvar_Register(&mod_loadentfiles, NULL); Cvar_Register(&mod_loadentfiles, NULL);
Cvar_Register(&mod_loadentfiles_dir, NULL); Cvar_Register(&mod_loadentfiles_dir, NULL);
Cvar_Register(&temp_lit2support, NULL); Cvar_Register(&temp_lit2support, NULL);
Cvar_Register (&r_meshpitch, "Gamecode");
Cmd_AddCommandD("sv_saveentfile", Mod_SaveEntFile_f, "Dumps a copy of the map's entities to disk, so that it can be edited and used as a replacement for slightly customised maps."); Cmd_AddCommandD("sv_saveentfile", Mod_SaveEntFile_f, "Dumps a copy of the map's entities to disk, so that it can be edited and used as a replacement for slightly customised maps.");
Cmd_AddCommandD("mod_showent", Mod_ShowEnt_f, "Allows you to quickly search through a map's entities."); Cmd_AddCommandD("mod_showent", Mod_ShowEnt_f, "Allows you to quickly search through a map's entities.");
Cmd_AddCommand("version_modelformats", Mod_PrintFormats_f); Cmd_AddCommand("version_modelformats", Mod_PrintFormats_f);

View file

@ -1659,6 +1659,7 @@ static qboolean Shader_LoadPermutations(char *name, program_t *prog, char *scrip
prog->preshade = Z_StrDup(prescript); prog->preshade = Z_StrDup(prescript);
prog->supportedpermutations = (~nopermutation) & (PERMUTATIONS-1); prog->supportedpermutations = (~nopermutation) & (PERMUTATIONS-1);
prog->shaderver = ver;
if (cvarcount) if (cvarcount)
{ {
@ -1954,7 +1955,8 @@ struct shader_field_names_s shader_unif_names[] =
{"m_modelview", SP_M_MODELVIEW},//the combined modelview matrix {"m_modelview", SP_M_MODELVIEW},//the combined modelview matrix
{"m_projection", SP_M_PROJECTION},//projection matrix {"m_projection", SP_M_PROJECTION},//projection matrix
/**/{"m_modelviewprojection", SP_M_MODELVIEWPROJECTION},//fancy mvp matrix. probably has degraded precision. /**/{"m_modelviewprojection", SP_M_MODELVIEWPROJECTION},//fancy mvp matrix. probably has degraded precision.
{"m_bones", SP_M_ENTBONES}, //bone matrix array. should normally be read via sys/skeletal.h {"m_bones_packed", SP_M_ENTBONES_PACKED}, //bone matrix array. should normally be read via sys/skeletal.h
{"m_bones_mat3x4", SP_M_ENTBONES_MAT3X4}, //bone matrix array. should normally be read via sys/skeletal.h
{"m_invviewprojection", SP_M_INVVIEWPROJECTION},//inverted vp matrix {"m_invviewprojection", SP_M_INVVIEWPROJECTION},//inverted vp matrix
{"m_invmodelviewprojection",SP_M_INVMODELVIEWPROJECTION},//inverted mvp matrix. {"m_invmodelviewprojection",SP_M_INVMODELVIEWPROJECTION},//inverted mvp matrix.
/**///m_modelinv /**///m_modelinv
@ -4966,9 +4968,9 @@ done:;
} }
} }
pass = s->passes; for (i = 0; i < s->numpasses; i += (pass->prog?pass->numMergedPasses:1))
for (i = 0; i < s->numpasses; i++, pass++)
{ {
pass = s->passes+i;
if (!(pass->shaderbits & (SBITS_BLEND_BITS|SBITS_MASK_BITS))) if (!(pass->shaderbits & (SBITS_BLEND_BITS|SBITS_MASK_BITS)))
{ {
break; break;

View file

@ -1133,6 +1133,7 @@ void GL_CheckExtensions (void *(*getglfunction) (char *name))
gl_config.arb_depth_texture = GL_CheckExtension("GL_ARB_depth_texture"); gl_config.arb_depth_texture = GL_CheckExtension("GL_ARB_depth_texture");
} }
gl_config.arb_shadow = GL_CheckExtension("GL_ARB_shadow"); gl_config.arb_shadow = GL_CheckExtension("GL_ARB_shadow");
gl_config.arb_shadow |= gl_config.glversion >= 3.0; //seems about right, for both gles and desktop...
//gl_config.arb_shadow |= GL_CheckExtension("GL_EXT_shadow_samplers"); //gles2. nvidia fucks up. depend on brute-force. :s //gl_config.arb_shadow |= GL_CheckExtension("GL_EXT_shadow_samplers"); //gles2. nvidia fucks up. depend on brute-force. :s
if (GL_CheckExtension("GL_ARB_seamless_cube_map")) if (GL_CheckExtension("GL_ARB_seamless_cube_map"))
@ -1325,13 +1326,7 @@ static const char *glsl_hdrs[] =
"attribute vec4 v_colour4;" "attribute vec4 v_colour4;"
#endif #endif
"\n#endif\n" "\n#endif\n"
#ifdef SHADOWDBG_COLOURNOTDEPTH
"#define sampler2DShadow sampler2D\n"
#else
"#ifndef USE_ARB_SHADOW\n" //fall back on regular samplers if we must
"#define sampler2DShadow sampler2D\n"
"#endif\n"
#endif
"#ifndef SPECEXP\n" "#ifndef SPECEXP\n"
"#define SPECEXP 1.0\n" "#define SPECEXP 1.0\n"
"#endif\n" "#endif\n"
@ -1420,9 +1415,9 @@ static const char *glsl_hdrs[] =
"layout(std140) unform u_bones\n" "layout(std140) unform u_bones\n"
"{\n" "{\n"
"#ifdef PACKEDBONES\n" "#ifdef PACKEDBONES\n"
"vec4 m_bones[3*MAX_GPU_BONES];\n" "vec4 m_bones_packed[3*MAX_GPU_BONES];\n"
"#else\n" "#else\n"
"mat3x4 m_bones[MAX_GPU_BONES]\n" "mat3x4 m_bones_mat3x4[MAX_GPU_BONES]\n"
"#endif\n" "#endif\n"
"};\n" "};\n"
"#endif\n" "#endif\n"
@ -1436,9 +1431,9 @@ static const char *glsl_hdrs[] =
"#endif\n" "#endif\n"
"#ifdef SKELETAL\n" //skeletal permutation tends to require glsl 120 "#ifdef SKELETAL\n" //skeletal permutation tends to require glsl 120
"#ifdef PACKEDBONES\n" "#ifdef PACKEDBONES\n"
"uniform vec4 m_bones[3*MAX_GPU_BONES];\n" "uniform vec4 m_bones_packed[3*MAX_GPU_BONES];\n"
"#else\n" "#else\n"
"uniform mat3x4 m_bones[MAX_GPU_BONES];\n" "uniform mat3x4 m_bones_mat3x4[MAX_GPU_BONES];\n"
"#endif\n" "#endif\n"
"#endif\n" "#endif\n"
"uniform mat4 m_invviewprojection;" "uniform mat4 m_invviewprojection;"
@ -1497,9 +1492,9 @@ static const char *glsl_hdrs[] =
"attribute vec4 v_bone;" "attribute vec4 v_bone;"
"attribute vec4 v_weight;\n" "attribute vec4 v_weight;\n"
"#ifdef PACKEDBONES\n" "#ifdef PACKEDBONES\n"
"uniform vec4 m_bones[3*MAX_GPU_BONES];\n" "uniform vec4 m_bones_packed[3*MAX_GPU_BONES];\n"
"#else\n" "#else\n"
"uniform mat3x4 m_bones[MAX_GPU_BONES];\n" "uniform mat3x4 m_bones_mat3x4[MAX_GPU_BONES];\n"
"#endif\n" "#endif\n"
"#endif\n" "#endif\n"
@ -1507,36 +1502,36 @@ static const char *glsl_hdrs[] =
"vec4 skeletaltransform()" "vec4 skeletaltransform()"
"{" "{"
"mat4 wmat;" "mat4 wmat;"
"wmat[0] = m_bones[0+3*int(v_bone.x)] * v_weight.x;" "wmat[0] = m_bones_packed[0+3*int(v_bone.x)] * v_weight.x;"
"wmat[0] += m_bones[0+3*int(v_bone.y)] * v_weight.y;" "wmat[0] += m_bones_packed[0+3*int(v_bone.y)] * v_weight.y;"
"wmat[0] += m_bones[0+3*int(v_bone.z)] * v_weight.z;" "wmat[0] += m_bones_packed[0+3*int(v_bone.z)] * v_weight.z;"
"wmat[0] += m_bones[0+3*int(v_bone.w)] * v_weight.w;" "wmat[0] += m_bones_packed[0+3*int(v_bone.w)] * v_weight.w;"
"wmat[1] = m_bones[1+3*int(v_bone.x)] * v_weight.x;" "wmat[1] = m_bones_packed[1+3*int(v_bone.x)] * v_weight.x;"
"wmat[1] += m_bones[1+3*int(v_bone.y)] * v_weight.y;" "wmat[1] += m_bones_packed[1+3*int(v_bone.y)] * v_weight.y;"
"wmat[1] += m_bones[1+3*int(v_bone.z)] * v_weight.z;" "wmat[1] += m_bones_packed[1+3*int(v_bone.z)] * v_weight.z;"
"wmat[1] += m_bones[1+3*int(v_bone.w)] * v_weight.w;" "wmat[1] += m_bones_packed[1+3*int(v_bone.w)] * v_weight.w;"
"wmat[2] = m_bones[2+3*int(v_bone.x)] * v_weight.x;" "wmat[2] = m_bones_packed[2+3*int(v_bone.x)] * v_weight.x;"
"wmat[2] += m_bones[2+3*int(v_bone.y)] * v_weight.y;" "wmat[2] += m_bones_packed[2+3*int(v_bone.y)] * v_weight.y;"
"wmat[2] += m_bones[2+3*int(v_bone.z)] * v_weight.z;" "wmat[2] += m_bones_packed[2+3*int(v_bone.z)] * v_weight.z;"
"wmat[2] += m_bones[2+3*int(v_bone.w)] * v_weight.w;" "wmat[2] += m_bones_packed[2+3*int(v_bone.w)] * v_weight.w;"
"wmat[3] = vec4(0.0,0.0,0.0,1.0);\n" "wmat[3] = vec4(0.0,0.0,0.0,1.0);\n"
"return m_modelviewprojection * (vec4(v_position.xyz, 1.0) * wmat);" "return m_modelviewprojection * (vec4(v_position.xyz, 1.0) * wmat);"
"}\n" "}\n"
"vec4 skeletaltransform_nst(out vec3 n, out vec3 t, out vec3 b)" "vec4 skeletaltransform_nst(out vec3 n, out vec3 t, out vec3 b)"
"{" "{"
"mat4 wmat;" "mat4 wmat;"
"wmat[0] = m_bones[0+3*int(v_bone.x)] * v_weight.x;" "wmat[0] = m_bones_packed[0+3*int(v_bone.x)] * v_weight.x;"
"wmat[0] += m_bones[0+3*int(v_bone.y)] * v_weight.y;" "wmat[0] += m_bones_packed[0+3*int(v_bone.y)] * v_weight.y;"
"wmat[0] += m_bones[0+3*int(v_bone.z)] * v_weight.z;" "wmat[0] += m_bones_packed[0+3*int(v_bone.z)] * v_weight.z;"
"wmat[0] += m_bones[0+3*int(v_bone.w)] * v_weight.w;" "wmat[0] += m_bones_packed[0+3*int(v_bone.w)] * v_weight.w;"
"wmat[1] = m_bones[1+3*int(v_bone.x)] * v_weight.x;" "wmat[1] = m_bones_packed[1+3*int(v_bone.x)] * v_weight.x;"
"wmat[1] += m_bones[1+3*int(v_bone.y)] * v_weight.y;" "wmat[1] += m_bones_packed[1+3*int(v_bone.y)] * v_weight.y;"
"wmat[1] += m_bones[1+3*int(v_bone.z)] * v_weight.z;" "wmat[1] += m_bones_packed[1+3*int(v_bone.z)] * v_weight.z;"
"wmat[1] += m_bones[1+3*int(v_bone.w)] * v_weight.w;" "wmat[1] += m_bones_packed[1+3*int(v_bone.w)] * v_weight.w;"
"wmat[2] = m_bones[2+3*int(v_bone.x)] * v_weight.x;" "wmat[2] = m_bones_packed[2+3*int(v_bone.x)] * v_weight.x;"
"wmat[2] += m_bones[2+3*int(v_bone.y)] * v_weight.y;" "wmat[2] += m_bones_packed[2+3*int(v_bone.y)] * v_weight.y;"
"wmat[2] += m_bones[2+3*int(v_bone.z)] * v_weight.z;" "wmat[2] += m_bones_packed[2+3*int(v_bone.z)] * v_weight.z;"
"wmat[2] += m_bones[2+3*int(v_bone.w)] * v_weight.w;" "wmat[2] += m_bones_packed[2+3*int(v_bone.w)] * v_weight.w;"
"wmat[3] = vec4(0.0,0.0,0.0,1.0);" "wmat[3] = vec4(0.0,0.0,0.0,1.0);"
"n = (vec4(v_normal.xyz, 0.0) * wmat).xyz;" "n = (vec4(v_normal.xyz, 0.0) * wmat).xyz;"
"t = (vec4(v_svector.xyz, 0.0) * wmat).xyz;" "t = (vec4(v_svector.xyz, 0.0) * wmat).xyz;"
@ -1546,18 +1541,18 @@ static const char *glsl_hdrs[] =
"vec4 skeletaltransform_wnst(out vec3 w, out vec3 n, out vec3 t, out vec3 b)" "vec4 skeletaltransform_wnst(out vec3 w, out vec3 n, out vec3 t, out vec3 b)"
"{" "{"
"mat4 wmat;" "mat4 wmat;"
"wmat[0] = m_bones[0+3*int(v_bone.x)] * v_weight.x;" "wmat[0] = m_bones_packed[0+3*int(v_bone.x)] * v_weight.x;"
"wmat[0] += m_bones[0+3*int(v_bone.y)] * v_weight.y;" "wmat[0] += m_bones_packed[0+3*int(v_bone.y)] * v_weight.y;"
"wmat[0] += m_bones[0+3*int(v_bone.z)] * v_weight.z;" "wmat[0] += m_bones_packed[0+3*int(v_bone.z)] * v_weight.z;"
"wmat[0] += m_bones[0+3*int(v_bone.w)] * v_weight.w;" "wmat[0] += m_bones_packed[0+3*int(v_bone.w)] * v_weight.w;"
"wmat[1] = m_bones[1+3*int(v_bone.x)] * v_weight.x;" "wmat[1] = m_bones_packed[1+3*int(v_bone.x)] * v_weight.x;"
"wmat[1] += m_bones[1+3*int(v_bone.y)] * v_weight.y;" "wmat[1] += m_bones_packed[1+3*int(v_bone.y)] * v_weight.y;"
"wmat[1] += m_bones[1+3*int(v_bone.z)] * v_weight.z;" "wmat[1] += m_bones_packed[1+3*int(v_bone.z)] * v_weight.z;"
"wmat[1] += m_bones[1+3*int(v_bone.w)] * v_weight.w;" "wmat[1] += m_bones_packed[1+3*int(v_bone.w)] * v_weight.w;"
"wmat[2] = m_bones[2+3*int(v_bone.x)] * v_weight.x;" "wmat[2] = m_bones_packed[2+3*int(v_bone.x)] * v_weight.x;"
"wmat[2] += m_bones[2+3*int(v_bone.y)] * v_weight.y;" "wmat[2] += m_bones_packed[2+3*int(v_bone.y)] * v_weight.y;"
"wmat[2] += m_bones[2+3*int(v_bone.z)] * v_weight.z;" "wmat[2] += m_bones_packed[2+3*int(v_bone.z)] * v_weight.z;"
"wmat[2] += m_bones[2+3*int(v_bone.w)] * v_weight.w;" "wmat[2] += m_bones_packed[2+3*int(v_bone.w)] * v_weight.w;"
"wmat[3] = vec4(0.0,0.0,0.0,1.0);" "wmat[3] = vec4(0.0,0.0,0.0,1.0);"
"n = (vec4(v_normal.xyz, 0.0) * wmat).xyz;" "n = (vec4(v_normal.xyz, 0.0) * wmat).xyz;"
"t = (vec4(v_svector.xyz, 0.0) * wmat).xyz;" "t = (vec4(v_svector.xyz, 0.0) * wmat).xyz;"
@ -1568,18 +1563,18 @@ static const char *glsl_hdrs[] =
"vec4 skeletaltransform_n(out vec3 n)" "vec4 skeletaltransform_n(out vec3 n)"
"{" "{"
"mat4 wmat;" "mat4 wmat;"
"wmat[0] = m_bones[0+3*int(v_bone.x)] * v_weight.x;" "wmat[0] = m_bones_packed[0+3*int(v_bone.x)] * v_weight.x;"
"wmat[0] += m_bones[0+3*int(v_bone.y)] * v_weight.y;" "wmat[0] += m_bones_packed[0+3*int(v_bone.y)] * v_weight.y;"
"wmat[0] += m_bones[0+3*int(v_bone.z)] * v_weight.z;" "wmat[0] += m_bones_packed[0+3*int(v_bone.z)] * v_weight.z;"
"wmat[0] += m_bones[0+3*int(v_bone.w)] * v_weight.w;" "wmat[0] += m_bones_packed[0+3*int(v_bone.w)] * v_weight.w;"
"wmat[1] = m_bones[1+3*int(v_bone.x)] * v_weight.x;" "wmat[1] = m_bones_packed[1+3*int(v_bone.x)] * v_weight.x;"
"wmat[1] += m_bones[1+3*int(v_bone.y)] * v_weight.y;" "wmat[1] += m_bones_packed[1+3*int(v_bone.y)] * v_weight.y;"
"wmat[1] += m_bones[1+3*int(v_bone.z)] * v_weight.z;" "wmat[1] += m_bones_packed[1+3*int(v_bone.z)] * v_weight.z;"
"wmat[1] += m_bones[1+3*int(v_bone.w)] * v_weight.w;" "wmat[1] += m_bones_packed[1+3*int(v_bone.w)] * v_weight.w;"
"wmat[2] = m_bones[2+3*int(v_bone.x)] * v_weight.x;" "wmat[2] = m_bones_packed[2+3*int(v_bone.x)] * v_weight.x;"
"wmat[2] += m_bones[2+3*int(v_bone.y)] * v_weight.y;" "wmat[2] += m_bones_packed[2+3*int(v_bone.y)] * v_weight.y;"
"wmat[2] += m_bones[2+3*int(v_bone.z)] * v_weight.z;" "wmat[2] += m_bones_packed[2+3*int(v_bone.z)] * v_weight.z;"
"wmat[2] += m_bones[2+3*int(v_bone.w)] * v_weight.w;" "wmat[2] += m_bones_packed[2+3*int(v_bone.w)] * v_weight.w;"
"wmat[3] = vec4(0.0,0.0,0.0,1.0);" "wmat[3] = vec4(0.0,0.0,0.0,1.0);"
"n = (vec4(v_normal.xyz, 0.0) * wmat).xyz;" "n = (vec4(v_normal.xyz, 0.0) * wmat).xyz;"
"return m_modelviewprojection * (vec4(v_position.xyz, 1.0) * wmat);" "return m_modelviewprojection * (vec4(v_position.xyz, 1.0) * wmat);"
@ -1588,19 +1583,19 @@ static const char *glsl_hdrs[] =
"vec4 skeletaltransform()" "vec4 skeletaltransform()"
"{" "{"
"mat3x4 wmat;" "mat3x4 wmat;"
"wmat = m_bones[int(v_bone.x)] * v_weight.x;" "wmat = m_bones_mat3x4[int(v_bone.x)] * v_weight.x;"
"wmat += m_bones[int(v_bone.y)] * v_weight.y;" "wmat += m_bones_mat3x4[int(v_bone.y)] * v_weight.y;"
"wmat += m_bones[int(v_bone.z)] * v_weight.z;" "wmat += m_bones_mat3x4[int(v_bone.z)] * v_weight.z;"
"wmat += m_bones[int(v_bone.w)] * v_weight.w;" "wmat += m_bones_mat3x4[int(v_bone.w)] * v_weight.w;"
"return m_modelviewprojection * vec4(vec4(v_position.xyz, 1.0) * wmat, 1.0);" "return m_modelviewprojection * vec4(vec4(v_position.xyz, 1.0) * wmat, 1.0);"
"}\n" "}\n"
"vec4 skeletaltransform_nst(out vec3 n, out vec3 t, out vec3 b)" "vec4 skeletaltransform_nst(out vec3 n, out vec3 t, out vec3 b)"
"{" "{"
"mat3x4 wmat;" "mat3x4 wmat;"
"wmat = m_bones[int(v_bone.x)] * v_weight.x;" "wmat = m_bones_mat3x4[int(v_bone.x)] * v_weight.x;"
"wmat += m_bones[int(v_bone.y)] * v_weight.y;" "wmat += m_bones_mat3x4[int(v_bone.y)] * v_weight.y;"
"wmat += m_bones[int(v_bone.z)] * v_weight.z;" "wmat += m_bones_mat3x4[int(v_bone.z)] * v_weight.z;"
"wmat += m_bones[int(v_bone.w)] * v_weight.w;" "wmat += m_bones_mat3x4[int(v_bone.w)] * v_weight.w;"
"n = vec4(v_normal.xyz, 0.0) * wmat;" "n = vec4(v_normal.xyz, 0.0) * wmat;"
"t = vec4(v_svector.xyz, 0.0) * wmat;" "t = vec4(v_svector.xyz, 0.0) * wmat;"
"b = vec4(v_tvector.xyz, 0.0) * wmat;" "b = vec4(v_tvector.xyz, 0.0) * wmat;"
@ -1609,10 +1604,10 @@ static const char *glsl_hdrs[] =
"vec4 skeletaltransform_wnst(out vec3 w, out vec3 n, out vec3 t, out vec3 b)" "vec4 skeletaltransform_wnst(out vec3 w, out vec3 n, out vec3 t, out vec3 b)"
"{" "{"
"mat3x4 wmat;" "mat3x4 wmat;"
"wmat = m_bones[int(v_bone.x)] * v_weight.x;" "wmat = m_bones_mat3x4[int(v_bone.x)] * v_weight.x;"
"wmat += m_bones[int(v_bone.y)] * v_weight.y;" "wmat += m_bones_mat3x4[int(v_bone.y)] * v_weight.y;"
"wmat += m_bones[int(v_bone.z)] * v_weight.z;" "wmat += m_bones_mat3x4[int(v_bone.z)] * v_weight.z;"
"wmat += m_bones[int(v_bone.w)] * v_weight.w;" "wmat += m_bones_mat3x4[int(v_bone.w)] * v_weight.w;"
"n = vec4(v_normal.xyz, 0.0) * wmat;" "n = vec4(v_normal.xyz, 0.0) * wmat;"
"t = vec4(v_svector.xyz, 0.0) * wmat;" "t = vec4(v_svector.xyz, 0.0) * wmat;"
"b = vec4(v_tvector.xyz, 0.0) * wmat;" "b = vec4(v_tvector.xyz, 0.0) * wmat;"
@ -1622,10 +1617,10 @@ static const char *glsl_hdrs[] =
"vec4 skeletaltransform_n(out vec3 n)" "vec4 skeletaltransform_n(out vec3 n)"
"{" "{"
"mat3x4 wmat;" "mat3x4 wmat;"
"wmat = m_bones[int(v_bone.x)] * v_weight.x;" "wmat = m_bones_mat3x4[int(v_bone.x)] * v_weight.x;"
"wmat += m_bones[int(v_bone.y)] * v_weight.y;" "wmat += m_bones_mat3x4[int(v_bone.y)] * v_weight.y;"
"wmat += m_bones[int(v_bone.z)] * v_weight.z;" "wmat += m_bones_mat3x4[int(v_bone.z)] * v_weight.z;"
"wmat += m_bones[int(v_bone.w)] * v_weight.w;" "wmat += m_bones_mat3x4[int(v_bone.w)] * v_weight.w;"
"n = vec4(v_normal.xyz, 0.0) * wmat;" "n = vec4(v_normal.xyz, 0.0) * wmat;"
"return m_modelviewprojection * vec4(vec4(v_position.xyz, 1.0) * wmat, 1.0);" "return m_modelviewprojection * vec4(vec4(v_position.xyz, 1.0) * wmat, 1.0);"
"}\n" "}\n"
@ -1748,9 +1743,9 @@ static const char *glsl_hdrs[] =
"vec2 tc = base;\n" "vec2 tc = base;\n"
"tc += OffsetVector;\n" "tc += OffsetVector;\n"
"OffsetVector *= 0.333;\n" "OffsetVector *= 0.333;\n"
"tc -= OffsetVector * texture2D(normtex, tc).w;\n" "tc -= OffsetVector * texture2D(normtex, tc).a;\n"
"tc -= OffsetVector * texture2D(normtex, tc).w;\n" "tc -= OffsetVector * texture2D(normtex, tc).a;\n"
"tc -= OffsetVector * texture2D(normtex, tc).w;\n" "tc -= OffsetVector * texture2D(normtex, tc).a;\n"
"return tc;\n" "return tc;\n"
"#else\n" "#else\n"
"return base;\n" "return base;\n"
@ -2071,6 +2066,8 @@ static GLhandleARB GLSlang_CreateShader (program_t *prog, const char *name, int
GLSlang_GenerateInternal(&glsl, *precompilerconstants++); GLSlang_GenerateInternal(&glsl, *precompilerconstants++);
GLSlang_GenerateInternal(&glsl, "#define ENGINE_"DISTRIBUTION"\n"); GLSlang_GenerateInternal(&glsl, "#define ENGINE_"DISTRIBUTION"\n");
if (ver < 120)
GLSlang_GenerateInternal(&glsl, "#define PACKEDBONES\n");
switch (shadertype) switch (shadertype)
{ {
@ -2126,7 +2123,15 @@ static GLhandleARB GLSlang_CreateShader (program_t *prog, const char *name, int
#if 1//def NOLEGACY #if 1//def NOLEGACY
const char *defaultsamplernames[] = const char *defaultsamplernames[] =
{ {
#ifdef SHADOWDBG_COLOURNOTDEPTH
"#define sampler2DShadow sampler2D\n"
#else
"#ifndef USE_ARB_SHADOW\n" //fall back on regular samplers if we must
"#define sampler2DShadow sampler2D\n"
"#endif\n"
#endif
"uniform sampler2DShadow s_shadowmap;\n", "uniform sampler2DShadow s_shadowmap;\n",
"uniform samplerCube s_projectionmap;\n", "uniform samplerCube s_projectionmap;\n",
"uniform sampler2D s_diffuse;\n", "uniform sampler2D s_diffuse;\n",
"uniform sampler2D s_normalmap;\n", "uniform sampler2D s_normalmap;\n",
@ -2201,8 +2206,6 @@ static GLhandleARB GLSlang_CreateShader (program_t *prog, const char *name, int
"#define varying out\n" "#define varying out\n"
); );
} }
else if (ver < 120)
GLSlang_GenerateInternal(&glsl, "#define PACKEDBONES\n");
if (gl_config_nofixedfunc) if (gl_config_nofixedfunc)
{ {
@ -2365,19 +2368,41 @@ static GLhandleARB GLSlang_FinishShader(GLhandleARB shader, const char *name, GL
if (developer.ival>1) if (developer.ival>1)
{ //could use echo console-link I guess (with embedded line numbers). shaders can get quite big though. { //could use echo console-link I guess (with embedded line numbers). shaders can get quite big though.
unsigned int line; unsigned int rawline, line, filenum = 0;
char *eol, *start; char *eol, *start, *e;
const char *filename = name;
qglGetShaderSource(shader, sizeof(str), NULL, str); qglGetShaderSource(shader, sizeof(str), NULL, str);
Con_Printf("Shader \"%s\" source:\n", name); Con_Printf("Shader \"%s\" source:\n", name);
for(start = str, line = 1; ;line++) for(start = str, line = 1, rawline = 1; ;)
{ {
eol = strchr(start, '\n'); eol = strchr(start, '\n');
if (eol) if (eol)
*eol=0; *eol=0;
Con_Printf("%3u: %s\n", line, start); // if (filename)
// Con_Printf("%s:%u:%u: %s\n", filename, line, rawline, start);
// else
Con_Printf("%u:%u:%u: %s\n", filenum, line, rawline, start);
if (!strncmp(start, "#line ", 6))
{
line = strtoul(start+6, &e, 0);
while(*e == ' ')
e++;
if (*e)
{
filenum = strtoul(e, &e, 0);
while(*e == ' ')
e++;
filename = NULL;
if (e[0]=='/'&&e[1]=='/')
filename = e+2;
}
}
else
line++;
if (!eol) if (!eol)
break; break;
start = eol+1; start = eol+1;
rawline++;
} }
} }
} }
@ -2589,11 +2614,7 @@ qboolean GLSlang_CreateProgramPermu(program_t *prog, struct programpermu_s *perm
if (gl_config.gles) if (gl_config.gles)
ver = 100; ver = 100;
else else
{
ver = 110; ver = 110;
if (sh_config.maxver>=120 && (permu->permutation & PERMUTATION_SKELETAL))
ver = 120;
}
} }
if ((permu->permutation & PERMUTATION_SKELETAL) && gl_config.maxattribs < 10) if ((permu->permutation & PERMUTATION_SKELETAL) && gl_config.maxattribs < 10)
return false; //can happen in gles2 return false; //can happen in gles2

View file

@ -1327,10 +1327,344 @@ static void GLX_CloseLibrary(void)
} }
*/ */
#if 0//def _DEBUG
//this is a list of the functions that exist in opengles2, as well as wglCreateContextAttribsARB.
//functions not in this list *should* be stubs that just return errors, but we can't always depend on drivers for that... they shouldn't get called.
//this list is just to make it easier to test+debug android gles2 stuff using windows.
static char *gles2funcs[] =
{
#define f(n) #n,
f(glActiveTexture)
f(glAttachShader)
f(glBindAttribLocation)
f(glBindBuffer)
f(glBindFramebuffer)
f(glBindRenderbuffer)
f(glBindTexture)
f(glBlendColor)
f(glBlendEquation)
f(glBlendEquationSeparate)
f(glBlendFunc)
f(glBlendFuncSeparate)
f(glBufferData)
f(glBufferSubData)
f(glCheckFramebufferStatus)
f(glClear)
f(glClearColor)
f(glClearDepthf)
f(glClearStencil)
f(glColorMask)
f(glCompileShader)
f(glCompressedTexImage2D)
f(glCompressedTexSubImage2D)
f(glCopyTexImage2D)
f(glCopyTexSubImage2D)
f(glCreateProgram)
f(glCreateShader)
f(glCullFace)
f(glDeleteBuffers)
f(glDeleteFramebuffers)
f(glDeleteProgram)
f(glDeleteRenderbuffers)
f(glDeleteShader)
f(glDeleteTextures)
f(glDepthFunc)
f(glDepthMask)
f(glDepthRangef)
f(glDetachShader)
f(glDisable)
f(glDisableVertexAttribArray)
f(glDrawArrays)
f(glDrawElements)
f(glEnable)
f(glEnableVertexAttribArray)
f(glFinish)
f(glFlush)
f(glFramebufferRenderbuffer)
f(glFramebufferTexture2D)
f(glFrontFace)
f(glGenBuffers)
f(glGenerateMipmap)
f(glGenFramebuffers)
f(glGenRenderbuffers)
f(glGenTextures)
f(glGetActiveAttrib)
f(glGetActiveUniform)
f(glGetAttachedShaders)
f(glGetAttribLocation)
f(glGetBooleanv)
f(glGetBufferParameteriv)
f(glGetError)
f(glGetFloatv)
f(glGetFramebufferAttachmentParameteriv)
f(glGetIntegerv)
f(glGetProgramiv)
f(glGetProgramInfoLog)
f(glGetRenderbufferParameteriv)
f(glGetShaderiv)
f(glGetShaderInfoLog)
f(glGetShaderPrecisionFormat)
f(glGetShaderSource)
f(glGetString)
f(glGetTexParameterfv)
f(glGetTexParameteriv)
f(glGetUniformfv)
f(glGetUniformiv)
f(glGetUniformLocation)
f(glGetVertexAttribfv)
f(glGetVertexAttribiv)
f(glGetVertexAttribPointerv)
f(glHint)
f(glIsBuffer)
f(glIsEnabled)
f(glIsFramebuffer)
f(glIsProgram)
f(glIsRenderbuffer)
f(glIsShader)
f(glIsTexture)
f(glLineWidth)
f(glLinkProgram)
f(glPixelStorei)
f(glPolygonOffset)
f(glReadPixels)
f(glReleaseShaderCompiler)
f(glRenderbufferStorage)
f(glSampleCoverage)
f(glScissor)
f(glShaderBinary)
f(glShaderSource)
f(glStencilFunc)
f(glStencilFuncSeparate)
f(glStencilMask)
f(glStencilMaskSeparate)
f(glStencilOp)
f(glStencilOpSeparate)
f(glTexImage2D)
f(glTexParameterf)
f(glTexParameterfv)
f(glTexParameteri)
f(glTexParameteriv)
f(glTexSubImage2D)
f(glUniform1f)
f(glUniform1fv)
f(glUniform1i)
f(glUniform1iv)
f(glUniform2f)
f(glUniform2fv)
f(glUniform2i)
f(glUniform2iv)
f(glUniform3f)
f(glUniform3fv)
f(glUniform3i)
f(glUniform3iv)
f(glUniform4f)
f(glUniform4fv)
f(glUniform4i)
f(glUniform4iv)
f(glUniformMatrix2fv)
f(glUniformMatrix3fv)
f(glUniformMatrix4fv)
f(glUseProgram)
f(glValidateProgram)
f(glVertexAttrib1f)
f(glVertexAttrib1fv)
f(glVertexAttrib2f)
f(glVertexAttrib2fv)
f(glVertexAttrib3f)
f(glVertexAttrib3fv)
f(glVertexAttrib4f)
f(glVertexAttrib4fv)
f(glVertexAttribPointer)
f(glViewport)
f(wglCreateContextAttribsARB)
NULL
};
//this is a list of the functions that exist in opengles2, as well as wglCreateContextAttribsARB.
//functions not in this list *should* be stubs that just return errors, but we can't always depend on drivers for that... they shouldn't get called.
//this list is just to make it easier to test+debug android gles2 stuff using windows.
static char *gles1funcs[] =
{
#define f(n) #n,
/* Available only in Common profile */
f(glAlphaFunc)
f(glClearColor)
f(glClearDepthf)
f(glClipPlanef)
f(glColor4f)
f(glDepthRangef)
f(glFogf)
f(glFogfv)
f(glFrustumf)
f(glGetClipPlanef)
f(glGetFloatv)
f(glGetLightfv)
f(glGetMaterialfv)
f(glGetTexEnvfv)
f(glGetTexParameterfv)
f(glLightModelf)
f(glLightModelfv)
f(glLightf)
f(glLightfv)
f(glLineWidth)
f(glLoadMatrixf)
f(glMaterialf)
f(glMaterialfv)
f(glMultMatrixf)
f(glMultiTexCoord4f)
f(glNormal3f)
f(glOrthof)
f(glPointParameterf)
f(glPointParameterfv)
f(glPointSize)
f(glPolygonOffset)
f(glRotatef)
f(glScalef)
f(glTexEnvf)
f(glTexEnvfv)
f(glTexParameterf)
f(glTexParameterfv)
f(glTranslatef)
/* Available in both Common and Common-Lite profiles */
f(glActiveTexture)
f(glAlphaFuncx)
f(glBindBuffer)
f(glBindTexture)
f(glBlendFunc)
f(glBufferData)
f(glBufferSubData)
f(glClear)
f(glClearColorx)
f(glClearDepthx)
f(glClearStencil)
f(glClientActiveTexture)
f(glClipPlanex)
f(glColor4ub)
f(glColor4x)
f(glColorMask)
f(glColorPointer)
f(glCompressedTexImage2D)
f(glCompressedTexSubImage2D)
f(glCopyTexImage2D)
f(glCopyTexSubImage2D)
f(glCullFace)
f(glDeleteBuffers)
f(glDeleteTextures)
f(glDepthFunc)
f(glDepthMask)
f(glDepthRangex)
f(glDisable)
f(glDisableClientState)
f(glDrawArrays)
f(glDrawElements)
f(glEnable)
f(glEnableClientState)
f(glFinish)
f(glFlush)
f(glFogx)
f(glFogxv)
f(glFrontFace)
f(glFrustumx)
f(glGetBooleanv)
f(glGetBufferParameteriv)
f(glGetClipPlanex)
f(glGenBuffers)
f(glGenTextures)
f(glGetError)
f(glGetFixedv)
f(glGetIntegerv)
f(glGetLightxv)
f(glGetMaterialxv)
f(glGetPointerv)
f(glGetString)
f(glGetTexEnviv)
f(glGetTexEnvxv)
f(glGetTexParameteriv)
f(glGetTexParameterxv)
f(glHint)
f(glIsBuffer)
f(glIsEnabled)
f(glIsTexture)
f(glLightModelx)
f(glLightModelxv)
f(glLightx)
f(glLightxv)
f(glLineWidthx)
f(glLoadIdentity)
f(glLoadMatrixx)
f(glLogicOp)
f(glMaterialx)
f(glMaterialxv)
f(glMatrixMode)
f(glMultMatrixx)
f(glMultiTexCoord4x)
f(glNormal3x)
f(glNormalPointer)
f(glOrthox)
f(glPixelStorei)
f(glPointParameterx)
f(glPointParameterxv)
f(glPointSizex)
f(glPolygonOffsetx)
f(glPopMatrix)
f(glPushMatrix)
f(glReadPixels)
f(glRotatex)
f(glSampleCoverage)
f(glSampleCoveragex)
f(glScalex)
f(glScissor)
f(glShadeModel)
f(glStencilFunc)
f(glStencilMask)
f(glStencilOp)
f(glTexCoordPointer)
f(glTexEnvi)
f(glTexEnvx)
f(glTexEnviv)
f(glTexEnvxv)
f(glTexImage2D)
f(glTexParameteri)
f(glTexParameterx)
f(glTexParameteriv)
f(glTexParameterxv)
f(glTexSubImage2D)
f(glTranslatex)
f(glVertexPointer)
f(glViewport)
/*required to switch stuff around*/
f(wglCreateContextAttribsARB)
f(glXGetProcAddress)
f(glXQueryExtensionsString)
f(glXChooseFBConfig)
f(glXGetFBConfigAttrib)
f(glXGetVisualFromFBConfig)
f(glXCreateContextAttribsARB)
NULL
};
#endif
static void *GLX_GetSymbol(char *name) static void *GLX_GetSymbol(char *name)
{ {
void *symb; void *symb;
#if 0//def _DEBUG
if (1)
{
int i;
for (i = 0; gles1funcs[i]; i++)
{
if (!strcmp(name, gles1funcs[i]))
break;
}
if (!gles1funcs[i])
return NULL; //not in the list
}
#endif
if (glx.GetProcAddress) if (glx.GetProcAddress)
symb = glx.GetProcAddress(name); symb = glx.GetProcAddress(name);
else else

View file

@ -437,7 +437,8 @@ typedef struct {
SP_W_FOG, SP_W_FOG,
SP_W_USER, //user-specified blob of data. SP_W_USER, //user-specified blob of data.
SP_M_ENTBONES, SP_M_ENTBONES_PACKED,
SP_M_ENTBONES_MAT3X4,
SP_M_VIEW, SP_M_VIEW,
SP_M_MODEL, SP_M_MODEL,
SP_M_MODELVIEW, SP_M_MODELVIEW,

View file

@ -1,5 +1,6 @@
//simple tool to read the particle configs and generate a header file for inclusion in the engine. //simple tool to read the particle configs and generate a header file for inclusion in the engine.
#include <stdio.h> #include <stdio.h>
#include <stdlib.h>
#include <string.h> #include <string.h>
struct struct
@ -30,7 +31,7 @@ int main(void)
if (!c || !h) if (!c || !h)
{ {
printf("unable to open a file\n"); printf("unable to open a file\n");
return; return EXIT_FAILURE;
} }
fprintf(h, "/*\nWARNING: THIS FILE IS GENERATED BY '"__FILE__"'.\nYOU SHOULD NOT EDIT THIS FILE BY HAND\n*/\n\n"); fprintf(h, "/*\nWARNING: THIS FILE IS GENERATED BY '"__FILE__"'.\nYOU SHOULD NOT EDIT THIS FILE BY HAND\n*/\n\n");
@ -46,7 +47,7 @@ int main(void)
if (!s) if (!s)
{ {
printf("unable to open %s\n", effects[i].filename); printf("unable to open %s\n", effects[i].filename);
return; return EXIT_FAILURE;
} }
*strchr(effects[i].filename, '.') = 0; *strchr(effects[i].filename, '.') = 0;
@ -114,4 +115,6 @@ int main(void)
fclose(h); fclose(h);
fclose(c); fclose(c);
return EXIT_SUCCESS;
} }

View file

@ -412,6 +412,7 @@ r_part te_teleport
surfaceparm nodlight surfaceparm nodlight
glslprogram glslprogram
{ {
!!samps screen=0
varying vec2 tcoord; varying vec2 tcoord;
varying vec4 scoord; varying vec4 scoord;
varying float alph; varying float alph;
@ -439,7 +440,7 @@ r_part te_teleport
// f = 1.0 - tcoord*tcoord; // f = 1.0 - tcoord*tcoord;
if (f < 0.0) discard; if (f < 0.0) discard;
f *= alph; f *= alph;
gl_FragColor = texture2D(s_t0, nst - tcoord*f); gl_FragColor = texture2D(s_screen, nst - tcoord*f);
} }
#endif #endif
} }

View file

@ -348,6 +348,21 @@ void Hash_RemoveBucket(hashtable_t *table, const char *name, bucket_t *data)
return; return;
} }
void Hash_RemoveDataKey(hashtable_t *table, unsigned int key, void *data)
{
unsigned int bucknum = key%table->numbuckets;
bucket_t **link, *buck;
for (link = &table->bucket[bucknum]; *link; link = &(*link)->next)
{
buck = *link;
if (buck->data == data && buck->key.value == key)
{
*link = buck->next;
return;
}
}
}
void Hash_RemoveKey(hashtable_t *table, unsigned int key) void Hash_RemoveKey(hashtable_t *table, unsigned int key)
{ {
unsigned int bucknum = key%table->numbuckets; unsigned int bucknum = key%table->numbuckets;

View file

@ -39,6 +39,7 @@ void Hash_RemoveData(hashtable_t *table, const char *name, void *data);
void Hash_RemoveDataInsensitive(hashtable_t *table, const char *name, void *data); void Hash_RemoveDataInsensitive(hashtable_t *table, const char *name, void *data);
void Hash_RemoveBucket(hashtable_t *table, const char *name, bucket_t *data); void Hash_RemoveBucket(hashtable_t *table, const char *name, bucket_t *data);
void Hash_RemoveKey(hashtable_t *table, unsigned int key); void Hash_RemoveKey(hashtable_t *table, unsigned int key);
void Hash_RemoveDataKey(hashtable_t *table, unsigned int key, void *data);
void *Hash_AddKey(hashtable_t *table, unsigned int key, void *data, bucket_t *buck); void *Hash_AddKey(hashtable_t *table, unsigned int key, void *data, bucket_t *buck);
#endif #endif

View file

@ -10116,7 +10116,7 @@ static void QCBUILTIN PF_SendPacket(pubprogfuncs_t *prinst, struct globalvars_s
char *send = Z_Malloc(4+strlen(contents)); char *send = Z_Malloc(4+strlen(contents));
send[0] = send[1] = send[2] = send[3] = 0xff; send[0] = send[1] = send[2] = send[3] = 0xff;
memcpy(send+4, contents, strlen(contents)); memcpy(send+4, contents, strlen(contents));
G_FLOAT(OFS_RETURN) = NET_SendPacket(NS_SERVER, 4+strlen(contents), send, &to); G_FLOAT(OFS_RETURN) = NET_SendPacket(svs.sockets, 4+strlen(contents), send, &to);
Z_Free(send); Z_Free(send);
} }
} }

View file

@ -334,7 +334,7 @@ typedef struct
// received from client // received from client
// reply // reply
double senttime; //time we sent this frame to the client, for ping calcs double senttime; //time we sent this frame to the client, for ping calcs (realtime)
int sequence; //the outgoing sequence - without mask, meaning we know if its current or stale int sequence; //the outgoing sequence - without mask, meaning we know if its current or stale
float ping_time; //how long it took for the client to ack it, may be negative float ping_time; //how long it took for the client to ack it, may be negative
float move_msecs; // float move_msecs; //
@ -365,8 +365,9 @@ typedef struct
float pmwaterjumptime; float pmwaterjumptime;
usercmd_t cmd; usercmd_t cmd;
//these are old positions of players, to give more accurate victim positions //these are old positions of players, to give more accurate victim positions
vec3_t playerpositions[MAX_CLIENTS]; //where each player was in this frame, for antilag laggedentinfo_t laggedplayer[MAX_CLIENTS];
qboolean playerpresent[MAX_CLIENTS]; //whether the player was actually present unsigned int numlaggedplayers;
float laggedtime; //sv.time of when this frame was sent
} client_frame_t; } client_frame_t;
#ifdef Q2SERVER #ifdef Q2SERVER
@ -524,6 +525,7 @@ typedef struct client_s
laggedentinfo_t laggedents[MAX_CLIENTS]; laggedentinfo_t laggedents[MAX_CLIENTS];
unsigned int laggedents_count; unsigned int laggedents_count;
float laggedents_frac; float laggedents_frac;
float laggedents_time;
// spawn parms are carried from level to level // spawn parms are carried from level to level
float spawn_parms[NUM_SPAWN_PARMS]; float spawn_parms[NUM_SPAWN_PARMS];
@ -939,7 +941,6 @@ typedef struct
struct netprim_s netprim; struct netprim_s netprim;
int language; //the server operators language
laggedpacket_t *free_lagged_packet; laggedpacket_t *free_lagged_packet;
packet_entities_t entstatebuffer; /*just a temp buffer*/ packet_entities_t entstatebuffer; /*just a temp buffer*/
@ -1325,6 +1326,7 @@ void SV_ClientProtocolExtensionsChanged(client_t *client);
//sv_master.c //sv_master.c
void SVM_Think(int port); void SVM_Think(int port);
vfsfile_t *SVM_GenerateIndex(const char *fname);
// //
@ -1333,6 +1335,9 @@ void SVM_Think(int port);
typedef enum {RD_NONE, RD_CLIENT, RD_PACKET, RD_PACKET_LOG, RD_OBLIVION, RD_MASTER} redirect_t; //oblivion is provided so people can read the output before the buffer is wiped. typedef enum {RD_NONE, RD_CLIENT, RD_PACKET, RD_PACKET_LOG, RD_OBLIVION, RD_MASTER} redirect_t; //oblivion is provided so people can read the output before the buffer is wiped.
void SV_BeginRedirect (redirect_t rd, int lang); void SV_BeginRedirect (redirect_t rd, int lang);
void SV_EndRedirect (void); void SV_EndRedirect (void);
extern char sv_redirected_buf[8000];
extern redirect_t sv_redirected;
extern int sv_redirectedlang;
qboolean PR_GameCodePacket(char *s); qboolean PR_GameCodePacket(char *s);

View file

@ -63,7 +63,7 @@ crosses a waterline.
============================================================================= =============================================================================
*/ */
int needcleanup; static int needcleanup;
//int fatbytes; //int fatbytes;
@ -106,9 +106,9 @@ void SV_ExpandNackFrames(client_t *client, int require)
// because there can be a lot of nails, there is a special // because there can be a lot of nails, there is a special
// network protocol for them // network protocol for them
#define MAX_NAILS 32 #define MAX_NAILS 32
edict_t *nails[MAX_NAILS]; static edict_t *nails[MAX_NAILS];
int numnails; static int numnails;
int nailcount = 0; static int nailcount = 0;
extern int sv_nailmodel, sv_supernailmodel, sv_playermodel; extern int sv_nailmodel, sv_supernailmodel, sv_playermodel;
#ifdef SERVER_DEMO_PLAYBACK #ifdef SERVER_DEMO_PLAYBACK
@ -1564,6 +1564,7 @@ qboolean SVFTE_EmitPacketEntities(client_t *client, packet_entities_t *to, sizeb
frame->numresend = outno; frame->numresend = outno;
frame->sequence = sequence; frame->sequence = sequence;
frame->laggedtime = sv.time;
for (i = 0; i < to->num_entities; i++) for (i = 0; i < to->num_entities; i++)
{ {
n = &to->entities[i]; n = &to->entities[i];
@ -1582,9 +1583,10 @@ qboolean SVFTE_EmitPacketEntities(client_t *client, packet_entities_t *to, sizeb
age = sv.time - sv.world.physicstime; age = sv.time - sv.world.physicstime;
age = bound(0, age, 0.1); age = bound(0, age, 0.1);
VectorMA(n->origin, (sv.time - cl->localtime)/8.0, n->u.q1.velocity, frame->playerpositions[j]); VectorMA(n->origin, (sv.time - cl->localtime)/8.0, n->u.q1.velocity, frame->laggedplayer[j].origin);
VectorCopy(n->angles, frame->laggedplayer[j].angles);
//FIXME: add framestate_t info. //FIXME: add framestate_t info.
frame->playerpresent[j] = true; frame->laggedplayer[j].present = true;
} }
return overflow; return overflow;
@ -2762,13 +2764,14 @@ void SV_WritePlayersToClient (client_t *client, client_frame_t *frame, edict_t *
clst.lastcmd = NULL; clst.lastcmd = NULL;
clst.velocity = NULL; clst.velocity = NULL;
clst.localtime = sv.time; clst.localtime = sv.time;
VectorCopy(clst.origin, frame->playerpositions[j]); VectorCopy(clst.origin, frame->laggedplayer[j].origin);
} }
else else
{ {
VectorMA(clst.origin, (sv.time - clst.localtime), clst.velocity, frame->playerpositions[j]); VectorMA(clst.origin, (sv.time - clst.localtime), clst.velocity, frame->laggedplayer[j].origin);
} }
frame->playerpresent[j] = true; VectorCopy(clst.angles, frame->laggedplayer[j].angles);
frame->laggedplayer[j].present = true;
SV_WritePlayerToClient(msg, &clst); SV_WritePlayerToClient(msg, &clst);
} }
@ -2983,7 +2986,7 @@ typedef struct gibfilter_s {
int minframe; int minframe;
int maxframe; int maxframe;
} gibfilter_t; } gibfilter_t;
gibfilter_t *gibfilter; static gibfilter_t *gibfilter;
void SV_GibFilterPurge(void) void SV_GibFilterPurge(void)
{ {
gibfilter_t *gf; gibfilter_t *gf;
@ -3881,9 +3884,7 @@ svc_playerinfo messages
*/ */
void SV_WriteEntitiesToClient (client_t *client, sizebuf_t *msg, qboolean ignorepvs) void SV_WriteEntitiesToClient (client_t *client, sizebuf_t *msg, qboolean ignorepvs)
{ {
#ifdef NQPROT int i;
int e;
#endif
packet_entities_t *pack; packet_entities_t *pack;
edict_t *clent; edict_t *clent;
client_frame_t *frame; client_frame_t *frame;
@ -3893,7 +3894,8 @@ void SV_WriteEntitiesToClient (client_t *client, sizebuf_t *msg, qboolean ignore
// this is the frame we are creating // this is the frame we are creating
frame = &client->frameunion.frames[client->netchan.incoming_sequence & UPDATE_MASK]; frame = &client->frameunion.frames[client->netchan.incoming_sequence & UPDATE_MASK];
memset(frame->playerpresent, 0, sizeof(frame->playerpresent)); for (i = 0; i < sv.allocated_client_slots; i++)
frame->laggedplayer[i].present = 0;
// find the client's PVS // find the client's PVS
if (ignorepvs) if (ignorepvs)
@ -3977,6 +3979,7 @@ void SV_WriteEntitiesToClient (client_t *client, sizebuf_t *msg, qboolean ignore
SVDP_EmitEntitiesUpdate(client, frame, pack, msg); SVDP_EmitEntitiesUpdate(client, frame, pack, msg);
else else
{ {
int e;
for (e = 0; e < pack->num_entities; e++) for (e = 0; e < pack->num_entities; e++)
{ {
if (pack->entities[e].number > sv.allocated_client_slots) if (pack->entities[e].number > sv.allocated_client_slots)

View file

@ -27,7 +27,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#define INVIS_CHAR2 (char)138 #define INVIS_CHAR2 (char)138
#define INVIS_CHAR3 (char)160 #define INVIS_CHAR3 (char)160
#ifdef SERVERONLY #ifndef HAVE_CLIENT
double host_frametime; double host_frametime;
double realtime; // without any filtering or bounding double realtime; // without any filtering or bounding
qboolean host_initialized; // true if into command execution (compatability) qboolean host_initialized; // true if into command execution (compatability)
@ -35,13 +35,6 @@ quakeparms_t host_parms;
int host_hunklevel; int host_hunklevel;
#endif #endif
// callbacks
void SV_Tcpport_Callback(struct cvar_s *var, char *oldvalue);
void SV_Tcpport6_Callback(struct cvar_s *var, char *oldvalue);
void SV_Port_Callback(struct cvar_s *var, char *oldvalue);
void SV_PortIPv6_Callback(struct cvar_s *var, char *oldvalue);
void SV_PortIPX_Callback(struct cvar_s *var, char *oldvalue);
client_t *host_client; // current client client_t *host_client; // current client
// bound the size of the physics time tic // bound the size of the physics time tic
@ -63,12 +56,9 @@ cvar_t zombietime = CVARD("zombietime", "2", "Client slots will not be reuse
cvar_t sv_crypt_rcon = CVARFD("sv_crypt_rcon", "", CVAR_ARCHIVE, "Controls whether the rcon password must be hashed or not. Hashed passwords also partially prevent replay attacks, but does NOT prevent malicious actors from reading the commands/results.\n0: completely insecure. ONLY allows plain-text passwords. Do not use.\n1: Mandatory hashing (recommended).\nEmpty: Allow either, whether the password is secure or not is purely the client's responsibility/fault. Only use this for comptibility with old clients."); cvar_t sv_crypt_rcon = CVARFD("sv_crypt_rcon", "", CVAR_ARCHIVE, "Controls whether the rcon password must be hashed or not. Hashed passwords also partially prevent replay attacks, but does NOT prevent malicious actors from reading the commands/results.\n0: completely insecure. ONLY allows plain-text passwords. Do not use.\n1: Mandatory hashing (recommended).\nEmpty: Allow either, whether the password is secure or not is purely the client's responsibility/fault. Only use this for comptibility with old clients.");
cvar_t sv_crypt_rcon_clockskew = CVARFD("sv_timestamplen", "60", CVAR_ARCHIVE, "Limits clock skew to reduce (delayed) replay attacks"); cvar_t sv_crypt_rcon_clockskew = CVARFD("sv_timestamplen", "60", CVAR_ARCHIVE, "Limits clock skew to reduce (delayed) replay attacks");
#ifdef SERVERONLY #ifdef SERVERONLY
cvar_t developer = CVAR("developer","0"); // show extra messages
cvar_t rcon_password = CVARF("rcon_password", "", CVAR_NOUNSAFEEXPAND); // password for remote server commands cvar_t rcon_password = CVARF("rcon_password", "", CVAR_NOUNSAFEEXPAND); // password for remote server commands
cvar_t password = CVARF("password", "", CVAR_NOUNSAFEEXPAND); // password for entering the game cvar_t password = CVARF("password", "", CVAR_NOUNSAFEEXPAND); // password for entering the game
#else #else
extern cvar_t developer;
extern cvar_t rcon_password; extern cvar_t rcon_password;
extern cvar_t password; extern cvar_t password;
#endif #endif
@ -108,6 +98,7 @@ cvar_t sv_listen_q3 = CVAR("sv_listen_q3", "0");
cvar_t sv_reconnectlimit = CVARD("sv_reconnectlimit", "0", "Blocks dupe connection within the specified length of time ."); cvar_t sv_reconnectlimit = CVARD("sv_reconnectlimit", "0", "Blocks dupe connection within the specified length of time .");
extern cvar_t net_enable_dtls; extern cvar_t net_enable_dtls;
cvar_t sv_reportheartbeats = CVARD("sv_reportheartbeats", "2", "Print a notice each time a heartbeat is sent to a master server. When set to 2, the message will be displayed once."); cvar_t sv_reportheartbeats = CVARD("sv_reportheartbeats", "2", "Print a notice each time a heartbeat is sent to a master server. When set to 2, the message will be displayed once.");
cvar_t sv_heartbeat_interval = CVARD("sv_heartbeat_interval", "110", "Interval between heartbeats. Low values are abusive, high values may cause NAT/ghost issues.");
cvar_t sv_highchars = CVAR("sv_highchars", "1"); cvar_t sv_highchars = CVAR("sv_highchars", "1");
cvar_t sv_maxrate = CVARD("sv_maxrate", "50000", "This controls the maximum number of bytes any indivual player may receive (when not downloading). The individual user's rate will also be controlled by the user's rate cvar."); cvar_t sv_maxrate = CVARD("sv_maxrate", "50000", "This controls the maximum number of bytes any indivual player may receive (when not downloading). The individual user's rate will also be controlled by the user's rate cvar.");
cvar_t sv_maxdrate = CVARAFD("sv_maxdrate", "500000", cvar_t sv_maxdrate = CVARAFD("sv_maxdrate", "500000",
@ -272,7 +263,9 @@ void SV_Shutdown (void)
#endif #endif
Cvar_Shutdown(); Cvar_Shutdown();
Cmd_Shutdown(); Cmd_Shutdown();
#ifdef PACKAGEMANAGER
PM_Shutdown(); PM_Shutdown();
#endif
InfoBuf_Clear(&svs.info, true); InfoBuf_Clear(&svs.info, true);
@ -1290,7 +1283,7 @@ static void SVC_GetInfo (char *challenge, int fullstatus)
} }
} }
NET_SendPacket (NS_SERVER, resp-response, response, &net_from); NET_SendPacket (svs.sockets, resp-response, response, &net_from);
} }
#endif #endif
@ -1378,7 +1371,7 @@ static void SVC_Log (void)
else if (seq == svs.logsequence) else if (seq == svs.logsequence)
{ //current log isn't available as its not complete yet. { //current log isn't available as its not complete yet.
data[0] = A2A_NACK; data[0] = A2A_NACK;
NET_SendPacket (NS_SERVER, 1, data, &net_from); NET_SendPacket (svs.sockets, 1, data, &net_from);
return; return;
} }
else if (seq > svs.logsequence) //future logs are not valid either. reply with the last that was. this is for compat, just in case. else if (seq > svs.logsequence) //future logs are not valid either. reply with the last that was. this is for compat, just in case.
@ -1392,7 +1385,7 @@ static void SVC_Log (void)
if (!fraglog_public.ival) if (!fraglog_public.ival)
{ //frag logs are not public (for DoS protection perhaps?. { //frag logs are not public (for DoS protection perhaps?.
data[0] = A2A_NACK; data[0] = A2A_NACK;
NET_SendPacket (NS_SERVER, 1, data, &net_from); NET_SendPacket (svs.sockets, 1, data, &net_from);
return; return;
} }
@ -1404,7 +1397,7 @@ static void SVC_Log (void)
Q_snprintfz(data, sizeof(data), "stdlog %i %s\n%s", seq, av, (char *)svs.log_buf[seq&(FRAGLOG_BUFFERS-1)]); Q_snprintfz(data, sizeof(data), "stdlog %i %s\n%s", seq, av, (char *)svs.log_buf[seq&(FRAGLOG_BUFFERS-1)]);
else else
Q_snprintfz(data, sizeof(data), "stdlog %i\n%s", seq, (char *)svs.log_buf[seq&(FRAGLOG_BUFFERS-1)]); Q_snprintfz(data, sizeof(data), "stdlog %i\n%s", seq, (char *)svs.log_buf[seq&(FRAGLOG_BUFFERS-1)]);
NET_SendPacket (NS_SERVER, strlen(data)+1, data, &net_from); NET_SendPacket (svs.sockets, strlen(data)+1, data, &net_from);
} }
/* /*
@ -1420,7 +1413,7 @@ void SVC_Ping (void)
data = A2A_ACK; data = A2A_ACK;
NET_SendPacket (NS_SERVER, 1, &data, &net_from); NET_SendPacket (svs.sockets, 1, &data, &net_from);
} }
//from net_from //from net_from
@ -1777,7 +1770,7 @@ void VARGS SV_RejectMessage(int protocol, char *format, ...)
vsnprintf (string+5,sizeof(string)-1-5, format,argptr); vsnprintf (string+5,sizeof(string)-1-5, format,argptr);
len = strlen(string+4)+1+4; len = strlen(string+4)+1+4;
*(int*)string = BigLong(NETFLAG_CTL|len); *(int*)string = BigLong(NETFLAG_CTL|len);
NET_SendPacket(NS_SERVER, len, string, &net_from); NET_SendPacket(svs.sockets, len, string, &net_from);
return; return;
case SCP_DARKPLACES6: case SCP_DARKPLACES6:
case SCP_DARKPLACES7: case SCP_DARKPLACES7:
@ -1840,7 +1833,7 @@ void SV_AcceptMessage(client_t *newcl)
MSG_WriteByte(&sb, 0/*flags*/); MSG_WriteByte(&sb, 0/*flags*/);
} }
*(int*)sb.data = BigLong(NETFLAG_CTL|sb.cursize); *(int*)sb.data = BigLong(NETFLAG_CTL|sb.cursize);
NET_SendPacket(NS_SERVER, sb.cursize, sb.data, &net_from); NET_SendPacket(svs.sockets, sb.cursize, sb.data, &net_from);
return; return;
} }
case SCP_DARKPLACES6: case SCP_DARKPLACES6:
@ -3484,7 +3477,7 @@ void SVC_RemoteCommand (void)
Con_TPrintf ("Bad rcon from %s:\t%s\n" Con_TPrintf ("Bad rcon from %s:\t%s\n"
, NET_AdrToString (adr, sizeof(adr), &net_from), net_message.data+4); , NET_AdrToString (adr, sizeof(adr), &net_from), net_message.data+4);
SV_BeginRedirect (RD_PACKET, svs.language); SV_BeginRedirect (RD_PACKET, com_language);
Con_TPrintf ("Bad rcon_password. Passwords might be logged. Be careful.\n"); Con_TPrintf ("Bad rcon_password. Passwords might be logged. Be careful.\n");
} }
@ -3501,7 +3494,7 @@ void SVC_RemoteCommand (void)
Con_TPrintf ("Rcon from %s:\t%s\n" Con_TPrintf ("Rcon from %s:\t%s\n"
, NET_AdrToString (adr, sizeof(adr), &net_from), net_message.data+4); , NET_AdrToString (adr, sizeof(adr), &net_from), net_message.data+4);
SV_BeginRedirect (RD_PACKET_LOG, svs.language); SV_BeginRedirect (RD_PACKET_LOG, com_language);
remaining[0] = 0; remaining[0] = 0;
@ -3725,7 +3718,7 @@ qboolean SV_ConnectionlessPacket (void)
if (secure.value) //FIXME: possible problem for nq clients when enabled if (secure.value) //FIXME: possible problem for nq clients when enabled
{ {
Netchan_OutOfBandTPrintf (NS_SERVER, &net_from, svs.language, "%c\nThis server requires client validation.\nPlease use the "FULLENGINENAME" validation program\n", A2C_PRINT); Netchan_OutOfBandTPrintf (NS_SERVER, &net_from, com_language, "%c\nThis server requires client validation.\nPlease use the "FULLENGINENAME" validation program\n", A2C_PRINT);
} }
else else
{ {
@ -3891,7 +3884,7 @@ qboolean SVNQ_ConnectionlessPacket(void)
SZ_Clear(&sb); SZ_Clear(&sb);
MSG_WriteLong(&sb, BigLong(NETFLAG_ACK | 8)); MSG_WriteLong(&sb, BigLong(NETFLAG_ACK | 8));
MSG_WriteLong(&sb, sequence); MSG_WriteLong(&sb, sequence);
NET_SendPacket(NS_SERVER, sb.cursize, sb.data, &net_from); NET_SendPacket(svs.sockets, sb.cursize, sb.data, &net_from);
} }
@ -3907,7 +3900,7 @@ qboolean SVNQ_ConnectionlessPacket(void)
MSG_WriteString(&sb, va("cmd challengeconnect %i %i\n", SV_NewChallenge(), MOD_PROQUAKE)); MSG_WriteString(&sb, va("cmd challengeconnect %i %i\n", SV_NewChallenge(), MOD_PROQUAKE));
*(int*)sb.data = BigLong(NETFLAG_UNRELIABLE|sb.cursize); *(int*)sb.data = BigLong(NETFLAG_UNRELIABLE|sb.cursize);
NET_SendPacket(NS_SERVER, sb.cursize, sb.data, &net_from); NET_SendPacket(svs.sockets, sb.cursize, sb.data, &net_from);
return true; return true;
} }
@ -3935,7 +3928,7 @@ qboolean SVNQ_ConnectionlessPacket(void)
MSG_WriteByte(&sb, CCREP_REJECT); MSG_WriteByte(&sb, CCREP_REJECT);
MSG_WriteString(&sb, "Incorrect game\n"); MSG_WriteString(&sb, "Incorrect game\n");
*(int*)sb.data = BigLong(NETFLAG_CTL+sb.cursize); *(int*)sb.data = BigLong(NETFLAG_CTL+sb.cursize);
NET_SendPacket(NS_SERVER, sb.cursize, sb.data, &net_from); NET_SendPacket(svs.sockets, sb.cursize, sb.data, &net_from);
return false; //not our game. return false; //not our game.
} }
if (MSG_ReadByte() != NQ_NETCHAN_VERSION) if (MSG_ReadByte() != NQ_NETCHAN_VERSION)
@ -3945,7 +3938,7 @@ qboolean SVNQ_ConnectionlessPacket(void)
MSG_WriteByte(&sb, CCREP_REJECT); MSG_WriteByte(&sb, CCREP_REJECT);
MSG_WriteString(&sb, "Incorrect version\n"); MSG_WriteString(&sb, "Incorrect version\n");
*(int*)sb.data = BigLong(NETFLAG_CTL+sb.cursize); *(int*)sb.data = BigLong(NETFLAG_CTL+sb.cursize);
NET_SendPacket(NS_SERVER, sb.cursize, sb.data, &net_from); NET_SendPacket(svs.sockets, sb.cursize, sb.data, &net_from);
return false; //not our version... return false; //not our version...
} }
@ -3957,7 +3950,7 @@ qboolean SVNQ_ConnectionlessPacket(void)
MSG_WriteByte(&sb, CCREP_REJECT); MSG_WriteByte(&sb, CCREP_REJECT);
MSG_WriteString(&sb, *banreason?va("You are banned: %s\n", banreason):"You are banned\n"); MSG_WriteString(&sb, *banreason?va("You are banned: %s\n", banreason):"You are banned\n");
*(int*)sb.data = BigLong(NETFLAG_CTL+sb.cursize); *(int*)sb.data = BigLong(NETFLAG_CTL+sb.cursize);
NET_SendPacket(NS_SERVER, sb.cursize, sb.data, &net_from); NET_SendPacket(svs.sockets, sb.cursize, sb.data, &net_from);
return false; //not our version... return false; //not our version...
} }
@ -3982,7 +3975,7 @@ qboolean SVNQ_ConnectionlessPacket(void)
MSG_WriteByte(&sb, CCREP_REJECT); MSG_WriteByte(&sb, CCREP_REJECT);
MSG_WriteString(&sb, "NQ clients are not supported with hexen2 gamecode\n"); MSG_WriteString(&sb, "NQ clients are not supported with hexen2 gamecode\n");
*(int*)sb.data = BigLong(NETFLAG_CTL+sb.cursize); *(int*)sb.data = BigLong(NETFLAG_CTL+sb.cursize);
NET_SendPacket(NS_SERVER, sb.cursize, sb.data, &net_from); NET_SendPacket(svs.sockets, sb.cursize, sb.data, &net_from);
return false; //not our version... return false; //not our version...
} }
if (sv_listen_nq.ival == 2) if (sv_listen_nq.ival == 2)
@ -3995,7 +3988,7 @@ qboolean SVNQ_ConnectionlessPacket(void)
MSG_WriteByte(&sb, MOD_PROQUAKE); MSG_WriteByte(&sb, MOD_PROQUAKE);
MSG_WriteByte(&sb, MOD_PROQUAKE_VERSION); MSG_WriteByte(&sb, MOD_PROQUAKE_VERSION);
*(int*)sb.data = BigLong(NETFLAG_CTL|sb.cursize); *(int*)sb.data = BigLong(NETFLAG_CTL|sb.cursize);
NET_SendPacket(NS_SERVER, sb.cursize, sb.data, &net_from); NET_SendPacket(svs.sockets, sb.cursize, sb.data, &net_from);
SZ_Clear(&sb); SZ_Clear(&sb);
@ -4006,7 +3999,7 @@ qboolean SVNQ_ConnectionlessPacket(void)
MSG_WriteString(&sb, va("cmd challengeconnect %i %i %i %i %i\n", SV_NewChallenge(), mod, modver, flags, passwd)); MSG_WriteString(&sb, va("cmd challengeconnect %i %i %i %i %i\n", SV_NewChallenge(), mod, modver, flags, passwd));
*(int*)sb.data = BigLong(NETFLAG_UNRELIABLE|sb.cursize); *(int*)sb.data = BigLong(NETFLAG_UNRELIABLE|sb.cursize);
NET_SendPacket(NS_SERVER, sb.cursize, sb.data, &net_from); NET_SendPacket(svs.sockets, sb.cursize, sb.data, &net_from);
/*don't worry about repeating, the nop case above will recover it*/ /*don't worry about repeating, the nop case above will recover it*/
} }
else else
@ -4048,7 +4041,7 @@ qboolean SVNQ_ConnectionlessPacket(void)
MSG_WriteByte (&sb, maxclients.value); MSG_WriteByte (&sb, maxclients.value);
MSG_WriteByte (&sb, NQ_NETCHAN_VERSION); MSG_WriteByte (&sb, NQ_NETCHAN_VERSION);
*(int*)sb.data = BigLong(NETFLAG_CTL+sb.cursize); *(int*)sb.data = BigLong(NETFLAG_CTL+sb.cursize);
NET_SendPacket(NS_SERVER, sb.cursize, sb.data, &net_from); NET_SendPacket(svs.sockets, sb.cursize, sb.data, &net_from);
return true; return true;
case CCREQ_PLAYER_INFO: case CCREQ_PLAYER_INFO:
if (sv_showconnectionlessmessages.ival) if (sv_showconnectionlessmessages.ival)
@ -4082,7 +4075,7 @@ qboolean SVNQ_ConnectionlessPacket(void)
MSG_WriteString (&sb, SV_PlayerPublicAddress(cl)); /*player's address, leave blank, don't spam that info as it can result in personal attacks exploits*/ MSG_WriteString (&sb, SV_PlayerPublicAddress(cl)); /*player's address, leave blank, don't spam that info as it can result in personal attacks exploits*/
} }
*(int*)sb.data = BigLong(NETFLAG_CTL+sb.cursize); *(int*)sb.data = BigLong(NETFLAG_CTL+sb.cursize);
NET_SendPacket(NS_SERVER, sb.cursize, sb.data, &net_from); NET_SendPacket(svs.sockets, sb.cursize, sb.data, &net_from);
return true; return true;
case CCREQ_RULE_INFO: case CCREQ_RULE_INFO:
if (sv_showconnectionlessmessages.ival) if (sv_showconnectionlessmessages.ival)
@ -4132,7 +4125,7 @@ qboolean SVNQ_ConnectionlessPacket(void)
MSG_WriteString (&sb, rval); MSG_WriteString (&sb, rval);
} }
*(int*)sb.data = BigLong(NETFLAG_CTL+sb.cursize); *(int*)sb.data = BigLong(NETFLAG_CTL+sb.cursize);
NET_SendPacket(NS_SERVER, sb.cursize, sb.data, &net_from); NET_SendPacket(svs.sockets, sb.cursize, sb.data, &net_from);
return true; return true;
} }
return false; return false;
@ -4285,7 +4278,7 @@ qboolean SV_ReadPackets (float *delay)
#ifdef SERVER_DEMO_PLAYBACK #ifdef SERVER_DEMO_PLAYBACK
while (giveup-- > 0 && SV_GetPacket()>=0) while (giveup-- > 0 && SV_GetPacket()>=0)
#else #else
while (giveup-- > 0 && (cookie=NET_GetPacket (NS_SERVER, cookie)) >= 0) while (giveup-- > 0 && (cookie=NET_GetPacket (svs.sockets, cookie)) >= 0)
#endif #endif
{ {
// check for connectionless packet (0xffffffff) first // check for connectionless packet (0xffffffff) first
@ -4299,9 +4292,9 @@ qboolean SV_ReadPackets (float *delay)
if (ct - lt > 5*1000) if (ct - lt > 5*1000)
{ {
if (*banreason) if (*banreason)
Netchan_OutOfBandTPrintf(NS_SERVER, &net_from, svs.language, "You are banned: %s\n", banreason); Netchan_OutOfBandTPrintf(NS_SERVER, &net_from, com_language, "You are banned: %s\n", banreason);
else else
Netchan_OutOfBandTPrintf(NS_SERVER, &net_from, svs.language, "You are banned\n"); Netchan_OutOfBandTPrintf(NS_SERVER, &net_from, com_language, "You are banned\n");
} }
continue; continue;
} }
@ -4454,7 +4447,7 @@ dominping:
if (SV_BannedReason (&net_from)) if (SV_BannedReason (&net_from))
continue; continue;
if (NET_WasSpecialPacket(NS_SERVER)) if (NET_WasSpecialPacket(svs.sockets))
continue; continue;
// packet is not from a known client // packet is not from a known client
@ -5125,8 +5118,6 @@ void SV_InitLocal (void)
if (isDedicated) if (isDedicated)
#endif #endif
{ {
Cvar_Register (&developer, cvargroup_servercontrol);
Cvar_Register (&password, cvargroup_servercontrol); Cvar_Register (&password, cvargroup_servercontrol);
Cvar_Register (&rcon_password, cvargroup_servercontrol); Cvar_Register (&rcon_password, cvargroup_servercontrol);
@ -5563,7 +5554,7 @@ void SV_ExtractFromUserinfo (client_t *cl, qboolean verbose)
} }
val = InfoBuf_ValueForKey (&cl->userinfo, "lang"); val = InfoBuf_ValueForKey (&cl->userinfo, "lang");
cl->language = *val?TL_FindLanguage(val):svs.language; cl->language = *val?TL_FindLanguage(val):com_language;
val = InfoBuf_ValueForKey (&cl->userinfo, "nogib"); val = InfoBuf_ValueForKey (&cl->userinfo, "nogib");
cl->gibfilter = !!atoi(val); cl->gibfilter = !!atoi(val);

View file

@ -11,60 +11,213 @@
#include "netinc.h" #include "netinc.h"
//quake1 protocol //quakeworld protocol
// // heartbeat: "a"
// // query: "c\n%i<sequence>\n%i<numplayers>\n"
//queryresponse: "d\naaaappaaaapp"
//quake2 protocol //quake2 protocol
//client sends "query\0" // heartbeat: "heartbeat\n%s<serverinfo>\n%i<frags> %i<ping> \"%s\"<name>\n<repeat>"
//server sends "0xff0xff0xff0xffservers" follwed by lots of ips. // query: "query\0"
//queryresponse: "servers\naaaappaaaapp"
#define SVM_Q1HEARTBEATTIME 330 //quake3/dpmaster protocol
#define SVM_Q2HEARTBEATTIME 330 // heartbeat: "heartbeat DarkPlaces\n"
// query: "getservers[Ext<ipv6>] [%s<game>] %u<version> [empty] [full] [ipv6]"
//queryresponse: "getservers[Ext]Response\\aaaapp/aaaaaaaaaaaapp\\EOF"
enum gametypes_e
{
GT_FFA=0,
GT_TOURNEY=1,
GT_TEAM=3,
GT_CTF=4,
};
typedef struct svm_server_s { typedef struct svm_server_s {
netadr_t adr; netadr_t adr;
int clients; int protover;
unsigned int clients;
unsigned int maxclients;
char hostname[48]; //just for our own listings.
char mapname[16]; //just for our own listings.
char gamedir[16]; //again...
unsigned short gametype;
float expiretime; float expiretime;
bucket_t bucket;
struct svm_game_s *game;
struct svm_server_s *next; struct svm_server_s *next;
} svm_server_t; } svm_server_t;
typedef struct { typedef struct svm_game_s {
SOCKET socketudp; struct svm_game_s *next;
float time;
int port;
svm_server_t *firstserver; svm_server_t *firstserver;
int numservers; size_t numservers;
char name[1];
} svm_game_t;
typedef struct {
float time;
svm_game_t *firstgame;
size_t numgames;
hashtable_t serverhash;
size_t numservers;
struct rates_s
{
double timestamp;
size_t heartbeats;
size_t queries;
size_t junk;
size_t drops;
size_t adds;
} total, stamps[60];
size_t stampring;
double nextstamp;
} masterserver_t; } masterserver_t;
masterserver_t svm = {INVALID_SOCKET}; static masterserver_t svm;
ftenet_connections_t *svm_sockets;
void SVM_RemoveOldServers(void) static void QDECL SVM_Tcpport_Callback(struct cvar_s *var, char *oldvalue)
{ {
svm_server_t *server, *next, *prev=NULL; FTENET_AddToCollection(svm_sockets, var->name, var->string, NA_IP, NP_STREAM);
for (server = svm.firstserver; server; server = next) }
static void QDECL SVM_Port_Callback(struct cvar_s *var, char *oldvalue)
{
FTENET_AddToCollection(svm_sockets, var->name, var->string, NA_IP, NP_DGRAM);
}
static cvar_t sv_heartbeattimeout = CVARD("sv_heartbeattimeout", "600", "How many seconds a server should remain listed after its latest heartbeat. Larger values can avoid issues from packetloss, but can also make dos attacks easier.");
static cvar_t sv_masterport = CVARC("sv_masterport", "27000 28000", SVM_Port_Callback);
static cvar_t sv_masterport_tcp = CVARC("sv_masterport_tcp", "27000 28000", SVM_Tcpport_Callback);
static cvar_t sv_maxgames = CVARD("sv_maxgames", "100", "Limits the number of games that may be known. This is to reduce denial of service attacks.");
static cvar_t sv_maxservers = CVARD("sv_maxservers", "1000", "Limits the number of servers (total from all games) that may be known. This is to reduce denial of service attacks.");
//returns a hash key for a server's address.
static unsigned int SVM_GenerateAddressKey(const netadr_t *adr)
{
unsigned int key;
switch(adr->type)
{ {
next = server->next; case NA_IP:
if (server->expiretime < svm.time) key = *(const unsigned int*)adr->address.ip;
key ^= 0xffff0000; //match ipv6's ipv4-mapped addresses.
key ^= adr->port;
break;
case NA_IPV6:
key = *(const unsigned int*)(adr->address.ip6+0);
key ^= *(const unsigned int*)(adr->address.ip6+4);
key ^= *(const unsigned int*)(adr->address.ip6+8);
key ^= *(const unsigned int*)(adr->address.ip6+12);
key ^= adr->port;
break;
default:
key = 0;
break;
}
return key;
}
static svm_server_t *SVM_GetServer(netadr_t *adr)
{
svm_server_t *server;
unsigned int key = SVM_GenerateAddressKey(adr);
server = Hash_GetKey(&svm.serverhash, key);
while (server && !NET_CompareAdr(&server->adr, adr))
{ {
BZ_Free(server); server = Hash_GetNextKey(&svm.serverhash, key, server);
if (prev) }
prev->next = next; return server;
else }
svm.firstserver = next;
static svm_game_t *SVM_FindGame(const char *game, qboolean create)
{
svm_game_t *g;
for (g = svm.firstgame; g; g = g->next)
{
if (!Q_strcasecmp(game, g->name))
return g;
}
if (create)
{
if (svm.numgames >= sv_maxgames.ival)
{
Con_DPrintf("game limit exceeded\n");
return NULL;
}
//block some chars that may cause issues/exploits. sorry.
if (strchr(game, '.') || strchr(game, '\"') || strchr(game, '/') || strchr(game, '?') || strchr(game, '&') || strchr(game, '+') || strchr(game, '\'') || strchr(game, '<') || strchr(game, '>'))
return NULL;
if (!*game || (*game >= '0' && *game <= '9'))
return NULL; //must not start with a number either.
g = ZF_Malloc(sizeof(*g) + strlen(game));
if (g)
{
strcpy(g->name, game);
g->next = svm.firstgame;
svm.firstgame = g;
svm.numgames++;
Con_DPrintf("Creating game \"%s\"\n", g->name);
}
}
return g;
}
static void SVM_RemoveOldServers(void)
{
svm_game_t **gamelink, *g;
svm_server_t **serverlink, *s;
for (gamelink = &svm.firstgame; (g=*gamelink); )
{
for (serverlink = &g->firstserver; (s=*serverlink); )
{
if (s->expiretime < svm.time)
{
if (developer.ival)
{
char buf[256];
Con_Printf("timeout: %s\n", NET_AdrToString(buf, sizeof(buf), &s->adr));
}
Hash_RemoveDataKey(&svm.serverhash, SVM_GenerateAddressKey(&s->adr), s);
svm.total.drops++;
*serverlink = s->next;
BZ_Free(s);
g->numservers--;
svm.numservers--;
} }
else else
prev = server; serverlink = &s->next;
}
if (!g->firstserver)
{
Con_DPrintf("game \"%s\" has no active servers\n", g->name);
*gamelink = g->next;
Z_Free(g);
svm.numgames--;
}
else
gamelink = &g->next;
} }
} }
int SVM_AddIPAddresses(sizebuf_t *sb, int first) int SVM_AddIPAddresses(sizebuf_t *sb, int first, const char *gamename, int v4, int v6, qboolean prefixes)
{ {
int number = 0; int number = 0;
svm_server_t *server; svm_server_t *server;
int prefix;
for (server = svm.firstserver; server; server = server->next) int len;
svm_game_t *game = SVM_FindGame(gamename, false);
if (game)
{
for (server = game->firstserver; server; server = server->next)
{ {
if (number == first) if (number == first)
break; break;
@ -74,93 +227,203 @@ int SVM_AddIPAddresses(sizebuf_t *sb, int first)
for (; server; server = server->next) for (; server; server = server->next)
{ {
if (sb->cursize + 6 >= sb->maxsize) switch(server->adr.type)
{
case NA_IP:
if (!v4)
continue;
prefix = '\\';
len = 4;
break; break;
case NA_IPV6:
if (!v6)
continue;
prefix = '/';
len = 16;
break;
default:
continue;
}
MSG_WriteByte(sb, server->adr.address.ip[0]); if (prefixes)
MSG_WriteByte(sb, server->adr.address.ip[1]); MSG_WriteByte(sb, prefixes);
MSG_WriteByte(sb, server->adr.address.ip[2]);
MSG_WriteByte(sb, server->adr.address.ip[3]); SZ_Write(sb, server->adr.address.ip, len);
MSG_WriteShort(sb, server->adr.port); MSG_WriteShort(sb, server->adr.port);
number++; number++;
} }
}
return number; return number;
} }
void SVM_Heartbeat(netadr_t *adr, int numclients, float validuntil) vfsfile_t *SVM_GenerateIndex(const char *fname)
{ {
static const char *thecss =
"<style type=\"text/css\">"
"body {"
"background-color: #303030;"
"color: #998080;"
"font-family: verdanah, trebuchet ms, arial, sans-serif;"
"}"
"a { text-decoration: none; }"
"a:link { color: #308090; }"
"a:visited { color: #308090; }"
"a:hover { color: #308090; text-decoration: underline; }"
".header { text-align: center; }"
".footer { text-align: center; }"
".main { width: 1024px; margin: 0 auto; }"
"H1 {"
"text-align: center;"
"background-color: #202020;"
"color: #808080;"
"}"
"table { width: 100%; border-collapse: collapse; }"
"th { text-align: left; }"
"tr:hover { background-color: #202020; }"
"</style>";
char tmpbuf[256];
svm_game_t *game;
svm_server_t *server; svm_server_t *server;
vfsfile_t *f = NULL;
for (server = svm.firstserver; server; server = server->next) unsigned clients = 0, maxclients=0;
if (!strcmp(fname, "index.html"))
{ {
if (NET_CompareAdr(&server->adr, adr)) f = VFSPIPE_Open(1, false);
break; VFS_PRINTF(f, "%s", thecss);
VFS_PRINTF(f, "<h1>FTE-Master</h1>\n");
VFS_PRINTF(f, "<table border=1>\n");
for (game = svm.firstgame; game; game = game->next)
{
VFS_PRINTF(f, "<tr><td><a href=\"game/%s.html\">%s</a></td><td%u server(s)</td></tr>\n", game->name, game->name, (unsigned)game->numservers);
clients += game->numservers;
} }
VFS_PRINTF(f, "</table>\n");
VFS_PRINTF(f, "%u game(s), %u server(s)\n", (unsigned)svm.numgames, clients);
}
else if (!strncmp(fname, "server/", 7))
{
netadr_t adr[64];
int count;
f = VFSPIPE_Open(1, false);
VFS_PRINTF(f, "%s", thecss);
VFS_PRINTF(f, "<h1>Single Server Info</h1>\n", tmpbuf);
VFS_PRINTF(f, "<table border=1>\n");
VFS_PRINTF(f, "<tr><th>Game</th><th>Address</th><th>Hostname</th><th>Mod dir</th><th>Mapname</th><th>Players</th></tr>\n");
count = NET_StringToAdr2(fname+7, 0, adr, countof(adr));
while(count-->0)
{
server = SVM_GetServer(&adr[count]);
if (server)
VFS_PRINTF(f, "<tr><td>%s</td><td>%s</td><td>%s</td><td>%s</td><td>%s</td><td>%u/%u</td></tr>\n", server->game?server->game->name:"Unknown", NET_AdrToString(tmpbuf, sizeof(tmpbuf), &server->adr), server->hostname, server->gamedir, server->mapname, server->clients, server->maxclients);
else
VFS_PRINTF(f, "<tr><td>?</td><td>%s</td><td>?</td><td>?</td><td>?</td><td>?/?</td></tr>\n", NET_AdrToString(tmpbuf, sizeof(tmpbuf), &adr[count]));
}
VFS_PRINTF(f, "</table>\n");
}
else if (!strncmp(fname, "game/", 5))
{
COM_StripExtension(fname+5, tmpbuf, sizeof(tmpbuf));
game = SVM_FindGame(tmpbuf, false);
f = VFSPIPE_Open(1, false);
VFS_PRINTF(f, "%s", thecss);
VFS_PRINTF(f, "<h1>Servers for %s</h1>\n", tmpbuf);
if(game)
{
VFS_PRINTF(f, "<table border=1>\n");
VFS_PRINTF(f, "<tr><th>Address</th><th>Hostname</th><th>Gamedir</th><th>Mapname</th><th>Players</th></tr>\n");
for (server = game->firstserver; server; server = server->next)
{
VFS_PRINTF(f, "<tr><td>%s</td><td>%s</td><td>%s</td><td>%s</td><td>%u/%u</td></tr>\n", NET_AdrToString(tmpbuf, sizeof(tmpbuf), &server->adr), server->hostname, server->gamedir, server->mapname, server->clients, server->maxclients);
clients += server->clients;
maxclients += server->maxclients;
}
VFS_PRINTF(f, "</table>\n");
VFS_PRINTF(f, "%u server(s), %u/%u client(s)\n", (unsigned)game->numservers, clients, maxclients);
}
else
VFS_PRINTF(f, "No servers known for %s\n", tmpbuf);
}
else if (!strncmp(fname, "raw/", 4))
{ //just spews all
COM_StripExtension(fname+4, tmpbuf, sizeof(tmpbuf));
game = SVM_FindGame(tmpbuf, false);
f = VFSPIPE_Open(1, false);
for (server = (game?game->firstserver:NULL); server; server = server->next)
VFS_PRINTF(f, "%s\n", NET_AdrToString(tmpbuf, sizeof(tmpbuf), &server->adr));
}
return f;
}
static svm_server_t *SVM_Heartbeat(const char *gamename, netadr_t *adr, int numclients, float validuntil)
{
svm_server_t *server = SVM_GetServer(adr);
svm_game_t *game = SVM_FindGame(gamename, true);
if (!game)
return NULL;
if (server && server->game != game)
{
server->expiretime = realtime - 1;
server = NULL;
}
if (!server) //not found if (!server) //not found
{ {
if (svm.numservers >= sv_maxservers.ival)
{
Con_DPrintf("server limit exceeded\n");
return NULL;
}
if (developer.ival)
{
char buf[256];
Con_Printf("heartbeat(new - %s): %s\n", game->name, NET_AdrToString(buf, sizeof(buf), adr));
}
server = Z_Malloc(sizeof(svm_server_t)); server = Z_Malloc(sizeof(svm_server_t));
server->next = svm.firstserver; server->game = game;
svm.firstserver = server; server->next = game->firstserver;
game->firstserver = server;
game->numservers++;
svm.numservers++;
server->adr = *adr; server->adr = *adr;
svm.total.adds++;
Hash_AddKey(&svm.serverhash, SVM_GenerateAddressKey(adr), server, &server->bucket);
}
else
{
if (developer.ival)
{
char buf[256];
Con_Printf("heartbeat(refresh): %s\n", NET_AdrToString(buf, sizeof(buf), &server->adr));
}
} }
server->clients = numclients; server->clients = numclients;
server->expiretime = validuntil; server->expiretime = validuntil;
} return server;
void SVM_Init(int port)
{
if (svm.socketudp == INVALID_SOCKET)
svm.socketudp = UDP_OpenSocket(port, false);
}
void SVM_ShutDown (void)
{
if (svm.socketudp != INVALID_SOCKET)
{
UDP_CloseSocket(svm.socketudp);
svm.socketudp = INVALID_SOCKET;
}
} }
void SVM_Think(int port) void SVM_Think(int port)
{ {
char *s; char *s;
struct sockaddr_qstorage addr; int cookie = 0;
int addrlen; int giveup = 500;
netadr_t netaddr;
if (!port) while (giveup-- > 0 && (cookie=NET_GetPacket (svm_sockets, cookie)) >= 0)
{ {
SVM_ShutDown();
return;
}
if (port != svm.port)
{
SVM_ShutDown(); //shut down (to cause a restart)
svm.port = port;
}
SVM_Init(port);
addrlen = sizeof(addr);
net_message.cursize = recvfrom(svm.socketudp, net_message_buffer, sizeof(net_message_buffer)-1, 0, (struct sockaddr *)&addr, &addrlen);
if (net_message.cursize <= 0)
{
addrlen = neterrno();
return;
}
net_message.data[net_message.cursize] = '\0'; //null term all strings. net_message.data[net_message.cursize] = '\0'; //null term all strings.
SockadrToNetadr(&addr, &netaddr);
svm.time = Sys_DoubleTime();
SVM_RemoveOldServers(); svm.time = Sys_DoubleTime();
MSG_BeginReading(msg_nullnetprim); MSG_BeginReading(msg_nullnetprim);
if (MSG_ReadLong() != -1 || msg_badread) if (MSG_ReadLong() != -1 || msg_badread)
@ -169,55 +432,308 @@ void SVM_Think(int port)
} }
s = MSG_ReadStringLine(); s = MSG_ReadStringLine();
s = COM_Parse(s); s = COM_Parse(s);
if (!strcmp(com_token, "getservers")) if (!strcmp(com_token, "getservers") || !strcmp(com_token, "getserversExt"))
{ { //q3
sizebuf_t sb; sizebuf_t sb;
int ver;
char *eos;
char game[64];
qboolean ext = !strcmp(com_token, "getserversExt");
qboolean empty = false;
qboolean full = false;
qboolean ipv4 = !ext;
qboolean ipv6 = false;
int gametype = -1;
s = COM_ParseOut(s, game, sizeof(game));
ver = strtol(game, &eos, 0);
if (*eos)
{
s = COM_Parse(s);
ver = strtol(com_token, NULL, 0);
}
else
Q_strncpyz(game, "Quake3", sizeof(game));
for(;s&&*s;)
{
s = COM_Parse(s);
if (!strcmp(com_token, "empty"))
empty = true;
else if (!strcmp(com_token, "full"))
full = true;
else if (!strcmp(com_token, "ipv4"))
ipv4 = true;
else if (!strcmp(com_token, "ipv6"))
ipv6 = true;
else if (!strcmp(com_token, "ffa"))
gametype = GT_FFA;
else if (!strcmp(com_token, "tourney"))
gametype = GT_TOURNEY;
else if (!strcmp(com_token, "team"))
gametype = GT_TEAM;
else if (!strcmp(com_token, "ctf"))
gametype = GT_CTF;
else if (!strncmp(com_token, "gametype=", 9))
gametype = atoi(com_token+9);
}
svm.total.queries++;
memset(&sb, 0, sizeof(sb)); memset(&sb, 0, sizeof(sb));
sb.maxsize = sizeof(net_message_buffer)-2; sb.maxsize = sizeof(net_message_buffer)-2;
sb.data = net_message_buffer; sb.data = net_message_buffer;
MSG_WriteLong(&sb, -1); MSG_WriteLong(&sb, -1);
MSG_WriteString(&sb, "getserversResponse\\");
sb.cursize--; if (!ipv4 && !ipv6)
SVM_AddIPAddresses(&sb, 0); ipv4 = ipv6 = true; //neither specified? use both
if (ext)
{ //ipv6 and ipv4 addresses
MSG_WriteString(&sb, "getserversExtResponse");
SVM_AddIPAddresses(&sb, 0, game, ipv4, ipv6, true);
}
else
{ //ipv4 only
MSG_WriteString(&sb, "getserversResponse");
SVM_AddIPAddresses(&sb, 0, game, ipv4, ipv6, true);
}
sb.maxsize+=2; sb.maxsize+=2;
MSG_WriteShort(&sb, 0); MSG_WriteByte(&sb, '\\'); //otherwise the last may be considered invalid and ignored.
sendto(svm.socketudp, sb.data, sb.cursize, 0, (struct sockaddr *)&addr, sizeof(addr)); // MSG_WriteByte(&sb, 'E');
// MSG_WriteByte(&sb, 'O');
// MSG_WriteByte(&sb, 'T');
NET_SendPacket(svm_sockets, sb.cursize, sb.data, &net_from);
} }
else if (!strcmp(com_token, "heartbeat")) else if (!strcmp(com_token, "heartbeat"))
{ //quake2 heartbeat. Serverinfo and players follow. { //quake2 heartbeat. Serverinfo and players should follow.
SVM_Heartbeat(&netaddr, 0, svm.time + SVM_Q2HEARTBEATTIME); if (*s == '\n' && s[1] == '\\')
{ //there's some serverinfo there, must be q2...
svm.total.heartbeats++;
SVM_Heartbeat("Quake2", &net_from, 0, svm.time + sv_heartbeattimeout.ival);
}
else
{ //dp/q3/etc are annoying, but we can query from an emphemerial socket to check NAT rules.
sizebuf_t sb;
svm.total.queries++;
memset(&sb, 0, sizeof(sb));
sb.maxsize = sizeof(net_message_buffer);
sb.data = net_message_buffer;
MSG_WriteLong(&sb, -1);
MSG_WriteString(&sb, "getinfo CAKE\n");
sb.cursize--;
NET_SendPacket(svm_sockets, sb.cursize, sb.data, &net_from);
}
}
else if (!strcmp(com_token, "infoResponse"))
{
int clients;
const char *game, *chal;
svm_server_t *srv;
s = MSG_ReadStringLine();
svm.total.heartbeats++;
chal = Info_ValueForKey(s, "challenge");
if (!strcmp(chal, "CAKE"))
{
clients = atoi(Info_ValueForKey(s, "clients"));
game = Info_ValueForKey(s, "gamename");
srv = SVM_Heartbeat(game, &net_from, clients, svm.time + sv_heartbeattimeout.ival);
if (srv)
{
if (developer.ival)
Info_Print(s, "\t");
srv->protover = atoi(Info_ValueForKey(s, "protocol"));
srv->maxclients = atoi(Info_ValueForKey(s, "sv_maxclients"));
Q_strncpyz(srv->hostname, Info_ValueForKey(s, "hostname"), sizeof(srv->hostname));
Q_strncpyz(srv->gamedir, Info_ValueForKey(s, "modname"), sizeof(srv->gamedir));
Q_strncpyz(srv->mapname, Info_ValueForKey(s, "mapname"), sizeof(srv->mapname));
}
}
} }
else if (!strcmp(com_token, "query")) else if (!strcmp(com_token, "query"))
{ //quake2 server listing request { //quake2 server listing request
sizebuf_t sb; sizebuf_t sb;
svm.total.queries++;
memset(&sb, 0, sizeof(sb)); memset(&sb, 0, sizeof(sb));
sb.maxsize = sizeof(net_message_buffer); sb.maxsize = sizeof(net_message_buffer);
sb.data = net_message_buffer; sb.data = net_message_buffer;
MSG_WriteLong(&sb, -1); MSG_WriteLong(&sb, -1);
MSG_WriteString(&sb, "servers\n"); MSG_WriteString(&sb, "servers\n");
sb.cursize--; sb.cursize--;
// MSG_WriteLong(&sb, 0); SVM_AddIPAddresses(&sb, 0, "Quake2", true, false, false);
// MSG_WriteShort(&sb, 0); NET_SendPacket(svm_sockets, sb.cursize, sb.data, &net_from);
SVM_AddIPAddresses(&sb, 0);
sendto(svm.socketudp, sb.data, sb.cursize, 0, (struct sockaddr *)&addr, sizeof(addr));
} }
else if (*com_token == S2M_HEARTBEAT) //sequence, players else if (*com_token == S2M_HEARTBEAT) //sequence, players
{ //quakeworld heartbeat { //quakeworld heartbeat
SVM_Heartbeat(&netaddr, 0, svm.time + SVM_Q1HEARTBEATTIME); int players;
s = MSG_ReadStringLine();
//sequence = atoi(s);
s = MSG_ReadStringLine();
players = atoi(s);
svm.total.heartbeats++;
SVM_Heartbeat("QuakeWorld", &net_from, players, svm.time + sv_heartbeattimeout.ival);
} }
else if (*com_token == S2C_CHALLENGE) else if (*com_token == C2M_MASTER_REQUEST)
{ //quakeworld server listing request { //quakeworld server listing request
sizebuf_t sb; sizebuf_t sb;
svm.total.queries++;
memset(&sb, 0, sizeof(sb)); memset(&sb, 0, sizeof(sb));
sb.maxsize = sizeof(net_message_buffer); sb.maxsize = sizeof(net_message_buffer);
sb.data = net_message_buffer; sb.data = net_message_buffer;
MSG_WriteLong(&sb, -1); MSG_WriteLong(&sb, -1);
MSG_WriteByte(&sb, M2C_MASTER_REPLY); MSG_WriteByte(&sb, M2C_MASTER_REPLY);
MSG_WriteByte(&sb, '\n'); MSG_WriteByte(&sb, '\n');
SVM_AddIPAddresses(&sb, 0); SVM_AddIPAddresses(&sb, 0, "QuakeWorld", true, false, false);
sendto(svm.socketudp, sb.data, sb.cursize, 0, (struct sockaddr *)&addr, sizeof(addr)); NET_SendPacket(svm_sockets, sb.cursize, sb.data, &net_from);
} }
else if (*com_token == A2A_PING)
{ //quakeworld server listing request
sizebuf_t sb;
svm.total.queries++;
memset(&sb, 0, sizeof(sb));
sb.maxsize = sizeof(net_message_buffer);
sb.data = net_message_buffer;
MSG_WriteLong(&sb, -1);
MSG_WriteByte(&sb, A2A_ACK);
MSG_WriteByte(&sb, '\n');
NET_SendPacket(svm_sockets, sb.cursize, sb.data, &net_from);
}
else
svm.total.junk++;
}
SVM_RemoveOldServers();
} }
#else #else
void SVM_Think(int port){} void SVM_Think(int port){}
#endif #endif
#ifdef MASTERONLY
static void SV_Quit_f (void)
{
Con_TPrintf ("Shutting down.\n");
Sys_Quit ();
}
static void SVM_Status_f(void)
{
svm_game_t *g;
svm_server_t *s;
unsigned clients;
struct rates_s *s1, *s2;
float period;
size_t r;
NET_PrintAddresses(svm_sockets);
NET_PrintConnectionsStatus(svm_sockets);
Con_Printf("Game count: %u\n", (unsigned)svm.numgames);
for (g = svm.firstgame; g; g = g->next)
{
clients = 0;
for (s = g->firstserver; s; s = s->next)
clients += s->clients;
Con_Printf("Game %s: %u servers, %u clients\n", g->name, (unsigned)g->numservers, clients);
}
s1 = &svm.total;
r = (svm.stampring >= countof(svm.stamps)-1)?svm.stampring-countof(svm.stamps)-1:0;
s2 = &svm.stamps[r%countof(svm.stamps)];
period = s1->timestamp-s2->timestamp;
period/=60;
if (!period)
period=1;
Con_Printf("Heartbeats/min: %f\n", (s1->heartbeats-s2->heartbeats)/period);
Con_Printf("Queries/min: %f\n", (s1->queries-s2->queries)/period);
}
void SV_Init (struct quakeparms_s *parms)
{
int manarg;
COM_InitArgv (parms->argc, parms->argv);
host_parms = *parms;
Cvar_Init();
Memory_Init();
Sys_Init();
COM_ParsePlusSets(false);
Cbuf_Init ();
Cmd_Init ();
NET_Init ();
COM_Init ();
#ifdef WEBSERVER
IWebInit();
#endif
Cmd_AddCommand ("quit", SV_Quit_f);
Cmd_AddCommand ("status", SVM_Status_f);
svm_sockets = FTENET_CreateCollection(true);
Hash_InitTable(&svm.serverhash, 1024, Z_Malloc(Hash_BytesForBuckets(1024)));
Cvar_Register(&sv_masterport, "server control variables");
Cvar_Register(&sv_masterport_tcp, "server control variables");
Cvar_Register(&sv_heartbeattimeout, "server control variables");
Cvar_Register(&sv_maxgames, "server control variables");
Cvar_Register(&sv_maxservers, "server control variables");
Cvar_ParseWatches();
host_initialized = true;
manarg = COM_CheckParm("-manifest");
if (manarg && manarg < com_argc-1 && com_argv[manarg+1])
{
char *man = FS_MallocFile(com_argv[manarg+1], FS_SYSTEM, NULL);
FS_ChangeGame(FS_Manifest_Parse(NULL, man), true, true);
BZ_Free(man);
}
else
FS_ChangeGame(NULL, true, true);
Cmd_StuffCmds();
Cbuf_Execute ();
Cvar_ForceCallback(&sv_masterport);
Cvar_ForceCallback(&sv_masterport_tcp);
Con_TPrintf ("Exe: %s %s\n", __DATE__, __TIME__);
Con_Printf ("%s\n", version_string());
Con_TPrintf ("======== %s Initialized ========\n", "FTEMaster");
}
float SV_Frame (void)
{
realtime = Sys_DoubleTime();
while (1)
{
const char *cmd = Sys_ConsoleInput ();
if (!cmd)
break;
Log_String(LOG_CONSOLE, cmd);
Cbuf_AddText (cmd, RESTRICT_LOCAL);
Cbuf_AddText ("\n", RESTRICT_LOCAL);
}
Cbuf_Execute ();
SVM_Think(sv_masterport.ival);
//record lots of info over multiple frames, for smoother stats info.
svm.total.timestamp = realtime;
if (svm.nextstamp < realtime)
{
svm.stamps[svm.stampring%countof(svm.stamps)] = svm.total;
svm.stampring++;
svm.nextstamp = realtime+60;
}
return 4;
}
#endif

View file

@ -41,7 +41,7 @@ Con_Printf redirection
============================================================================= =============================================================================
*/ */
char sv_redirected_buf[8000]; char sv_redirected_buf[countof(sv_redirected_buf)];
redirect_t sv_redirected; redirect_t sv_redirected;
int sv_redirectedlang; int sv_redirectedlang;
@ -74,7 +74,7 @@ void SV_FlushRedirect (void)
send[4] = A2C_PRINT; send[4] = A2C_PRINT;
memcpy (send+5, sv_redirected_buf, strlen(sv_redirected_buf)+1); memcpy (send+5, sv_redirected_buf, strlen(sv_redirected_buf)+1);
NET_SendPacket (NS_SERVER, strlen(send)+1, send, &net_from); NET_SendPacket (svs.sockets, strlen(send)+1, send, &net_from);
} }
#ifdef SUBSERVERS #ifdef SUBSERVERS
else if (sv_redirected == RD_MASTER) else if (sv_redirected == RD_MASTER)
@ -145,208 +145,6 @@ void SV_EndRedirect (void)
sv_redirected = RD_NONE; sv_redirected = RD_NONE;
} }
/*
================
Con_Printf
Handles cursor positioning, line wrapping, etc
================
*/
#define MAXPRINTMSG 4096
// FIXME: make a buffer size safe vsprintf?
#ifdef SERVERONLY
vfsfile_t *con_pipe;
vfsfile_t *Con_POpen(char *conname)
{
if (!conname || !*conname)
{
if (con_pipe)
VFS_CLOSE(con_pipe);
con_pipe = VFSPIPE_Open(2, false);
return con_pipe;
}
return NULL;
}
static void Con_PrintFromThread (void *ctx, void *data, size_t a, size_t b)
{
Con_Printf("%s", (char*)data);
BZ_Free(data);
}
void VARGS Con_Printf (const char *fmt, ...)
{
va_list argptr;
char msg[MAXPRINTMSG];
va_start (argptr,fmt);
vsnprintf (msg,sizeof(msg)-1, fmt,argptr);
va_end (argptr);
if (!Sys_IsMainThread())
{
COM_AddWork(WG_MAIN, Con_PrintFromThread, NULL, Z_StrDup(msg), 0, 0);
return;
}
// add to redirected message
if (sv_redirected)
{
if (strlen (msg) + strlen(sv_redirected_buf) > sizeof(sv_redirected_buf) - 1)
SV_FlushRedirect ();
strcat (sv_redirected_buf, msg);
if (sv_redirected != -1)
return;
}
Sys_Printf ("%s", msg); // also echo to debugging console
Con_Log(msg); // log to console
if (con_pipe)
VFS_PUTS(con_pipe, msg);
}
void Con_TPrintf (translation_t stringnum, ...)
{
va_list argptr;
char msg[MAXPRINTMSG];
const char *fmt;
if (!Sys_IsMainThread())
{ //shouldn't be redirected anyway...
fmt = langtext(stringnum,svs.language);
va_start (argptr,stringnum);
vsnprintf (msg,sizeof(msg)-1, fmt,argptr);
va_end (argptr);
COM_AddWork(WG_MAIN, Con_PrintFromThread, NULL, Z_StrDup(msg), 0, 0);
return;
}
// add to redirected message
if (sv_redirected)
{
fmt = langtext(stringnum,sv_redirectedlang);
va_start (argptr,stringnum);
vsnprintf (msg,sizeof(msg)-1, fmt,argptr);
va_end (argptr);
if (strlen (msg) + strlen(sv_redirected_buf) > sizeof(sv_redirected_buf) - 1)
SV_FlushRedirect ();
strcat (sv_redirected_buf, msg);
return;
}
fmt = langtext(stringnum,svs.language);
va_start (argptr,stringnum);
vsnprintf (msg,sizeof(msg)-1, fmt,argptr);
va_end (argptr);
Sys_Printf ("%s", msg); // also echo to debugging console
Con_Log(msg); // log to console
if (con_pipe)
VFS_PUTS(con_pipe, msg);
}
/*
================
Con_DPrintf
A Con_Printf that only shows up if the "developer" cvar is set
================
*/
static void Con_DPrintFromThread (void *ctx, void *data, size_t a, size_t b)
{
Con_DLPrintf(a, "%s", (char*)data);
BZ_Free(data);
}
void Con_DPrintf (const char *fmt, ...)
{
va_list argptr;
char msg[MAXPRINTMSG];
extern cvar_t log_developer;
if (!developer.value && !log_developer.value)
return;
va_start (argptr,fmt);
vsnprintf (msg,sizeof(msg)-1, fmt,argptr);
va_end (argptr);
if (!Sys_IsMainThread())
{
COM_AddWork(WG_MAIN, Con_DPrintFromThread, NULL, Z_StrDup(msg), 0, 0);
return;
}
// add to redirected message
if (sv_redirected)
{
if (strlen (msg) + strlen(sv_redirected_buf) > sizeof(sv_redirected_buf) - 1)
SV_FlushRedirect ();
strcat (sv_redirected_buf, 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
}
void Con_DLPrintf (int level, const char *fmt, ...)
{
va_list argptr;
char msg[MAXPRINTMSG];
extern cvar_t log_developer;
if (developer.ival < level && !log_developer.value)
return;
va_start (argptr,fmt);
vsnprintf (msg,sizeof(msg)-1, fmt,argptr);
va_end (argptr);
if (!Sys_IsMainThread())
{
COM_AddWork(WG_MAIN, Con_DPrintFromThread, NULL, Z_StrDup(msg), level, 0);
return;
}
// add to redirected message
if (sv_redirected)
{
if (strlen (msg) + strlen(sv_redirected_buf) > sizeof(sv_redirected_buf) - 1)
SV_FlushRedirect ();
strcat (sv_redirected_buf, msg);
if (sv_redirected != -1)
return;
}
if (developer.ival >= level)
Sys_Printf ("%s", msg); // also echo to debugging console
if (log_developer.value)
Con_Log(msg); // log to console
}
//for spammed warnings, so they don't spam prints with every single frame/call. the timer arg should be a static local.
void VARGS Con_ThrottlePrintf (float *timer, int developerlevel, const char *fmt, ...)
{
va_list argptr;
char msg[MAXPRINTMSG];
va_start (argptr,fmt);
vsnprintf (msg,sizeof(msg)-1, fmt,argptr);
va_end (argptr);
if (developerlevel)
Con_DLPrintf (developerlevel, "%s", msg);
else
Con_Printf("%s", msg);
}
#endif
/* /*
============================================================================= =============================================================================
@ -624,7 +422,7 @@ void VARGS SV_BroadcastTPrintf (int level, translation_t stringnum, ...)
client_t *cl; client_t *cl;
int i; int i;
int oldlang=-1; int oldlang=-1;
const char *fmt = langtext(stringnum, oldlang=svs.language); const char *fmt = langtext(stringnum, oldlang=com_language);
va_start (argptr,stringnum); va_start (argptr,stringnum);
vsnprintf (string,sizeof(string)-1, fmt,argptr); vsnprintf (string,sizeof(string)-1, fmt,argptr);

View file

@ -765,7 +765,7 @@ static int Sys_CheckChRoot(void)
freeaddrinfo(info); freeaddrinfo(info);
} }
#ifdef SQL #if defined(SQL) && defined(HAVE_SERVER)
SQL_Available(); SQL_Available();
#endif #endif
#ifdef HAVE_GNUTLS #ifdef HAVE_GNUTLS

View file

@ -194,7 +194,7 @@ qboolean SV_CheckRealIP(client_t *client, qboolean force)
if (client->realip_status == 1) if (client->realip_status == 1)
{ {
msg = va("\xff\xff\xff\xff%c %i", A2A_PING, client->realip_ping); msg = va("\xff\xff\xff\xff%c %i", A2A_PING, client->realip_ping);
NET_SendPacket(NS_SERVER, strlen(msg), msg, &client->realip); NET_SendPacket(svs.sockets, strlen(msg), msg, &client->realip);
} }
else else
{ {
@ -2566,7 +2566,7 @@ void VARGS OutofBandPrintf(netadr_t *where, char *fmt, ...)
vsnprintf (send+5, sizeof(send)-5, fmt, argptr); vsnprintf (send+5, sizeof(send)-5, fmt, argptr);
va_end (argptr); va_end (argptr);
NET_SendPacket (NS_SERVER, strlen(send)+1, send, where); NET_SendPacket (svs.sockets, strlen(send)+1, send, where);
} }
/* /*
@ -4980,9 +4980,9 @@ void Cmd_SetPos_f(void)
if (!svprogfuncs) if (!svprogfuncs)
return; return;
if (Cmd_Argc() != 4) if (Cmd_Argc() != 4 && Cmd_Argc() != 7)
{ {
SV_ClientPrintf(host_client, PRINT_HIGH, "setpos %f %f %f\n", sv_player->v->origin[0], sv_player->v->origin[1], sv_player->v->origin[2]); SV_ClientPrintf(host_client, PRINT_HIGH, "setpos %f %f %f %f %f %f\n", sv_player->v->origin[0], sv_player->v->origin[1], sv_player->v->origin[2], sv_player->v->v_angle[0], sv_player->v->v_angle[1], sv_player->v->v_angle[2]);
return; return;
} }
SV_LogPlayer(host_client, "setpos cheat"); SV_LogPlayer(host_client, "setpos cheat");
@ -4999,6 +4999,14 @@ void Cmd_SetPos_f(void)
sv_player->v->origin[1] = atof(Cmd_Argv(2)); sv_player->v->origin[1] = atof(Cmd_Argv(2));
sv_player->v->origin[2] = atof(Cmd_Argv(3)); sv_player->v->origin[2] = atof(Cmd_Argv(3));
World_LinkEdict (&sv.world, (wedict_t*)sv_player, false); World_LinkEdict (&sv.world, (wedict_t*)sv_player, false);
if (Cmd_Argc() > 4)
{
sv_player->v->angles[0] = atof(Cmd_Argv(4));
sv_player->v->angles[1] = atof(Cmd_Argv(5));
sv_player->v->angles[2] = atof(Cmd_Argv(6));
sv_player->v->fixangle = true;
}
} }
void SV_SetUpClientEdict (client_t *cl, edict_t *ent) void SV_SetUpClientEdict (client_t *cl, edict_t *ent)
@ -7657,7 +7665,7 @@ void SV_ExecuteClientMessage (client_t *cl)
vec3_t o; vec3_t o;
int checksumIndex; int checksumIndex;
qbyte checksum, calculatedChecksum; qbyte checksum, calculatedChecksum;
int seq_hash, i; int seq_hash;
// calc ping time // calc ping time
if (cl->frameunion.frames) if (cl->frameunion.frames)
@ -7694,14 +7702,9 @@ void SV_ExecuteClientMessage (client_t *cl)
#ifdef warningmsg #ifdef warningmsg
#pragma warningmsg("FIXME: make antilag optionally support non-player ents too") #pragma warningmsg("FIXME: make antilag optionally support non-player ents too")
#endif #endif
for (i = 0; i < sv.allocated_client_slots; i++)
{
cl->laggedents[i].present = frame->playerpresent[i];
if (cl->laggedents[i].present)
VectorCopy(frame->playerpositions[i], cl->laggedents[i].laggedpos);
}
cl->laggedents_count = sv.allocated_client_slots; cl->laggedents_count = sv.allocated_client_slots;
memcpy(cl->laggedents, frame->laggedplayer, sizeof(*cl->laggedents)*cl->laggedents_count);
cl->laggedents_time = frame->laggedtime;
cl->laggedents_frac = !*sv_antilag_frac.string?1:sv_antilag_frac.value; cl->laggedents_frac = !*sv_antilag_frac.string?1:sv_antilag_frac.value;
} }
else else

View file

@ -649,12 +649,12 @@ static int SVQ3_PointContents(vec3_t pos, int entnum)
mod = Q3G_GetCModel(es->s.modelindex); mod = Q3G_GetCModel(es->s.modelindex);
if (!mod) if (!mod)
continue; continue;
World_TransformedTrace(mod, 0, 0, pos, pos, vec3_origin, vec3_origin, false, &tr, es->r.currentOrigin, es->r.currentAngles, 0xffffffff); World_TransformedTrace(mod, 0, NULL, pos, pos, vec3_origin, vec3_origin, false, &tr, es->r.currentOrigin, es->r.currentAngles, 0xffffffff);
} }
else else
{ {
mod = CM_TempBoxModel(es->r.mins, es->r.maxs); mod = CM_TempBoxModel(es->r.mins, es->r.maxs);
World_TransformedTrace(mod, 0, 0, pos, pos, vec3_origin, vec3_origin, false, &tr, es->r.currentOrigin, vec3_origin, 0xffffffff); World_TransformedTrace(mod, 0, NULL, pos, pos, vec3_origin, vec3_origin, false, &tr, es->r.currentOrigin, vec3_origin, 0xffffffff);
} }
cont |= tr.contents; cont |= tr.contents;
@ -3405,7 +3405,7 @@ void SVQ3_DirectConnect(void) //Actually connect the client, use up a slot, and
{ {
Con_Printf("%s\n", reason); Con_Printf("%s\n", reason);
reason = va("\377\377\377\377print\n%s", reason); reason = va("\377\377\377\377print\n%s", reason);
NET_SendPacket (NS_SERVER, strlen(reason), reason, &net_from); NET_SendPacket (svs.sockets, strlen(reason), reason, &net_from);
return; return;
} }
@ -3422,7 +3422,7 @@ void SVQ3_DirectConnect(void) //Actually connect the client, use up a slot, and
cl->gamestatesequence = -1; cl->gamestatesequence = -1;
NET_SendPacket (NS_SERVER, 19, "\377\377\377\377connectResponse", &net_from); NET_SendPacket (svs.sockets, 19, "\377\377\377\377connectResponse", &net_from);
cl->frameunion.q3frames = BZ_Malloc(Q3UPDATE_BACKUP*sizeof(*cl->frameunion.q3frames)); cl->frameunion.q3frames = BZ_Malloc(Q3UPDATE_BACKUP*sizeof(*cl->frameunion.q3frames));
} }

View file

@ -1241,7 +1241,7 @@ Handles selection or creation of a clipping hull, and offseting (and
eventually rotation) of the end points eventually rotation) of the end points
================== ==================
*/ */
static trace_t World_ClipMoveToEntity (world_t *w, wedict_t *ent, vec3_t eorg, vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, int hullnum, qboolean hitmodel, qboolean capsule, unsigned int hitcontentsmask) //hullnum overrides min/max for q1 style bsps static trace_t World_ClipMoveToEntity (world_t *w, wedict_t *ent, vec3_t eorg, vec3_t eang, vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, int hullnum, qboolean hitmodel, qboolean capsule, unsigned int hitcontentsmask) //hullnum overrides min/max for q1 style bsps
{ {
trace_t trace; trace_t trace;
model_t *model; model_t *model;
@ -1285,16 +1285,16 @@ static trace_t World_ClipMoveToEntity (world_t *w, wedict_t *ent, vec3_t eorg, v
if (ent->v->solid == SOLID_PORTAL) if (ent->v->solid == SOLID_PORTAL)
{ {
//solid_portal cares only about origins and as such has no mins/max //solid_portal cares only about origins and as such has no mins/max
World_TransformedTrace(model, 0, &framestate, start, end, vec3_origin, vec3_origin, capsule, &trace, eorg, ent->v->angles, hitcontentsmask); World_TransformedTrace(model, 0, &framestate, start, end, vec3_origin, vec3_origin, capsule, &trace, eorg, eang, hitcontentsmask);
if (trace.startsolid) //portals should not block traces. this prevents infinite looping if (trace.startsolid) //portals should not block traces. this prevents infinite looping
trace.startsolid = false; trace.startsolid = false;
hitmodel = false; hitmodel = false;
} }
else if (ent->v->solid != SOLID_BSP) else if (ent->v->solid != SOLID_BSP)
{ {
ent->v->angles[0]*=r_meshpitch.value; //carmack made bsp models rotate wrongly. eang[0]*=r_meshpitch.value; //carmack made bsp models rotate wrongly.
World_TransformedTrace(model, hullnum, &framestate, start, end, mins, maxs, capsule, &trace, eorg, ent->v->angles, hitcontentsmask); World_TransformedTrace(model, hullnum, &framestate, start, end, mins, maxs, capsule, &trace, eorg, eang, hitcontentsmask);
ent->v->angles[0]*=r_meshpitch.value; eang[0]*=r_meshpitch.value;
} }
else else
{ {
@ -1315,7 +1315,7 @@ static trace_t World_ClipMoveToEntity (world_t *w, wedict_t *ent, vec3_t eorg, v
} }
if (hitcontentsmask & forcedcontents) if (hitcontentsmask & forcedcontents)
{ {
World_TransformedTrace(model, hullnum, &framestate, start, end, mins, maxs, capsule, &trace, eorg, ent->v->angles, ~0u); World_TransformedTrace(model, hullnum, &framestate, start, end, mins, maxs, capsule, &trace, eorg, eang, ~0u);
if (trace.contents) if (trace.contents)
trace.contents = forcedcontents; trace.contents = forcedcontents;
} }
@ -1330,7 +1330,7 @@ static trace_t World_ClipMoveToEntity (world_t *w, wedict_t *ent, vec3_t eorg, v
} }
} }
else else
World_TransformedTrace(model, hullnum, &framestate, start, end, mins, maxs, capsule, &trace, eorg, ent->v->angles, hitcontentsmask); World_TransformedTrace(model, hullnum, &framestate, start, end, mins, maxs, capsule, &trace, eorg, eang, hitcontentsmask);
} }
// if using hitmodel, we know it hit the bounding box, so try a proper trace now. // if using hitmodel, we know it hit the bounding box, so try a proper trace now.
@ -1342,7 +1342,7 @@ static trace_t World_ClipMoveToEntity (world_t *w, wedict_t *ent, vec3_t eorg, v
if (model && model->funcs.NativeTrace && model->loadstate == MLS_LOADED) if (model && model->funcs.NativeTrace && model->loadstate == MLS_LOADED)
{ {
//do the second trace, using the actual mesh. //do the second trace, using the actual mesh.
World_TransformedTrace(model, hullnum, &framestate, start, end, mins, maxs, capsule, &trace, eorg, ent->v->angles, hitcontentsmask); World_TransformedTrace(model, hullnum, &framestate, start, end, mins, maxs, capsule, &trace, eorg, eang, hitcontentsmask);
} }
} }
@ -1687,9 +1687,9 @@ void WorldQ2_ClipMoveToEntities (world_t *w, moveclip_t *clip )
angles = vec3_origin; // boxes don't rotate angles = vec3_origin; // boxes don't rotate
if (touch->svflags & SVF_MONSTER) if (touch->svflags & SVF_MONSTER)
World_TransformedTrace (model, 0, 0, clip->start, clip->end, clip->mins2, clip->maxs2, false, &trace, touch->s.origin, angles, clip->hitcontentsmask); World_TransformedTrace (model, 0, NULL, clip->start, clip->end, clip->mins2, clip->maxs2, false, &trace, touch->s.origin, angles, clip->hitcontentsmask);
else else
World_TransformedTrace (model, 0, 0, clip->start, clip->end, clip->mins, clip->maxs, false, &trace, touch->s.origin, angles, clip->hitcontentsmask); World_TransformedTrace (model, 0, NULL, clip->start, clip->end, clip->mins, clip->maxs, false, &trace, touch->s.origin, angles, clip->hitcontentsmask);
if (trace.allsolid || trace.startsolid || if (trace.allsolid || trace.startsolid ||
trace.fraction < clip->trace.fraction) trace.fraction < clip->trace.fraction)
@ -1875,9 +1875,9 @@ static void World_ClipToEverything (world_t *w, moveclip_t *clip)
} }
if ((int)touch->v->flags & FL_MONSTER) if ((int)touch->v->flags & FL_MONSTER)
trace = World_ClipMoveToEntity (w, touch, touch->v->origin, clip->start, clip->mins2, clip->maxs2, clip->end, clip->hullnum, clip->type & MOVE_HITMODEL, clip->capsule, clip->hitcontentsmask); trace = World_ClipMoveToEntity (w, touch, touch->v->origin, touch->v->angles, clip->start, clip->mins2, clip->maxs2, clip->end, clip->hullnum, clip->type & MOVE_HITMODEL, clip->capsule, clip->hitcontentsmask);
else else
trace = World_ClipMoveToEntity (w, touch, touch->v->origin, clip->start, clip->mins, clip->maxs, clip->end, clip->hullnum, clip->type & MOVE_HITMODEL, clip->capsule, clip->hitcontentsmask); trace = World_ClipMoveToEntity (w, touch, touch->v->origin, touch->v->angles, clip->start, clip->mins, clip->maxs, clip->end, clip->hullnum, clip->type & MOVE_HITMODEL, clip->capsule, clip->hitcontentsmask);
if (trace.allsolid || trace.startsolid || if (trace.allsolid || trace.startsolid ||
trace.fraction < clip->trace.fraction) trace.fraction < clip->trace.fraction)
{ {
@ -2034,9 +2034,9 @@ static void World_ClipToLinks (world_t *w, areagridlink_t *node, moveclip_t *cli
} }
if ((int)touch->v->flags & FL_MONSTER) if ((int)touch->v->flags & FL_MONSTER)
trace = World_ClipMoveToEntity (w, touch, touch->v->origin, clip->start, clip->mins2, clip->maxs2, clip->end, clip->hullnum, clip->type & MOVE_HITMODEL, clip->capsule, clip->hitcontentsmask); trace = World_ClipMoveToEntity (w, touch, touch->v->origin, touch->v->angles, clip->start, clip->mins2, clip->maxs2, clip->end, clip->hullnum, clip->type & MOVE_HITMODEL, clip->capsule, clip->hitcontentsmask);
else else
trace = World_ClipMoveToEntity (w, touch, touch->v->origin, clip->start, clip->mins, clip->maxs, clip->end, clip->hullnum, clip->type & MOVE_HITMODEL, clip->capsule, clip->hitcontentsmask); trace = World_ClipMoveToEntity (w, touch, touch->v->origin, touch->v->angles, clip->start, clip->mins, clip->maxs, clip->end, clip->hullnum, clip->type & MOVE_HITMODEL, clip->capsule, clip->hitcontentsmask);
if (trace.fraction < clip->trace.fraction) if (trace.fraction < clip->trace.fraction)
{ {
@ -2561,18 +2561,18 @@ trace_t World_Move (world_t *w, vec3_t start, vec3_t mins, vec3_t maxs, vec3_t e
if (type & MOVE_OTHERONLY) if (type & MOVE_OTHERONLY)
{ {
wedict_t *other = WEDICT_NUM_UB(w->progs, *w->g.other); wedict_t *other = WEDICT_NUM_UB(w->progs, *w->g.other);
return World_ClipMoveToEntity (w, other, other->v->origin, start, mins, maxs, end, hullnum, type & MOVE_HITMODEL, clip.capsule, clip.hitcontentsmask); return World_ClipMoveToEntity (w, other, other->v->origin, other->v->angles, start, mins, maxs, end, hullnum, type & MOVE_HITMODEL, clip.capsule, clip.hitcontentsmask);
} }
#ifndef NOLEGACY #ifndef NOLEGACY
if ((type&MOVE_WORLDONLY) == MOVE_WORLDONLY) if ((type&MOVE_WORLDONLY) == MOVE_WORLDONLY)
{ //for compat with DP { //for compat with DP
wedict_t *other = w->edicts; wedict_t *other = w->edicts;
return World_ClipMoveToEntity (w, other, other->v->origin, start, mins, maxs, end, hullnum, type & MOVE_HITMODEL, clip.capsule, clip.hitcontentsmask); return World_ClipMoveToEntity (w, other, other->v->origin, other->v->angles, start, mins, maxs, end, hullnum, type & MOVE_HITMODEL, clip.capsule, clip.hitcontentsmask);
} }
#endif #endif
// clip to world // clip to world
clip.trace = World_ClipMoveToEntity (w, w->edicts, w->edicts->v->origin, start, mins, maxs, end, hullnum, false, clip.capsule, clip.hitcontentsmask); clip.trace = World_ClipMoveToEntity (w, w->edicts, w->edicts->v->origin, w->edicts->v->angles, start, mins, maxs, end, hullnum, false, clip.capsule, clip.hitcontentsmask);
clip.start = start; clip.start = start;
clip.end = end; clip.end = end;
@ -2622,6 +2622,7 @@ trace_t World_Move (world_t *w, vec3_t start, vec3_t mins, vec3_t maxs, vec3_t e
w->lagents = svs.clients[passedict->entnum-1].laggedents; w->lagents = svs.clients[passedict->entnum-1].laggedents;
w->maxlagents = svs.clients[passedict->entnum-1].laggedents_count; w->maxlagents = svs.clients[passedict->entnum-1].laggedents_count;
w->lagentsfrac = svs.clients[passedict->entnum-1].laggedents_frac; w->lagentsfrac = svs.clients[passedict->entnum-1].laggedents_frac;
w->lagentstime = svs.clients[passedict->entnum-1].laggedents_time;
} }
else if (passedict->v->owner) else if (passedict->v->owner)
{ {
@ -2631,6 +2632,7 @@ trace_t World_Move (world_t *w, vec3_t start, vec3_t mins, vec3_t maxs, vec3_t e
w->lagents = svs.clients[passedict->v->owner-1].laggedents; w->lagents = svs.clients[passedict->v->owner-1].laggedents;
w->maxlagents = svs.clients[passedict->v->owner-1].laggedents_count; w->maxlagents = svs.clients[passedict->v->owner-1].laggedents_count;
w->lagentsfrac = svs.clients[passedict->v->owner-1].laggedents_frac; w->lagentsfrac = svs.clients[passedict->v->owner-1].laggedents_frac;
w->lagentstime = svs.clients[passedict->entnum-1].laggedents_time;
} }
} }
} }
@ -2640,7 +2642,8 @@ trace_t World_Move (world_t *w, vec3_t start, vec3_t mins, vec3_t maxs, vec3_t e
{ {
trace_t trace; trace_t trace;
wedict_t *touch; wedict_t *touch;
vec3_t lp; vec3_t lp, la;
int j;
#ifdef USEAREAGRID #ifdef USEAREAGRID
World_ClipToAllLinks (w, &clip); World_ClipToAllLinks (w, &clip);
@ -2686,7 +2689,18 @@ trace_t World_Move (world_t *w, vec3_t start, vec3_t mins, vec3_t maxs, vec3_t e
continue; continue;
} }
VectorInterpolate(touch->v->origin, w->lagentsfrac, w->lagents[i].laggedpos, lp); VectorInterpolate(touch->v->origin, w->lagentsfrac, w->lagents[i].origin, lp);
//I hate working with angles
VectorSubtract(w->lagents[i].angles, touch->v->angles, la);
for (j = 0; j < 3; j++)
{
la[j] = (360.0/65536) * ((int)(la[j]*(65536/360.0)) & 65535);
if (la[j]<-180)
la[j] += 360;
if (la[j]>180)
la[j] -= 360;
}
VectorMA(touch->v->angles, 1, la, la);
if (clip.boxmins[0] > lp[0]+touch->v->maxs[0] if (clip.boxmins[0] > lp[0]+touch->v->maxs[0]
|| clip.boxmins[1] > lp[1]+touch->v->maxs[1] || clip.boxmins[1] > lp[1]+touch->v->maxs[1]
@ -2707,7 +2721,13 @@ trace_t World_Move (world_t *w, vec3_t start, vec3_t mins, vec3_t maxs, vec3_t e
continue; // don't clip against owner continue; // don't clip against owner
} }
trace = World_ClipMoveToEntity (w, touch, lp, clip.start, clip.mins, clip.maxs, clip.end, clip.hullnum, clip.type & MOVE_HITMODEL, clip.capsule, clip.hitcontentsmask); if ((clip.type & MOVE_HITMODEL) && w->Event_Backdate)
{
w->Event_Backdate(w, touch, w->lagentstime);
trace = World_ClipMoveToEntity (w, touch, lp, la, clip.start, clip.mins, clip.maxs, clip.end, clip.hullnum, clip.type & MOVE_HITMODEL, clip.capsule, clip.hitcontentsmask);
}
else
trace = World_ClipMoveToEntity (w, touch, lp, la, clip.start, clip.mins, clip.maxs, clip.end, clip.hullnum, clip.type & MOVE_HITMODEL, clip.capsule, clip.hitcontentsmask);
if (trace.allsolid || trace.startsolid || trace.fraction < clip.trace.fraction) if (trace.allsolid || trace.startsolid || trace.fraction < clip.trace.fraction)
{ {

View file

@ -1,4 +1,4 @@
!!ver 100 150 !!ver 100 300
!!permu TESS !!permu TESS
!!permu BUMP !!permu BUMP
!!permu FRAMEBLEND !!permu FRAMEBLEND