Better compat with mvdsv

Added -install arg to linux dedicated servers, to automatically install dependancies and updates.
Fix edge friction (at least when pm_edgefriction is 2 and not empty - can't break compat).
Added getchannellevel csqc builtin.



git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@5438 fc73d0e0-1445-4013-8a0c-d673dee63da5
This commit is contained in:
Spoike 2019-03-23 07:06:37 +00:00
parent a8b30e3008
commit ee9c9025a0
42 changed files with 921 additions and 479 deletions

View File

@ -1217,7 +1217,6 @@ static void CLQW_RecordServerData(sizebuf_t *buf, int *seq)
// send the serverdata
MSG_WriteByte (buf, svc_serverdata);
#ifdef PROTOCOL_VERSION_FTE
if (cls.fteprotocolextensions&~PEXT1_HIDEPROTOCOLS) //maintain demo compatability
{
MSG_WriteLong (buf, PROTOCOL_VERSION_FTE);
@ -1228,7 +1227,11 @@ static void CLQW_RecordServerData(sizebuf_t *buf, int *seq)
MSG_WriteLong (buf, PROTOCOL_VERSION_FTE2);
MSG_WriteLong (buf, cls.fteprotocolextensions2);
}
#endif
if (cls.ezprotocolextensions1)
{
MSG_WriteLong (buf, PROTOCOL_VERSION_EZQUAKE1);
MSG_WriteLong (buf, cls.ezprotocolextensions1);
}
MSG_WriteLong (buf, PROTOCOL_VERSION_QW);
MSG_WriteLong (buf, cl.servercount);
MSG_WriteString (buf, gamedirfile);

View File

@ -465,7 +465,7 @@ void CLQW_ParseDelta (entity_state_t *from, entity_state_t *to, int bits)
if (bits & U_ORIGIN3)
{
if (cls.ezprotocolextensions1 & EZPEXT1_FLOATENTCOORDS)
to->origin[1] = MSG_ReadCoordFloat ();
to->origin[2] = MSG_ReadCoordFloat ();
else
to->origin[2] = MSG_ReadCoord ();
}
@ -4592,7 +4592,12 @@ void CLQW_ParsePlayerinfo (void)
for (i = 0; i < 3; i++)
{
if (flags & (DF_ORIGINX << i))
state->origin[i] = MSG_ReadCoord ();
{
if (cls.ezprotocolextensions1 & EZPEXT1_FLOATENTCOORDS)
state->origin[i] = MSG_ReadCoordFloat ();
else
state->origin[i] = MSG_ReadCoord ();
}
}
VectorSubtract(state->origin, prevstate->origin, dist);

View File

@ -280,6 +280,7 @@ static struct
int subprotocol; //the monkeys are trying to eat me.
unsigned int fteext1;
unsigned int fteext2;
unsigned int ezext1;
int qport;
int challenge; //tracked as part of guesswork based upon what replies we get.
double time; //for connection retransmits
@ -456,28 +457,31 @@ void CL_ConnectToDarkPlaces(char *challenge, netadr_t *adr)
cl.splitclients = 0;
}
#ifdef PROTOCOL_VERSION_FTE
void CL_SupportedFTEExtensions(int *pext1, int *pext2)
void CL_SupportedFTEExtensions(unsigned int *pext1, unsigned int *pext2, unsigned int *ezpext1)
{
unsigned int fteprotextsupported = 0;
unsigned int fteprotextsupported1 = 0;
unsigned int fteprotextsupported2 = 0;
unsigned int ezprotextsupported1 = 0;
fteprotextsupported = Net_PextMask(1, false);
fteprotextsupported1 = Net_PextMask(1, false);
fteprotextsupported2 = Net_PextMask(2, false);
ezprotextsupported1 = Net_PextMask(3, false) & EZPEXT1_CLIENTADVERTISE;
fteprotextsupported &= strtoul(cl_pext_mask.string, NULL, 16);
fteprotextsupported1 &= strtoul(cl_pext_mask.string, NULL, 16);
// fteprotextsupported2 &= strtoul(cl_pext2_mask.string, NULL, 16);
// ezprotextsupported1 &= strtoul(cl_ezpext1_mask.string, NULL, 16);
if (cl_nopext.ival)
{
fteprotextsupported = 0;
fteprotextsupported1 = 0;
fteprotextsupported2 = 0;
ezprotextsupported1 = 0;
}
*pext1 = fteprotextsupported;
*pext1 = fteprotextsupported1;
*pext2 = fteprotextsupported2;
*ezpext1 = ezprotextsupported1;
}
#endif
char *CL_GUIDString(netadr_t *adr, const char *guidstring)
{
@ -550,9 +554,7 @@ called by CL_Connect_f and CL_CheckResend
======================
*/
void CL_SendConnectPacket (netadr_t *to, int mtu,
#ifdef PROTOCOL_VERSION_FTE
int ftepext, int ftepext2,
#endif
unsigned int ftepext1, unsigned int ftepext2, unsigned int ezpext1,
int compressioncrc,
const char *guidhash
/*, ...*/)
@ -562,10 +564,9 @@ void CL_SendConnectPacket (netadr_t *to, int mtu,
char data[2048];
char *info;
double t1, t2;
#ifdef PROTOCOL_VERSION_FTE
int fteprotextsupported=0;
int fteprotextsupported1=0;
int fteprotextsupported2=0;
#endif
int ezprotextsupported1=0;
char *a;
// JACK: Fixed bug where DNS lookups would cause two connects real fast
@ -580,31 +581,33 @@ void CL_SendConnectPacket (netadr_t *to, int mtu,
compressioncrc = 0;
}
#ifdef PROTOCOL_VERSION_FTE
#ifdef Q2CLIENT
if (connectinfo.protocol == CP_QUAKE2)
{
fteprotextsupported = ftepext & (PEXT_MODELDBL|PEXT_SOUNDDBL|PEXT_SPLITSCREEN);
fteprotextsupported1 = ftepext1 & (PEXT_MODELDBL|PEXT_SOUNDDBL|PEXT_SPLITSCREEN);
fteprotextsupported2 = 0;
ezprotextsupported1 = 0;
}
else
#endif
{
CL_SupportedFTEExtensions(&fteprotextsupported, &fteprotextsupported2);
CL_SupportedFTEExtensions(&fteprotextsupported1, &fteprotextsupported2, &ezprotextsupported1);
fteprotextsupported &= ftepext;
fteprotextsupported1 &= ftepext1;
fteprotextsupported2 &= ftepext2;
ezprotextsupported1 &= ezpext1;
if (connectinfo.protocol != CP_QUAKEWORLD)
{
fteprotextsupported = 0;
fteprotextsupported1 = 0;
fteprotextsupported2 = 0;
ezprotextsupported1 = 0;
}
}
connectinfo.fteext1 = fteprotextsupported;
connectinfo.fteext1 = fteprotextsupported1;
connectinfo.fteext2 = fteprotextsupported2;
#endif
connectinfo.ezext1 = ezprotextsupported1;
t1 = Sys_DoubleTime ();
@ -679,14 +682,13 @@ void CL_SendConnectPacket (netadr_t *to, int mtu,
Q_strncatz(data, "\n", sizeof(data));
#ifdef PROTOCOL_VERSION_FTE
if (ftepext)
Q_strncatz(data, va("0x%x 0x%x\n", PROTOCOL_VERSION_FTE, fteprotextsupported), sizeof(data));
#endif
#ifdef PROTOCOL_VERSION_FTE2
if (ftepext1)
Q_strncatz(data, va("0x%x 0x%x\n", PROTOCOL_VERSION_FTE, fteprotextsupported1), sizeof(data));
if (ftepext2)
Q_strncatz(data, va("0x%x 0x%x\n", PROTOCOL_VERSION_FTE2, fteprotextsupported2), sizeof(data));
#endif
if (ezpext1)
Q_strncatz(data, va("0x%x 0x%x\n", PROTOCOL_VERSION_EZQUAKE1, ezprotextsupported1), sizeof(data));
{
int ourmtu;
@ -786,6 +788,7 @@ void CL_CheckForResend (void)
connectinfo.subprotocol = PROTOCOL_VERSION_Q2;
connectinfo.fteext1 = PEXT_MODELDBL|PEXT_SOUNDDBL|PEXT_SPLITSCREEN;
connectinfo.fteext2 = 0;
connectinfo.ezext1 = 0;
break;
#endif
default:
@ -798,6 +801,7 @@ void CL_CheckForResend (void)
connectinfo.subprotocol = PROTOCOL_VERSION_QW;
connectinfo.fteext1 = Net_PextMask(1, false);
connectinfo.fteext2 = Net_PextMask(2, false);
connectinfo.ezext1 = Net_PextMask(3, false) & EZPEXT1_CLIENTADVERTISE;
}
else if (!strcmp(lbp, "qwid") || !strcmp(lbp, "idqw"))
{ //for recording .qwd files in any client
@ -805,6 +809,7 @@ void CL_CheckForResend (void)
connectinfo.subprotocol = PROTOCOL_VERSION_QW;
connectinfo.fteext1 = 0;
connectinfo.fteext2 = 0;
connectinfo.ezext1 = 0;
}
#ifdef Q3CLIENT
else if (!strcmp(lbp, "q3"))
@ -824,6 +829,7 @@ void CL_CheckForResend (void)
connectinfo.subprotocol = PROTOCOL_VERSION_QW;
connectinfo.fteext1 = Net_PextMask(1, false);
connectinfo.fteext2 = Net_PextMask(2, false);
connectinfo.ezext1 = Net_PextMask(3, false) & EZPEXT1_CLIENTADVERTISE;
}
}
else if (!strcmp(lbp, "fitz") || !strcmp(lbp, "rmqe") ||
@ -873,6 +879,7 @@ void CL_CheckForResend (void)
connectinfo.subprotocol = CPNQ_FITZ666;
connectinfo.fteext1 = Net_PextMask(1, true);
connectinfo.fteext2 = Net_PextMask(2, true);
connectinfo.ezext1 = Net_PextMask(3, false) & EZPEXT1_CLIENTADVERTISE;
}
#endif
else
@ -881,6 +888,7 @@ void CL_CheckForResend (void)
connectinfo.subprotocol = PROTOCOL_VERSION_QW;
connectinfo.fteext1 = Net_PextMask(1, false);
connectinfo.fteext2 = Net_PextMask(2, false);
connectinfo.ezext1 = Net_PextMask(3, false) & EZPEXT1_CLIENTADVERTISE;
}
#ifdef NETPREPARSE
@ -896,6 +904,7 @@ void CL_CheckForResend (void)
connectinfo.subprotocol = PROTOCOL_VERSION_QW;
connectinfo.fteext1 = Net_PextMask(1, false);
connectinfo.fteext2 = Net_PextMask(2, false);
connectinfo.ezext1 = Net_PextMask(3, false) & EZPEXT1_CLIENTADVERTISE;
}
else if (progstype != PROG_QW && cls.protocol == CP_QUAKEWORLD)
{
@ -911,6 +920,7 @@ void CL_CheckForResend (void)
connectinfo.subprotocol = PROTOCOL_VERSION_QW;
connectinfo.fteext1 = Net_PextMask(1, false);
connectinfo.fteext2 = Net_PextMask(2, false);
connectinfo.ezext1 = Net_PextMask(3, false) & EZPEXT1_CLIENTADVERTISE;
}
#ifdef NQPROT
else if (cls.demorecording == DPB_NETQUAKE && cls.protocol != CP_NETQUAKE)
@ -998,7 +1008,7 @@ void CL_CheckForResend (void)
{
if (!connectinfo.challenge)
connectinfo.challenge = rand();
CL_SendConnectPacket (NULL, 8192-16, connectinfo.fteext1, connectinfo.fteext2, 0, sv_guidhash.string);
CL_SendConnectPacket (NULL, 8192-16, connectinfo.fteext1, connectinfo.fteext2, connectinfo.ezext1, 0, sv_guidhash.string);
}
return;
@ -2271,6 +2281,8 @@ void CL_CheckServerInfo(void)
movevars.flyfriction = *s?Q_atof(s):4;
s = InfoBuf_ValueForKey(&cl.serverinfo, "pm_edgefriction");
movevars.edgefriction = *s?Q_atof(s):2;
if (!(movevars.flags&MOVEFLAG_VALID))
movevars.flags = (movevars.flags&~MOVEFLAG_QWEDGEBOX) | (*s?0:MOVEFLAG_QWEDGEBOX);
}
movevars.coordsize = cls.netchan.netprim.coordsize;
@ -3011,7 +3023,7 @@ void CL_ConnectionlessPacket (void)
static unsigned int lasttime = 0xdeadbeef;
static netadr_t lastadr;
unsigned int curtime = Sys_Milliseconds();
unsigned long pext = 0, pext2 = 0, huffcrc=0, mtu=0;
unsigned long ftepext1= 0, ftepext2 = 0, ezpext1 = 0, huffcrc=0, mtu=0;
#ifdef HAVE_DTLS
int candtls = 0; //0=no,1=optional,2=mandatory
#endif
@ -3050,7 +3062,7 @@ void CL_ConnectionlessPacket (void)
connectinfo.protocol = CP_QUAKE3;
connectinfo.challenge = atoi(s+17);
CL_SendConnectPacket (&net_from, 0, 0, 0, 0/*, ...*/, NULL);
CL_SendConnectPacket (&net_from, 0, 0, 0, 0, 0/*, ...*/, NULL);
}
else
{
@ -3197,8 +3209,9 @@ void CL_ConnectionlessPacket (void)
unsigned int l = MSG_ReadLong();
switch(cmd)
{
case PROTOCOL_VERSION_FTE: pext = l; break;
case PROTOCOL_VERSION_FTE2: pext2 = l; break;
case PROTOCOL_VERSION_FTE: ftepext1 = l; break;
case PROTOCOL_VERSION_FTE2: ftepext2 = l; break;
case PROTOCOL_VERSION_EZQUAKE1: ezpext1 = l; break;
case PROTOCOL_VERSION_FRAGMENT: mtu = l; break;
#ifdef HAVE_DTLS
case PROTOCOL_VERSION_DTLSUPGRADE: candtls = l; break; //0:not enabled. 1:explicit use allowed. 2:favour it. 3: require it
@ -3241,7 +3254,7 @@ void CL_ConnectionlessPacket (void)
}
#endif
CL_SendConnectPacket (&net_from, mtu, pext, pext2, huffcrc/*, ...*/, guidhash);
CL_SendConnectPacket (&net_from, mtu, ftepext1, ftepext2, ezpext1, huffcrc/*, ...*/, guidhash);
return;
}
#ifdef Q2CLIENT
@ -3473,6 +3486,7 @@ client_connect: //fixme: make function
cls.proquake_angles_hack = false;
cls.fteprotocolextensions = connectinfo.fteext1;
cls.fteprotocolextensions2 = connectinfo.fteext2;
cls.ezprotocolextensions1 = connectinfo.ezext1;
cls.challenge = connectinfo.challenge;
Netchan_Setup (NS_CLIENT, &cls.netchan, &net_from, connectinfo.qport);
if (cls.protocol == CP_QUAKE2)
@ -3671,7 +3685,7 @@ void CLNQ_ConnectionlessPacket(void)
cls.fteprotocolextensions = connectinfo.fteext1;
cls.fteprotocolextensions2 = connectinfo.fteext2;
cls.ezprotocolextensions1 = 0;
cls.ezprotocolextensions1 = connectinfo.ezext1;
Netchan_Setup (NS_CLIENT, &cls.netchan, &net_from, connectinfo.qport);
CL_ParseEstablished();
cls.netchan.isnqprotocol = true;
@ -5723,7 +5737,7 @@ double Host_Frame (double time)
#ifdef WEBCLIENT
// FTP_ClientThink();
HTTP_CL_Think();
HTTP_CL_Think(NULL, NULL);
#endif
if (r_blockvidrestart)

View File

@ -3093,7 +3093,6 @@ static void CLQW_ParseServerData (void)
// parse protocol version number
// allow 2.2 and 2.29 demos to play
#ifdef PROTOCOL_VERSION_FTE
cls.fteprotocolextensions = 0;
cls.fteprotocolextensions2 = 0;
cls.ezprotocolextensions1 = 0;
@ -3139,18 +3138,18 @@ static void CLQW_ParseServerData (void)
break;
Host_EndGame ("Server returned version %i, not %i\n", protover, PROTOCOL_VERSION_QW);
}
#else
protover = MSG_ReadLong ();
if (protover != PROTOCOL_VERSION_QW &&
!(cls.demoplayback && (protover >= 24 && protover <= 28)))
Host_EndGame ("Server returned version %i, not %i\n", protover, PROTOCOL_VERSION_QW);
#endif
if (developer.ival || cl_shownet.ival)
{
if (cls.fteprotocolextensions2||cls.fteprotocolextensions)
Con_TPrintf ("Using FTE extensions 0x%x%08x\n", cls.fteprotocolextensions2, cls.fteprotocolextensions);
if (cls.fteprotocolextensions2||cls.fteprotocolextensions||cls.ezprotocolextensions1)
Con_TPrintf ("Using FTE extensions 0x%x%08x %#x\n", cls.fteprotocolextensions2, cls.fteprotocolextensions, cls.ezprotocolextensions1);
}
if (cls.fteprotocolextensions & ~PEXT_CLIENTSUPPORT)
Con_TPrintf (CON_WARNING"Using unknown fte-pext1 extensions (%#x)\n", cls.fteprotocolextensions&~PEXT_CLIENTSUPPORT);
if (cls.fteprotocolextensions2 & ~PEXT2_CLIENTSUPPORT)
Con_TPrintf (CON_WARNING"Using unknown fte-pext2 extensions (%#x)\n", cls.fteprotocolextensions2&~PEXT2_CLIENTSUPPORT);
if (cls.ezprotocolextensions1 & ~EZPEXT1_CLIENTSUPPORT)
Con_TPrintf (CON_WARNING"Using unknown ezquake extensions (%#x)\n", cls.ezprotocolextensions1&~EZPEXT1_CLIENTSUPPORT);
if (cls.fteprotocolextensions & PEXT_FLOATCOORDS)
{
@ -3332,6 +3331,7 @@ static void CLQW_ParseServerData (void)
movevars.waterfriction = 1;
entgrav = 1;
}
movevars.flags = MOVEFLAG_QWCOMPAT;
for (clnum = 0; clnum < cl.splitclients; clnum++)
{
@ -3882,6 +3882,7 @@ static void CLNQ_SendInitialUserInfo(void *ctx, const char *key, const char *val
{
char keybuf[2048];
char valbuf[4096];
#warning FIXME: use CL_SendUserinfoUpdate or something
CL_SendClientCommand(true, "setinfo %s %s\n", COM_QuotedString(key, keybuf, sizeof(keybuf), false), COM_QuotedString(value, valbuf, sizeof(valbuf), false));
}
void CLNQ_SignonReply (void)
@ -5451,7 +5452,7 @@ static void CL_SetStatMovevar(int pnum, int stat, int ivalue, float value)
}
break;
case STAT_MOVEFLAGS:
// movevars.flags = ivalue;
movevars.flags = ivalue;
break;
case STAT_MOVEVARS_GRAVITY:
movevars.gravity = value;
@ -8358,4 +8359,4 @@ void CL_ShowTrafficUsage(float x, float y)
Draw_FunString(x, y, va("%22s:%5.1f%% (%.0f/s)", sorted[i].name, (100.0*sorted[i].bytes)/total, (sorted[i].bytes/packetusage_interval)));
y+=8;
}
}
}

View File

@ -13,17 +13,17 @@
#include "fs.h"
//whole load of extra args for the downloads menu (for the downloads menu to handle engine updates).
#ifdef VKQUAKE
#if defined(VKQUAKE) && !defined(SERVERONLY)
#define PHPVK "&vk=1"
#else
#define PHPVK
#endif
#ifdef GLQUAKE
#if defined(GLQUAKE) && !defined(SERVERONLY)
#define PHPGL "&gl=1"
#else
#define PHPGL
#endif
#ifdef D3DQUAKE
#if defined(D3DQUAKE) && !defined(SERVERONLY)
#define PHPD3D "&d3d=1"
#else
#define PHPD3D
@ -262,7 +262,7 @@ static void PM_FreePackage(package_t *p)
Z_Free(p);
}
qboolean PM_PurgeOnDisable(package_t *p)
static qboolean PM_PurgeOnDisable(package_t *p)
{
//corrupt packages must be purged
if (p->flags & DPF_CORRUPT)
@ -281,7 +281,7 @@ qboolean PM_PurgeOnDisable(package_t *p)
}
//checks the status of each package
void PM_ValidatePackage(package_t *p)
static void PM_ValidatePackage(package_t *p)
{
package_t *o;
struct packagedep_s *dep;
@ -631,8 +631,8 @@ static void PM_ParsePackageList(vfsfile_t *f, int parseflags, const char *url, c
char defaultgamedir[64];
char mirror[countof(p->mirror)][MAX_OSPATH];
int nummirrors = 0;
int argc;
qboolean isauto;
char *tokstart;
if (!f)
return;
@ -676,52 +676,61 @@ static void PM_ParsePackageList(vfsfile_t *f, int parseflags, const char *url, c
*sl = '\0';
while((sl=strchr(line, '\r')))
*sl = '\0';
Cmd_TokenizeString (line, false, false);
argc = Cmd_Argc();
if (argc)
tokstart = COM_StringParse (line, com_token, sizeof(com_token), false, false);
if (*com_token)
{
if (!strcmp(Cmd_Argv(0), "sublist"))
if (!strcmp(com_token, "sublist"))
{
char *subprefix;
char url[MAX_OSPATH];
tokstart = COM_StringParse (tokstart, url, sizeof(url), false, false);
tokstart = COM_StringParse (tokstart, com_token, sizeof(com_token), false, false);
if (*prefix)
subprefix = va("%s/%s", prefix, Cmd_Argv(2));
subprefix = va("%s/%s", prefix, com_token);
else
subprefix = Cmd_Argv(2);
PM_AddSubList(Cmd_Argv(1), subprefix, (parseflags & DPF_ENABLED)?true:false, (parseflags&DPF_TRUSTED));
subprefix = com_token;
PM_AddSubList(url, subprefix, (parseflags & DPF_ENABLED)?true:false, (parseflags&DPF_TRUSTED));
continue;
}
if (!strcmp(Cmd_Argv(0), "set"))
if (!strcmp(com_token, "set"))
{
if (!strcmp(Cmd_Argv(1), "gamedir"))
tokstart = COM_StringParse (tokstart, com_token, sizeof(com_token), false, false);
if (!strcmp(com_token, "gamedir"))
{
if (argc == 2)
tokstart = COM_StringParse (tokstart, com_token, sizeof(com_token), false, false);
if (!*com_token)
Q_strncpyz(defaultgamedir, FS_GetGamedir(false), sizeof(defaultgamedir));
else
Q_strncpyz(defaultgamedir, Cmd_Argv(2), sizeof(defaultgamedir));
Q_strncpyz(defaultgamedir, com_token, sizeof(defaultgamedir));
}
else if (!strcmp(Cmd_Argv(1), "mirrors"))
else if (!strcmp(com_token, "mirrors"))
{
nummirrors = 0;
while (nummirrors < countof(mirror) && 2+nummirrors < argc)
while (nummirrors < countof(mirror) && tokstart)
{
Q_strncpyz(mirror[nummirrors], Cmd_Argv(2+nummirrors), sizeof(mirror[nummirrors]));
if (!*mirror[nummirrors])
break;
nummirrors++;
tokstart = COM_StringParse (tokstart, com_token, sizeof(com_token), false, false);
if (*com_token)
{
Q_strncpyz(mirror[nummirrors], com_token, sizeof(mirror[nummirrors]));
nummirrors++;
}
}
}
else if (!strcmp(Cmd_Argv(1), "updatemode"))
else if (!strcmp(com_token, "updatemode"))
{
tokstart = COM_StringParse (tokstart, com_token, sizeof(com_token), false, false);
if (parseflags & DPF_ENABLED) //don't use a downloaded file's version of this, only use the local version of it.
Cvar_ForceSet(&pm_autoupdate, Cmd_Argv(2));
Cvar_ForceSet(&pm_autoupdate, com_token);
}
else if (!strcmp(Cmd_Argv(1), "declined"))
else if (!strcmp(com_token, "declined"))
{
if (parseflags & DPF_ENABLED) //don't use a downloaded file's version of this, only use the local version of it.
{
tokstart = COM_StringParse (tokstart, com_token, sizeof(com_token), false, false);
Z_Free(declinedpackages);
if (*Cmd_Argv(2))
declinedpackages = Z_StrDup(Cmd_Argv(2));
if (*com_token)
declinedpackages = Z_StrDup(com_token);
else
declinedpackages = NULL;
}
@ -733,183 +742,8 @@ static void PM_ParsePackageList(vfsfile_t *f, int parseflags, const char *url, c
continue;
}
isauto = false;
if (version > 1)
{
char pathname[256];
char *fullname = Cmd_Argv(0);
char *file = NULL;
char *url = NULL;
char *gamedir = NULL;
char *ver = NULL;
char *arch = NULL;
char *qhash = NULL;
char *title = NULL;
char *category = NULL;
char *description = NULL;
char *license = NULL;
char *author = NULL;
char *previewimage = NULL;
char *website = NULL;
int extract = EXTRACT_COPY;
int priority = PM_DEFAULTPRIORITY;
unsigned int flags = parseflags;
enum fs_relative fsroot = FS_ROOT;
int i;
if (version > 2)
flags &= ~DPF_ENABLED;
p = Z_Malloc(sizeof(*p));
for (i = 1; i < argc; i++)
{
char *arg = Cmd_Argv(i);
if (!strncmp(arg, "url=", 4))
url = arg+4;
else if (!strncmp(arg, "category=", 9))
category = arg+9;
else if (!strncmp(arg, "title=", 6))
title = arg+6;
else if (!strncmp(arg, "gamedir=", 8))
gamedir = arg+8;
else if (!strncmp(arg, "ver=", 4))
ver = arg+4;
else if (!strncmp(arg, "v=", 2))
ver = arg+2;
else if (!strncmp(arg, "arch=", 5))
arch = arg+5;
else if (!strncmp(arg, "priority=", 9))
priority = atoi(arg+9);
else if (!strncmp(arg, "qhash=", 6))
qhash = arg+6;
else if (!strncmp(arg, "desc=", 5))
description = arg+5;
else if (!strncmp(arg, "license=", 8))
license = arg+8;
else if (!strncmp(arg, "author=", 7))
author = arg+7;
else if (!strncmp(arg, "preview=", 8))
previewimage = arg+8;
else if (!strncmp(arg, "website=", 8))
website = arg+8;
else if (!strncmp(arg, "file=", 5))
{
if (!file)
file = arg+5; //for when url isn't explicitly given. assume the url to be the same as the file (relative to defined mirrors)
PM_AddDep(p, DEP_FILE, arg+5);
}
else if (!strncmp(arg, "extract=", 8))
{
if (!strcmp(arg+8, "xz"))
extract = EXTRACT_XZ;
else if (!strcmp(arg+8, "gz"))
extract = EXTRACT_GZ;
else if (!strcmp(arg+8, "zip"))
extract = EXTRACT_ZIP;
else
Con_Printf("Unknown decompression method: %s\n", arg+8);
}
else if (!strncmp(arg, "depend=", 7))
PM_AddDep(p, DEP_REQUIRE, arg+7);
else if (!strncmp(arg, "conflict=", 9))
PM_AddDep(p, DEP_CONFLICT, arg+9);
else if (!strncmp(arg, "fileconflict=", 13))
PM_AddDep(p, DEP_FILECONFLICT, arg+13);
else if (!strncmp(arg, "recommend=", 10))
PM_AddDep(p, DEP_RECOMMEND, arg+10);
else if (!strncmp(arg, "test=", 5))
flags |= DPF_TESTING;
else if (!strncmp(arg, "stale=", 6) && version==2)
flags &= ~DPF_ENABLED; //known about, (probably) cached, but not actually enabled.
else if (!strncmp(arg, "installed=", 6) && version>2)
flags |= parseflags & DPF_ENABLED;
else if (!strcmp(arg, "auto"))
isauto = true; //autoinstalled and NOT user-installed
else if (!strncmp(arg, "root=", 5) && (parseflags&DPF_ENABLED))
{
if (!Q_strcasecmp(arg+5, "bin"))
fsroot = FS_BINARYPATH;
else
fsroot = FS_ROOT;
}
else
{
Con_DPrintf("Unknown package property\n");
}
}
if (category)
{
p->name = Z_StrDup(fullname);
if (*prefix)
Q_snprintfz(pathname, sizeof(pathname), "%s/%s", prefix, category);
else
Q_snprintfz(pathname, sizeof(pathname), "%s", category);
if (*pathname)
{
if (pathname[strlen(pathname)-1] != '/')
Q_strncatz(pathname, "/", sizeof(pathname));
}
p->category = Z_StrDup(pathname);
}
else
{
if (*prefix)
Q_snprintfz(pathname, sizeof(pathname), "%s/%s", prefix, fullname);
else
Q_snprintfz(pathname, sizeof(pathname), "%s", fullname);
p->name = Z_StrDup(COM_SkipPath(pathname));
*COM_SkipPath(pathname) = 0;
p->category = Z_StrDup(pathname);
}
if (!title)
title = p->name;
if (!gamedir)
gamedir = defaultgamedir;
Q_strncpyz(p->version, ver?ver:"", sizeof(p->version));
Q_snprintfz(p->gamedir, sizeof(p->gamedir), "%s", gamedir);
p->fsroot = fsroot;
p->extract = extract;
p->priority = priority;
p->flags = flags;
p->title = Z_StrDup(title);
p->arch = arch?Z_StrDup(arch):NULL;
p->qhash = qhash?Z_StrDup(qhash):NULL;
p->description = description?Z_StrDup(description):NULL;
p->license = license?Z_StrDup(license):NULL;
p->author = author?Z_StrDup(author):NULL;
p->previewimage = previewimage?Z_StrDup(previewimage):NULL;
p->website = website?Z_StrDup(website):NULL;
if (url && (!strncmp(url, "http://", 7) || !strncmp(url, "https://", 8)))
p->mirror[0] = Z_StrDup(url);
else
{
int m;
char *ext = "";
if (!url)
{
if (extract == EXTRACT_XZ)
ext = ".xz";
else if (extract == EXTRACT_GZ)
ext = ".gz";
else if (extract == EXTRACT_ZIP)
ext = ".zip";
url = file;
}
if (url)
{
for (m = 0; m < nummirrors; m++)
p->mirror[m] = Z_StrDup(va("%s%s%s", mirror[m], url, ext));
}
}
}
else
#if 0
if (version < 2)
{
char pathname[256];
const char *fullname = Cmd_Argv(0);
@ -952,7 +786,217 @@ static void PM_ParsePackageList(vfsfile_t *f, int parseflags, const char *url, c
p->fsroot = FS_ROOT;
}
}
else
#endif
{
char pathname[256];
char *fullname = Z_StrDup(com_token);
char *file = NULL;
char *url = NULL;
char *gamedir = NULL;
char *ver = NULL;
char *arch = NULL;
char *qhash = NULL;
char *title = NULL;
char *category = NULL;
char *description = NULL;
char *license = NULL;
char *author = NULL;
char *previewimage = NULL;
char *website = NULL;
int extract = EXTRACT_COPY;
int priority = PM_DEFAULTPRIORITY;
unsigned int flags = parseflags;
enum fs_relative fsroot = FS_ROOT;
int i;
if (version > 2)
flags &= ~DPF_ENABLED;
p = Z_Malloc(sizeof(*p));
for (i = 1; tokstart; i++)
{
char key[8192];
char val[8192];
char *eq;
//the following are [\]["]key=["]value["] parameters, which is definitely messy, yes.
//skip leading whitespace
while (*tokstart>0 && *tokstart <= ' ')
tokstart++;
*val = 0;
if (*tokstart == '\\' || *tokstart == '\"')
{ //legacy quoting
tokstart = COM_StringParse (tokstart, key, sizeof(key), false, false);
eq = strchr(key, '=');
if (eq)
{
*eq = 0;
Q_strncpyz(val, eq+1, sizeof(val));
}
}
else
{
tokstart = COM_ParseTokenOut(tokstart, "=", key, sizeof(key), NULL);
if (!*key)
continue;
if (tokstart && *tokstart == '=')
{
tokstart++;
if (!(*tokstart >= 0 && *tokstart <= ' '))
tokstart = COM_ParseCString(tokstart, val, sizeof(val), NULL);
}
}
if (!strcmp(key, "url"))
Z_StrDupPtr(&url, val);
else if (!strcmp(key, "category"))
Z_StrDupPtr(&category, val);
else if (!strcmp(key, "title"))
Z_StrDupPtr(&title, val);
else if (!strcmp(key, "gamedir"))
Z_StrDupPtr(&gamedir, val);
else if (!strcmp(key, "ver") || !strcmp(key, "v"))
Z_StrDupPtr(&ver, val);
else if (!strcmp(key, "arch"))
Z_StrDupPtr(&arch, val);
else if (!strcmp(key, "priority"))
priority = atoi(val);
else if (!strcmp(key, "qhash"))
Z_StrDupPtr(&qhash, val);
else if (!strcmp(key, "desc") || !strcmp(key, "description"))
Z_StrDupPtr(&description, val);
else if (!strcmp(key, "license"))
Z_StrDupPtr(&license, val);
else if (!strcmp(key, "author"))
Z_StrDupPtr(&author, val);
else if (!strcmp(key, "preview"))
Z_StrDupPtr(&previewimage, val);
else if (!strcmp(key, "website"))
Z_StrDupPtr(&website, val);
else if (!strcmp(key, "file"))
{
if (!file)
Z_StrDupPtr(&file, val);
PM_AddDep(p, DEP_FILE, val);
}
else if (!strcmp(key, "extract"))
{
if (!strcmp(val, "xz"))
extract = EXTRACT_XZ;
else if (!strcmp(val, "gz"))
extract = EXTRACT_GZ;
else if (!strcmp(val, "zip"))
extract = EXTRACT_ZIP;
else
Con_Printf("Unknown decompression method: %s\n", val);
}
else if (!strcmp(key, "depend"))
PM_AddDep(p, DEP_REQUIRE, val);
else if (!strcmp(key, "conflict"))
PM_AddDep(p, DEP_CONFLICT, val);
else if (!strcmp(key, "fileconflict"))
PM_AddDep(p, DEP_FILECONFLICT, val);
else if (!strcmp(key, "recommend"))
PM_AddDep(p, DEP_RECOMMEND, val);
else if (!strcmp(key, "test"))
flags |= DPF_TESTING;
else if (!strcmp(key, "stale") && version==2)
flags &= ~DPF_ENABLED; //known about, (probably) cached, but not actually enabled.
else if (!strcmp(key, "installed") && version>2)
flags |= parseflags & DPF_ENABLED;
else if (!strcmp(key, "auto"))
isauto = true; //autoinstalled and NOT user-installed
else if (!strcmp(key, "root") && (parseflags&DPF_ENABLED))
{
if (!Q_strcasecmp(val, "bin"))
fsroot = FS_BINARYPATH;
else
fsroot = FS_ROOT;
}
else
{
Con_DPrintf("Unknown package property\n");
}
}
if (category)
{
p->name = fullname;
if (*prefix)
Q_snprintfz(pathname, sizeof(pathname), "%s/%s", prefix, category);
else
Q_snprintfz(pathname, sizeof(pathname), "%s", category);
if (*pathname)
{
if (pathname[strlen(pathname)-1] != '/')
Q_strncatz(pathname, "/", sizeof(pathname));
}
p->category = Z_StrDup(pathname);
}
else
{
if (*prefix)
Q_snprintfz(pathname, sizeof(pathname), "%s/%s", prefix, fullname);
else
Q_snprintfz(pathname, sizeof(pathname), "%s", fullname);
Z_Free(fullname);
p->name = Z_StrDup(COM_SkipPath(pathname));
*COM_SkipPath(pathname) = 0;
p->category = Z_StrDup(pathname);
}
if (!title)
title = Z_StrDup(p->name);
Q_strncpyz(p->version, ver?ver:"", sizeof(p->version));
Q_snprintfz(p->gamedir, sizeof(p->gamedir), "%s", gamedir?gamedir:defaultgamedir);
p->fsroot = fsroot;
p->extract = extract;
p->priority = priority;
p->flags = flags;
p->title = title;
p->arch = arch;
p->qhash = qhash;
p->description = description;
p->license = license;
p->author = author;
p->previewimage = previewimage;
p->website = website;
if (url && (!strncmp(url, "http://", 7) || !strncmp(url, "https://", 8)))
p->mirror[0] = Z_StrDup(url);
else
{
int m;
char *ext = "";
char *relurl = url;
if (!relurl)
{
if (extract == EXTRACT_XZ)
ext = ".xz";
else if (extract == EXTRACT_GZ)
ext = ".gz";
else if (extract == EXTRACT_ZIP)
ext = ".zip";
relurl = file;
}
if (relurl)
{
for (m = 0; m < nummirrors; m++)
p->mirror[m] = Z_StrDup(va("%s%s%s", mirror[m], relurl, ext));
}
}
Z_Free(ver);
Z_Free(file);
Z_Free(url);
Z_Free(gamedir);
Z_Free(category);
}
if (p->arch)
{
if (!Q_strcasecmp(p->arch, THISENGINE))
@ -964,7 +1008,7 @@ static void PM_ParsePackageList(vfsfile_t *f, int parseflags, const char *url, c
}
else if (!Q_strcasecmp(p->arch, THISARCH))
{
if ((p->fsroot == FS_ROOT || p->fsroot == FS_BINARYPATH) && !*p->gamedir)
if ((p->fsroot == FS_ROOT || p->fsroot == FS_BINARYPATH) && !*p->gamedir && p->priority == PM_DEFAULTPRIORITY)
p->flags |= DPF_PLUGIN;
}
else
@ -1232,12 +1276,12 @@ static package_t *PM_FindPackage(const char *packagename)
return r;
}
//returns the marked version of a package, if any.
static package_t *PM_MarkedPackage(const char *packagename)
static package_t *PM_MarkedPackage(const char *packagename, int markflag)
{
package_t *p;
for (p = availablepackages; p; p = p->next)
{
if (p->flags & DPF_MARKED)
if (p->flags & markflag)
if (!strcmp(p->name, packagename))
return p;
}
@ -1319,7 +1363,7 @@ static void PM_UnmarkPackage(package_t *package, unsigned int markflag)
{
if (dep->dtype == DEP_REQUIRE || dep->dtype == DEP_RECOMMEND)
{
package_t *d = PM_MarkedPackage(dep->name);
package_t *d = PM_MarkedPackage(dep->name, DPF_AUTOMARKED);
if (d && !(d->flags & DPF_USERMARKED))
{
if (!PM_HasDependant(d, DPF_MARKED))
@ -1343,7 +1387,7 @@ static void PM_MarkPackage(package_t *package, unsigned int markflag)
if (package->flags & DPF_MARKED)
{
package->flags |= markflag;
return; //looks like its already picked.
return; //looks like its already picked. marking it again will do no harm.
}
//any file-conflicts prevent the package from being installable.
@ -1410,7 +1454,7 @@ static void PM_MarkPackage(package_t *package, unsigned int markflag)
{
if (dep->dtype == DEP_REQUIRE || dep->dtype == DEP_RECOMMEND)
{
package_t *d = PM_MarkedPackage(dep->name);
package_t *d = PM_MarkedPackage(dep->name, DPF_MARKED);
if (!d)
{
d = PM_FindPackage(dep->name);
@ -1424,7 +1468,7 @@ static void PM_MarkPackage(package_t *package, unsigned int markflag)
{
for (;;)
{
package_t *d = PM_MarkedPackage(dep->name);
package_t *d = PM_MarkedPackage(dep->name, DPF_MARKED);
if (!d)
break;
PM_UnmarkPackage(d, DPF_MARKED);
@ -1455,7 +1499,7 @@ static qboolean PM_NameIsInStrings(const char *strings, const char *match)
}
//just flag stuff as needing updating
static unsigned int PM_MarkUpdates (void)
unsigned int PM_MarkUpdates (void)
{
unsigned int changecount = 0;
package_t *p, *o, *b, *e = NULL;
@ -1470,7 +1514,7 @@ static unsigned int PM_MarkUpdates (void)
if (PM_NameIsInStrings(declinedpackages, tok))
continue;
p = PM_MarkedPackage(tok);
p = PM_MarkedPackage(tok, DPF_MARKED);
if (!p)
{
p = PM_FindPackage(tok);
@ -1612,7 +1656,6 @@ static void PM_PrintChanges(void)
Con_Printf("<%i package(s) changed>\n", changes);
}
static void PM_ApplyChanges(void);
#ifdef WEBCLIENT
static void PM_ListDownloaded(struct dl_download *dl)
{
@ -1715,7 +1758,7 @@ static void PM_UpdatePackageList(qboolean autoupdate, int retry)
//make sure our sources are okay.
if (*pm_downloads_url.string)
PM_AddSubList(pm_downloads_url.string, "", true, true);
PM_AddSubList(pm_downloads_url.string, "", false, true);
#ifndef WEBCLIENT
for (i = 0; i < numdownloadablelists; i++)
@ -1790,7 +1833,7 @@ static void COM_QuotedConcat(const char *cat, char *buf, size_t bufsize)
}
static void PM_WriteInstalledPackages(void)
{
char buf[8192];
char buf[65536];
int i;
char *s;
package_t *p, *e = NULL;
@ -2404,7 +2447,7 @@ static void PM_StartADownload(void)
#endif
}
//'just' starts doing all the things needed to remove/install selected packages
static void PM_ApplyChanges(void)
void PM_ApplyChanges(void)
{
package_t *p, **link;
char temp[MAX_OSPATH];
@ -2574,7 +2617,7 @@ static qboolean PM_DeclinedPackages(char *out, size_t outsize)
if (PM_NameIsInStrings(declinedpackages, tok))
continue;
p = PM_MarkedPackage(tok);
p = PM_MarkedPackage(tok, DPF_MARKED);
if (p) //don't mark it as declined if it wasn't
continue;
@ -2738,7 +2781,7 @@ void PM_Command_f(void)
if (p->flags & DPF_PURGE)
status = S_COLOR_CYAN"<reinstall>";
else
status = S_COLOR_CYAN"<install>";
status = S_COLOR_CYAN"<inst all>";
}
else if ((p->flags & DPF_PURGE) || !(p->qhash && (p->flags & DPF_CACHED)))
status = S_COLOR_CYAN"<uninstall>";
@ -2747,10 +2790,14 @@ void PM_Command_f(void)
}
else if ((p->flags & (DPF_ENABLED|DPF_CACHED)) == DPF_CACHED)
status = S_COLOR_CYAN"<disabled>";
else if (p->flags & DPF_USERMARKED)
status = S_COLOR_GRAY"<manual>";
else if (p->flags & DPF_AUTOMARKED)
status = S_COLOR_GRAY"<auto>";
else
status = "";
Con_Printf(" ^[%s%s%s%s^] %s^9 %s (%s%s)\n", markup, p->name, p->arch?":":"", p->arch?p->arch:"", status, strcmp(p->name, p->title)?p->title:"", p->version, (p->flags&DPF_TESTING)?"-testing":"");
Con_Printf(" ^["S_COLOR_GRAY"%s%s%s%s%s^] %s"S_COLOR_GRAY" %s (%s%s)\n", p->category?p->category:"", markup, p->name, p->arch?":":"", p->arch?p->arch:"", status, strcmp(p->name, p->title)?p->title:"", p->version, (p->flags&DPF_TESTING)?"-testing":"");
}
Con_Printf("<end of list>\n");
}
@ -2831,7 +2878,7 @@ void PM_Command_f(void)
}
Con_Printf("<end of list>\n");
}
else if (!strcmp(act, "sources") || !strcmp(act, "addsources"))
else if (!strcmp(act, "sources") || !strcmp(act, "addsource"))
{
if (Cmd_Argc() == 2)
{
@ -2908,13 +2955,13 @@ void PM_Command_f(void)
}
PM_PrintChanges();
}
else if (!strcmp(act, "disable") || !strcmp(act, "rem"))
else if (!strcmp(act, "disable") || !strcmp(act, "rem") || !strcmp(act, "remove"))
{
int arg = 2;
for (arg = 2; arg < Cmd_Argc(); arg++)
{
const char *key = Cmd_Argv(arg);
p = PM_MarkedPackage(key);
p = PM_MarkedPackage(key, DPF_MARKED);
if (!p)
p = PM_FindPackage(key);
if (p)
@ -2930,7 +2977,7 @@ void PM_Command_f(void)
for (arg = 2; arg < Cmd_Argc(); arg++)
{
const char *key = Cmd_Argv(arg);
p = PM_MarkedPackage(key);
p = PM_MarkedPackage(key, DPF_MARKED);
if (!p)
p = PM_FindPackage(key);
if (p)
@ -2944,7 +2991,7 @@ void PM_Command_f(void)
PM_PrintChanges();
}
else
Con_Printf("%s: Unknown action %s\nShould be one of list, show, search, upgrade, revert, add, rem, del, changes, apply\n", Cmd_Argv(0), act);
Con_Printf("%s: Unknown action %s\nShould be one of list, show, search, upgrade, revert, add, rem, del, changes, apply, sources, addsource, remsource\n", Cmd_Argv(0), act);
}
qboolean PM_FindUpdatedEngine(char *syspath, size_t syspathsize)
@ -3570,6 +3617,9 @@ void Menu_Download_Update(void)
#else
void Menu_Download_Update(void)
{
#ifdef PACKAGEMANAGER
PM_UpdatePackageList(true, 2);
#endif
}
void Menu_DownloadStuff_f (void)
{

View File

@ -291,6 +291,7 @@ void M_Menu_Options_f (void)
NULL
};
extern cvar_t cfg_save_auto;
menubulk_t bulk[] = {
MB_CONSOLECMD("Customize controls", "menu_keys\n", "Modify keyboard and mouse inputs."),
#ifdef PACKAGEMANAGER
@ -299,6 +300,7 @@ void M_Menu_Options_f (void)
MB_CONSOLECMD("Go to console", "toggleconsole\nplay misc/menu2.wav\n", "Open up the engine console."),
MB_CONSOLECMD("Reset to defaults", "cvarreset *\nexec default.cfg\nplay misc/menu2.wav\n", "Reloads the default configuration."),
MB_CONSOLECMD("Save all settings", "cfg_save\n", "Writes changed settings out to a config file."),
MB_CHECKBOXCVARTIP("Auto-save Settings", cfg_save_auto, 1, "If this is disabled, you will need to explicitly save your settings."),
MB_SPACING(4),
MB_COMBOCVAR("View Projection", r_projection, projections, projectionvalues, NULL),
MB_COMBOCVAR("FOV Mode", scr_fov_mode, fovmodes, fovmodevalues, NULL),
@ -1004,6 +1006,7 @@ static void ApplyPreset (int presetnum)
void M_Menu_Preset_f (void)
{
extern cvar_t cfg_save_auto;
menu_t *menu;
int y;
menubulk_t bulk[] =
@ -1019,6 +1022,8 @@ void M_Menu_Preset_f (void)
#ifdef RTLIGHTS
MB_CONSOLECMD("realtime (all on)", "fps_preset realtime;menupop\n", "For people who value pretty over fast/smooth. Not viable for deathmatch."),
#endif
MB_SPACING(16),
MB_CHECKBOXCVARTIP("Auto-save Settings", cfg_save_auto, 1, "If this is disabled, you will need to explicitly save your settings."),
MB_END()
};
static menuresel_t resel;

View File

@ -4131,6 +4131,13 @@ void QCBUILTIN PF_getsoundtime (pubprogfuncs_t *prinst, struct globalvars_s *pr_
G_FLOAT(OFS_RETURN) = S_GetSoundTime(-entity->entnum, channel);
}
void QCBUILTIN PF_getchannellevel (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
wedict_t *entity = G_WEDICT(prinst, OFS_PARM0);
int channel = G_FLOAT(OFS_PARM1);
G_FLOAT(OFS_RETURN) = S_GetChannelLevel(-entity->entnum, channel);
}
static void QCBUILTIN PF_cs_sound(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
const char *sample;
@ -6740,6 +6747,7 @@ static struct {
{"stopsound", PF_stopsound, 0},
{"soundupdate", PF_soundupdate, 0},
{"getsoundtime", PF_getsoundtime, 533},
{"getchannellevel", PF_getchannellevel, 0},
{"soundlength", PF_soundlength, 534},
{"buf_loadfile", PF_buf_loadfile, 535},
{"buf_writefile", PF_buf_writefile, 536},
@ -7414,6 +7422,7 @@ qboolean CSQC_Init (qboolean anycsqc, const char *csprogsname, unsigned int chec
movevars.edgefriction = 2;//*pm_edgefriction.string?pm_edgefriction.value:2;
movevars.stepheight = PM_DEFAULTSTEPHEIGHT;
movevars.coordsize = 4;
movevars.flags = MOVEFLAG_NOGRAVITYONGROUND;
}
for (i = 0; i < sizeof(csqc_builtin)/sizeof(csqc_builtin[0]); i++)

View File

@ -583,6 +583,21 @@ static qboolean OpenAL_ReclaimASource(soundcardinfo_t *sc)
return success;
}
//for querying sound offsets (for various hacks).
static ssamplepos_t OpenAL_GetChannelPos(soundcardinfo_t *sc, channel_t *chan)
{
ALint spos = 0;
oalinfo_t *oali = sc->handle;
int chnum = chan - sc->channel;
ALuint src;
src = oali->source[chnum];
if (!src)
return (ssamplepos_t)(~(usamplepos_t)0)>>1; //not actually playing...
palGetSourcei(src, AL_SAMPLE_OFFSET, &spos);
return spos;
}
//schanged says the sample has changed, otherwise its merely moved around a little, maybe changed in volume, but nothing that will restart it.
static void OpenAL_ChannelUpdate(soundcardinfo_t *sc, channel_t *chan, unsigned int schanged)
{
@ -1361,6 +1376,7 @@ static qboolean QDECL OpenAL_InitCard(soundcardinfo_t *sc, const char *devname)
#endif
sc->ChannelUpdate = OpenAL_ChannelUpdate;
sc->ListenerUpdate = OpenAL_ListenerUpdate;
sc->GetChannelPos = OpenAL_GetChannelPos;
//these are stubs for our software mixer, and are not used with hardware mixing.
sc->Lock = OpenAL_LockBuffer;
sc->Unlock = OpenAL_UnlockBuffer;

View File

@ -3053,7 +3053,55 @@ float S_GetSoundTime(int entnum, int entchannel)
{
if (sc->channel[i].entnum == entnum && sc->channel[i].entchannel == entchannel && sc->channel[i].sfx)
{
result = (sc->channel[i].pos>>PITCHSHIFT) / (float)snd_speed; //the time into the sound, ignoring play rate.
ssamplepos_t spos = sc->GetChannelPos?sc->GetChannelPos(sc, &sc->channel[i]):(sc->channel[i].pos>>PITCHSHIFT);
result = spos / (float)snd_speed; //the time into the sound, ignoring play rate.
break;
}
}
//we found one on this sound device card, ignore others.
if (result != -1)
break;
}
S_UnlockMixer();
return result;
}
float S_GetChannelLevel(int entnum, int entchannel)
{
int i, j;
float result = -1; //if we didn't find one
soundcardinfo_t *sc;
sfxcache_t scachebuf, *scache;
S_LockMixer();
for (sc = sndcardinfo; sc && result == -1; sc = sc->next)
{
for (i = 0; i < sc->total_chans; i++)
{
if (sc->channel[i].entnum == entnum && sc->channel[i].entchannel == entchannel && sc->channel[i].sfx)
{
ssamplepos_t spos = sc->GetChannelPos?sc->GetChannelPos(sc, &sc->channel[i]):(sc->channel[i].pos>>PITCHSHIFT);
scache = sc->channel[i].sfx->decoder.decodedata(sc->channel[i].sfx, &scachebuf, spos, 1);
if (!scache)
scache = sc->channel[i].sfx->decoder.buf;
if (scache && spos >= scache->soundoffset && spos < scache->soundoffset+scache->length)
{
spos -= scache->soundoffset;
spos *= scache->numchannels;
switch(scache->width)
{
case 1:
for (j = 0; j < scache->numchannels; j++) //average the channels
result += abs(((signed char*)scache->data)[spos+j]);
result /= scache->numchannels*127.0;
break;
case 2:
for (j = 0; j < scache->numchannels; j++) //average the channels
result += abs(((signed short*)scache->data)[spos+j]);
result /= scache->numchannels*32767.0;
break;
}
}
else
result = 0;
break;
}
}

View File

@ -187,6 +187,7 @@ void S_Startup (void);
void S_EnumerateDevices(void);
void S_Shutdown (qboolean final);
float S_GetSoundTime(int entnum, int entchannel);
float S_GetChannelLevel(int entnum, int entchannel);
void S_StartSound (int entnum, int entchannel, sfx_t *sfx, vec3_t origin, vec3_t velocity, float fvol, float attenuation, float timeofs, float pitchadj, unsigned int flags);
float S_UpdateSound(int entnum, int entchannel, sfx_t *sfx, vec3_t origin, vec3_t velocity, float fvol, float attenuation, float timeofs, float pitchadj, unsigned int flags);
void S_StaticSound (sfx_t *sfx, vec3_t origin, float vol, float attenuation);
@ -376,6 +377,7 @@ struct soundcardinfo_s { //windows has one defined AFTER directsound
void (*Restore) (soundcardinfo_t *sc); //called before lock/unlock/lock/unlock/submit. optional
void (*ChannelUpdate) (soundcardinfo_t *sc, channel_t *channel, unsigned int schanged); //properties of a sound effect changed. this is to notify hardware mixers. optional.
void (*ListenerUpdate) (soundcardinfo_t *sc, int entnum, vec3_t origin, vec3_t forward, vec3_t right, vec3_t up, vec3_t velocity); //player moved or something. this is to notify hardware mixers. optional.
ssamplepos_t (*GetChannelPos) (soundcardinfo_t *sc, channel_t *channel); //queries a hardware mixer's channel position (essentially returns channel->pos, except more up to date)
//driver-specific - if you need more stuff, you should just shove it in the handle pointer
void *thread;

View File

@ -491,6 +491,14 @@ void Sys_ServerActivity(void)
{
/*FIXME: flash window*/
}
#ifdef WEBCLIENT
qboolean Sys_RunInstaller(void)
{ //not implemented
return false;
}
#endif
#ifndef MULTITHREAD
void Sys_Sleep (double seconds)
{

View File

@ -1126,3 +1126,10 @@ qboolean Sys_RandomBytes(qbyte *string, int len)
return res;
}
#ifdef WEBCLIENT
qboolean Sys_RunInstaller(void)
{
return false;
}
#endif

View File

@ -3316,8 +3316,8 @@ BOOL CopyFileU(const char *src, const char *dst, BOOL bFailIfExists)
return CopyFileW(widen(wide1, sizeof(wide1), src), widen(wide2, sizeof(wide2), dst), bFailIfExists);
}
void FS_CreateBasedir(const char *path);
qboolean Sys_DoInstall(void)
#ifdef WEBCLIENT
static qboolean Sys_DoInstall(void)
{
extern ftemanifest_t *fs_manifest;
char exepath[MAX_OSPATH];
@ -3416,7 +3416,7 @@ qboolean Sys_DoInstall(void)
SendMessage(progress, PBM_SETRANGE32, 0, 10000);
*fname = 0;
HTTP_CL_Think();
HTTP_CL_Think(NULL, NULL);
while(FS_DownloadingPackage())
{
MSG msg;
@ -3447,7 +3447,7 @@ qboolean Sys_DoInstall(void)
DispatchMessage (&msg);
Sleep(10);
HTTP_CL_Think();
HTTP_CL_Think(NULL, NULL);
}
DestroyWindow(progress);
DestroyWindow(wnd);
@ -3511,6 +3511,7 @@ qboolean Sys_RunInstaller(void)
}
return true;
}
#endif
#define RESLANG MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_UK)
static const char *Sys_FindManifest(void)

View File

@ -1946,7 +1946,7 @@ void R_DrawNameTags(void)
if (body)
{
// Q_snprintfz(fname, sizeof(fname), "<default shader>");
str = va("^2%s^7\n%s\n{%s\n", fname, surf->texinfo->texture->name, body);
str = va("^2%s^7\n%s%s\n{%s\n", fname, ruleset_allow_shaders.ival?"":CON_ERROR"WARNING: ruleset_allow_shaders disables external shaders"CON_DEFAULT"\n", surf->texinfo->texture->name, body);
Z_Free(body);
}
else

View File

@ -532,6 +532,8 @@ qbyte *W_GetTexture(const char *name, int *width, int *height, uploadfmt_t *form
}
return data;
}
else if (lumptype == TYP_HLFONT)
; //FIXME... gah
else
Con_Printf("W_GetTexture: unknown lump type\n");
}

View File

@ -2623,14 +2623,24 @@ static void Cmd_ForwardToServer_f (void)
if (Q_strcasecmp(Cmd_Argv(1), "pext") == 0 && (cls.protocol != CP_NETQUAKE || cls.fteprotocolextensions2 || cls.protocol_nq != CPNQ_ID || cls.proquake_angles_hack || cls.netchan.remote_address.type != NA_LOOPBACK))
{ //don't send any extension flags this if we're using cl_loopbackprotocol nqid, purely for a compat test.
//if you want to record compat-demos, disable extensions instead.
unsigned int fp1 = Net_PextMask(1, cls.protocol == CP_NETQUAKE), fp2 = Net_PextMask(2, cls.protocol == CP_NETQUAKE);
unsigned int fp1 = Net_PextMask(1, cls.protocol == CP_NETQUAKE),
fp2 = Net_PextMask(2, cls.protocol == CP_NETQUAKE),
ez1 = Net_PextMask(3, cls.protocol == CP_NETQUAKE) & EZPEXT1_CLIENTADVERTISE;
extern cvar_t cl_nopext;
char line[256];
if (cl_nopext.ival)
{
fp1 = 0;
fp2 = 0;
}
CL_SendClientCommand(true, "pext %#x %#x %#x %#x", PROTOCOL_VERSION_FTE, fp1, PROTOCOL_VERSION_FTE2, fp2);
Q_strncpyz(line, "pext", sizeof(line));
if (fp1)
Q_strncatz(line, va(" %#x %#x", PROTOCOL_VERSION_FTE, fp1), sizeof(line));
if (fp2)
Q_strncatz(line, va(" %#x %#x", PROTOCOL_VERSION_FTE2, fp2), sizeof(line));
if (ez1)
Q_strncatz(line, va(" %#x %#x", PROTOCOL_VERSION_EZQUAKE1, ez1), sizeof(line));
CL_SendClientCommand(true, "%s", line);
return;
}
if (Q_strcasecmp(Cmd_Argv(1), "ptrack") == 0)

View File

@ -2870,7 +2870,7 @@ static void Mod_GenerateMeshVBO(model_t *mod, galiasinfo_t *galias)
BE_VBO_Data(&vboctx, galias->ofs_skel_svect, sizeof(*galias->ofs_skel_svect) * galias->numverts, &galias->vbo_skel_svector);
if (galias->ofs_skel_tvect)
BE_VBO_Data(&vboctx, galias->ofs_skel_tvect, sizeof(*galias->ofs_skel_tvect) * galias->numverts, &galias->vbo_skel_tvector);
if (!galias->mappedbones /*&& galias->numbones > sh_config.max_gpu_bones*/ && galias->ofs_skel_idx)
if (!galias->mappedbones && galias->numbones > sh_config.max_gpu_bones && galias->ofs_skel_idx && sh_config.max_gpu_bones)
{ //if we're using gpu bones, then its possible that we're trying to load a model with more bones than the gpu supports
//to work around this (and get performance back), each surface has a gpu->cpu table so that bones not used on a mesh don't cause it to need to use a software fallback
qboolean *seen = alloca(sizeof(*seen) * galias->numbones);
@ -2898,6 +2898,8 @@ static void Mod_GenerateMeshVBO(model_t *mod, galiasinfo_t *galias)
galias->bonemap[galias->mappedbones++] = j;
}
}
else
Con_DPrintf("\"%s\":\"%s\" exceeds gpu bone limit and will be software-skinned - %i > %i\n", mod->name, galias->surfacename, k, sh_config.max_gpu_bones);
}
if (galias->mappedbones)
{

View File

@ -3996,9 +3996,6 @@ char *COM_StringParse (const char *data, char *token, unsigned int tokenlen, qbo
len = 0;
token[0] = 0;
if (token == com_token)
COM_AssertMainThread("COM_ParseOut: com_token");
if (!data)
return NULL;

View File

@ -693,6 +693,7 @@ qboolean PM_CanInstall(const char *packagename);
void COM_InitFilesystem (void); //does not set up any gamedirs.
qboolean FS_DownloadingPackage(void);
void FS_CreateBasedir(const char *path);
qboolean FS_ChangeGame(ftemanifest_t *newgame, qboolean allowreloadconfigs, qboolean allowbasedirchange);
void FS_Shutdown(void);
struct gamepacks

View File

@ -88,6 +88,8 @@ extern conchar_t q3codemasks[MAXQ3COLOURS];
#define S_COLOR_CYAN "^5"
#define S_COLOR_MAGENTA "^6"
#define S_COLOR_WHITE "^7"
#define S_COLOR_TRANS "^8"
#define S_COLOR_GRAY "^9"
#define CON_DEFAULT "^&--"
#define CON_WARNING "^&E0"

View File

@ -74,6 +74,8 @@ void FS_AddHashedPackage(searchpath_t **oldpaths, const char *parent_pure, const
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));
int PM_IsApplying(qboolean listsonly);
unsigned int PM_MarkUpdates (void); //mark new/updated packages as needing install.
void PM_ApplyChanges(void); //for -install/-doinstall args
void PM_ManifestPackage(const char *name, int security);
qboolean PM_FindUpdatedEngine(char *syspath, size_t syspathsize); //names the engine we should be running
void Menu_Download_Update(void);

View File

@ -233,6 +233,10 @@ unsigned int Net_PextMask(int maskset, qboolean fornq)
// else
// mask &= ~PEXT2_PREDINFO;
}
else if (maskset == 3)
{
mask = EZPEXT1_FLOATENTCOORDS|EZPEXT1_SETANGLEREASON;
}
return mask;
}

View File

@ -528,10 +528,10 @@ void PM_Friction (void)
//id quirk: this is a tracebox, NOT a traceline, yet still starts BELOW the player.
start[2] = pmove.origin[2] + pmove.player_mins[2];
stop[2] = start[2] - 34;
if (movevars_dpflags & MOVEFLAG_QWEDGEBOX) //quirky qw behaviour uses a tracebox, which
if (movevars.flags & MOVEFLAG_QWEDGEBOX) //vanilla qw behaviour is to use a tracebox, which makes edge friction almost unnoticable.
trace = PM_PlayerTrace (start, stop, MASK_PLAYERSOLID);
else
{
{ //traceline instead.
vec3_t min, max;
VectorCopy(pmove.player_mins, min);
VectorCopy(pmove.player_maxs, max);

View File

@ -132,7 +132,7 @@ typedef struct {
#define MOVEFLAG_NOGRAVITYONGROUND 0x00000002 //no slope sliding
#define MOVEFLAG_GRAVITYUNAFFECTEDBYTICRATE 0x00000004 //apply half-gravity both before AND after the move, which better matches the curve
#define MOVEFLAG_QWEDGEBOX 0x00010000 //calculate edgefriction using tracebox and a buggy start pos
#define MOVEFLAG_QWCOMPAT (MOVEFLAG_VALID|MOVEFLAG_NOGRAVITYONGROUND|MOVEFLAG_QWEDGEBOX)
#define MOVEFLAG_QWCOMPAT (MOVEFLAG_NOGRAVITYONGROUND|MOVEFLAG_QWEDGEBOX)
extern movevars_t movevars;
extern playermove_t pmove;

View File

@ -23,9 +23,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#define PEXT_SCALE 0x00000002
#define PEXT_LIGHTSTYLECOL 0x00000004
#define PEXT_TRANS 0x00000008
#ifdef SIDEVIEWS
#define PEXT_VIEW2 0x00000010
#endif
#define PEXT_VIEW2_ 0x00000010
//#define PEXT_BULLETENS 0x00000020 //obsolete
#define PEXT_ACCURATETIMINGS 0x00000040
#define PEXT_SOUNDDBL 0x00000080 //revised startsound protocol
@ -55,18 +53,21 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#define PEXT_CHUNKEDDOWNLOADS 0x20000000 //alternate file download method. Hopefully it'll give quadroupled download speed, especially on higher pings.
#define PEXT_CSQC 0x40000000 //csqc additions
#define PEXT_DPFLAGS 0x80000000 //extra flags for viewmodel/externalmodel and possible other persistant style flags.
#define PEXT_CLIENTSUPPORT (PEXT_SETVIEW|PEXT_SCALE|PEXT_LIGHTSTYLECOL|PEXT_TRANS|PEXT_VIEW2_|PEXT_ACCURATETIMINGS|PEXT_SOUNDDBL|PEXT_FATNESS|PEXT_HLBSP|PEXT_TE_BULLET|PEXT_HULLSIZE|PEXT_MODELDBL|PEXT_ENTITYDBL|PEXT_ENTITYDBL2|PEXT_FLOATCOORDS|PEXT_Q2BSP_|PEXT_Q3BSP_|PEXT_COLOURMOD|PEXT_SPLITSCREEN|PEXT_HEXEN2|PEXT_SPAWNSTATIC2|PEXT_CUSTOMTEMPEFFECTS|PEXT_256PACKETENTITIES|PEXT_SHOWPIC|PEXT_SETATTACHMENT|PEXT_CHUNKEDDOWNLOADS|PEXT_CSQC|PEXT_DPFLAGS)
#ifdef CSQC_DAT
#define PEXT_BIGUSERINFOS PEXT_CSQC //FIXME: while useful for csqc, we should include something else that isn't so often stripped, or is available in ezquake, or something.
#define PEXT_BIGUSERINFOS PEXT_CSQC //FIXME: while useful for csqc, we should include something else that isn't so often stripped, or is available in ezquake, or something.
#else
#define PEXT_BIGUSERINFOS 0xffffffff
#define PEXT_BIGUSERINFOS 0xffffffff
#endif
#ifdef SIDEVIEWS
#define PEXT_VIEW2 PEXT_VIEW2_
#endif
#ifdef Q2BSPS
#define PEXT_Q2BSP PEXT_Q2BSP_
#define PEXT_Q2BSP PEXT_Q2BSP_
#endif
#ifdef Q3BSPS
#define PEXT_Q3BSP PEXT_Q3BSP_
#define PEXT_Q3BSP PEXT_Q3BSP_
#endif
#define PEXT1_HIDEPROTOCOLS (PEXT_Q3BSP_|PEXT_Q2BSP_|PEXT_HLBSP) //These are hints for the server, and not useful to the client (they can figure stuff out themselves)
@ -78,10 +79,14 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#define PEXT2_PREDINFO 0x00000020 //movevar stats, NQ input sequences+acks.
#define PEXT2_NEWSIZEENCODING 0x00000040 //richer size encoding.
#define PEXT2_INFOBLOBS 0x00000080 //serverinfo+userinfo lengths can be MUCH higher (protocol is unbounded, but expect low sanity limits on userinfo), and contain nulls etc.
#define PEXT2_CLIENTSUPPORT (PEXT2_PRYDONCURSOR|PEXT2_VOICECHAT|PEXT2_SETANGLEDELTA|PEXT2_REPLACEMENTDELTAS|PEXT2_MAXPLAYERS|PEXT2_PREDINFO|PEXT2_NEWSIZEENCODING|PEXT2_INFOBLOBS)
//EzQuake/Mvdsv extensions
#define EZPEXT1_FLOATENTCOORDS 0x00000001 //quirky - doesn't apply to broadcasts, just players+ents. this gives more precision, but will bug out if you try using it to increase map bounds in ways that may not be immediately apparent. iiuc this was added instead of fixing some inconsistent rounding...
#define EZPEXT1_SETANGLEREASON 0x00000002 //specifies the reason for an svc_setangles call. the mvdsv implementation will fuck over any mods that writebyte them. we'd need to modify our preparse stuff to work around the issue.
#define EZPEXT1_SERVERADVERTISE 0
#define EZPEXT1_CLIENTADVERTISE 0 //
#define EZPEXT1_CLIENTSUPPORT (EZPEXT1_FLOATENTCOORDS|EZPEXT1_SETANGLEREASON) //ones we can support in demos. warning if other bits.
//ZQuake transparent protocol extensions.
#define Z_EXT_PM_TYPE (1<<0) // basic PM_TYPE functionality (reliable jump_held)

View File

@ -126,12 +126,22 @@ qboolean QVM_LoadDLL(vm_t *vm, const char *name, qboolean binroot, void **vmMain
Con_DLPrintf(2, "Loading native: %s\n", fname);
hVM = Sys_LoadLibrary(fname, funcs);
}
if (!hVM && FS_NativePath(va("%s_%s"ARCH_DL_POSTFIX, name, gpath), FS_BINARYPATH, fname, sizeof(fname)))
{
Con_DLPrintf(2, "Loading native: %s\n", fname);
hVM = Sys_LoadLibrary(fname, funcs);
}
if (!hVM && FS_NativePath(va("%s_%s_"ARCH_CPU_POSTFIX ARCH_DL_POSTFIX, name, gpath), FS_ROOT, fname, sizeof(fname)))
{
Con_DLPrintf(2, "Loading native: %s\n", fname);
hVM = Sys_LoadLibrary(fname, funcs);
}
if (!hVM && FS_NativePath(va("%s_%s"ARCH_DL_POSTFIX, name, gpath), FS_ROOT, fname, sizeof(fname)))
{
Con_DLPrintf(2, "Loading native: %s\n", fname);
hVM = Sys_LoadLibrary(fname, funcs);
}
}
}
else

View File

@ -132,6 +132,7 @@ void ZG_FreeGroup(zonegroup_t *ctx);
#define ZF_ReallocElements(p,e,n,s) ZF_ReallocElementsNamed(p,e,n,s,__FILE__,__LINE__)
#endif
#define Z_StrDup(s) strcpy(Z_Malloc(strlen(s)+1), s)
#define Z_StrDupPtr(v,s) do{Z_Free(*v),*(v) = strcpy(Z_Malloc(strlen(s)+1), s);}while(0)
void Z_StrCat(char **ptr, const char *append);

View File

@ -1396,7 +1396,7 @@ static unsigned int dlthreads = 0;
static void HTTP_Wake_Think(void *ctx, void *data, size_t a, size_t b)
{
dlthreads--;
HTTP_CL_Think();
HTTP_CL_Think(NULL, NULL);
}
#endif
static int DL_Thread_Work(void *arg)
@ -1613,7 +1613,7 @@ struct dl_download *HTTP_CL_Put(const char *url, const char *mime, const char *d
return dl;
}
void HTTP_CL_Think(void)
void HTTP_CL_Think(const char **curname, float *curpercent)
{
struct dl_download *dl = activedownloads;
struct dl_download **link = NULL;
@ -1661,6 +1661,23 @@ void HTTP_CL_Think(void)
}
link = &dl->next;
if (curname && curpercent)
{
if (*dl->localname)
*curname = (const char*)dl->localname;
else
*curname = (const char*)dl->url;
if (dl->status == DL_FINISHED)
*curpercent = 100;
else if (dl->status != DL_ACTIVE)
*curpercent = 0;
else if (dl->totalsize <= 0)
*curpercent = -1;
else
*curpercent = dl->completed*100.0f/dl->totalsize;
}
#ifndef SERVERONLY
if (!cls.download && !dl->isquery)
#ifdef MULTITHREAD
@ -1712,7 +1729,7 @@ void HTTP_CL_Terminate(void)
next = dl->next;
DL_Close(dl);
}
HTTP_CL_Think();
HTTP_CL_Think(NULL, NULL);
#ifdef COOKIECOOKIECOOKIE
Cookie_Monster();

View File

@ -138,7 +138,7 @@ struct dl_download
};
vfsfile_t *VFSPIPE_Open(int refs, qboolean seekable); //refs should be 1 or 2, to say how many times it must be closed before its actually closed, so both ends can close separately
void HTTP_CL_Think(void);
void HTTP_CL_Think(const char **fname, float *percent);
void HTTP_CL_Terminate(void); //kills all active downloads
unsigned int HTTP_CL_GetActiveDownloads(void);
struct dl_download *HTTP_CL_Get(const char *url, const char *localfile, void (*NotifyFunction)(struct dl_download *dl));

View File

@ -11259,6 +11259,7 @@ BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs
{"log", PF_Logarithm, 0, 0, 0, 532, D("float(float v, optional float base)", "Determines the logarithm of the input value according to the specified base. This can be used to calculate how much something was shifted by.")},
{"soundupdate", PF_Fixme, 0, 0, 0, 0, D("float(entity e, float channel, string newsample, float volume, float attenuation, float pitchpct, float flags, float timeoffset)", "Changes the properties of the current sound being played on the given entity channel. newsample may be empty, and will be ignored in this case. timeoffset is relative to the current position (subtract the result of getsoundtime for absolute positions). Negative volume can be used to stop the sound. Return value is a fractional value based upon the number of audio devices that could be updated - test against TRUE rather than non-zero.")},
{"getsoundtime", PF_Ignore, 0, 0, 0, 533, D("float(entity e, float channel)", "Returns the current playback time of the sample on the given entity's channel. Beware CHAN_AUTO (in csqc, channels are not limited by network protocol).")},
{"getchannellevel", PF_Ignore, 0, 0, 0, 0, D("float(entity e, float channel)", "")},
{"soundlength", PF_Ignore, 0, 0, 0, 534, D("float(string sample)", "Provides a way to query the duration of a sound sample, allowing you to set up a timer to chain samples.")},
{"buf_loadfile", PF_buf_loadfile, 0, 0, 0, 535, D("float(string filename, strbuf bufhandle)", "Appends the named file into a string buffer (which must have been created in advance). The return value merely says whether the file was readable.")},
{"buf_writefile", PF_buf_writefile, 0, 0, 0, 536, D("float(filestream filehandle, strbuf bufhandle, optional float startpos, optional float numstrings)", "Writes the contents of a string buffer onto the end of the supplied filehandle (you must have already used fopen). Additional optional arguments permit you to constrain the writes to a subsection of the stringbuffer.")},

View File

@ -366,13 +366,13 @@ typedef enum {
emufield(vw_index, F_FLOAT) \
emufield(isBot, F_INT) \
emufield(items2, F_FLOAT) \
emufield(trackent, F_INT) /*network another player instead, but not entity because of an mvdsv bug. used during bloodfest.*/
// emufield(mod_admin, F_INT) /*enable 'cmd ban' etc when &2*/
// emufield(hideentity, F_INT) /*backward nodrawtoclient, used by race mode spectators*/
// emufield(hideplayers, F_INT) /*force other clients as invisible, for race mode*/
emufield(trackent, F_INT) /*network another player instead, but not entity because of an mvdsv bug. used during bloodfest.*/ \
emufield(hideentity, F_INT) /*backward nodrawtoclient, used by race mode spectators*/ \
emufield(hideplayers, F_INT) /*force other clients as invisible, for race mode*/
// emufield(visclients, F_INT) /*bitfield of clients that can see this entity (borked with playerslots>32). used for 'cmd tpmsg foo', and bots.*/
// emufield(teleported, F_INT) /*teleport angle twisting*/
// emufield(brokenankle, F_FLOAT) /*not actually in mvdsv after all*/
// emufield(mod_admin, F_INT) /*enable 'cmd ban' etc when &2*/
static struct
@ -2560,6 +2560,10 @@ void Q1QVM_PostThink(void)
sv_player->xv->items2 = ((float*)sv_player->v)[fofs.items2];
if (fofs.trackent)
host_client->viewent = ((int*)sv_player->v)[fofs.trackent];
if (fofs.hideplayers)
host_client->hideplayers = ((int*)sv_player->v)[fofs.hideplayers];
if (fofs.hideentity)
host_client->hideentity = ((int*)sv_player->v)[fofs.hideentity];
}
void Q1QVM_StartFrame(qboolean botsarespecialsnowflakes)

View File

@ -647,11 +647,10 @@ typedef struct client_s
#endif
qboolean csqcactive;
#ifdef PROTOCOL_VERSION_FTE
qboolean pextknown;
unsigned int fteprotocolextensions;
unsigned int fteprotocolextensions2;
#endif
unsigned int ezprotocolextensions1;
unsigned int zquake_extensions;
unsigned int max_net_ents; /*highest entity number the client can receive (limited by either protocol or client's buffer size)*/
unsigned int max_net_staticents; /*limit to the number of static ents supported by the client*/
@ -720,6 +719,11 @@ typedef struct client_s
float delay;
laggedpacket_t *laggedpacket;
laggedpacket_t *laggedpacket_last;
#ifdef VM_Q1
int hideentity;
qboolean hideplayers;
#endif
} client_t;
#if defined(NQPROT) || defined(Q2SERVER) || defined(Q3SERVER)
@ -1270,7 +1274,7 @@ void SV_SendClientMessages (void);
void VARGS SV_Multicast (vec3_t origin, multicast_t to);
#define FULLDIMENSIONMASK 0xffffffff
void SV_MulticastProtExt(vec3_t origin, multicast_t to, int dimension_mask, int with, int without);
void SV_MulticastCB(vec3_t origin, multicast_t to, int dimension_mask, void (*callback)(client_t *cl, sizebuf_t *msg, void *ctx), void *ctx);
void SV_MulticastCB(vec3_t origin, multicast_t to, const char *reliableinfokey, int dimension_mask, void (*callback)(client_t *cl, sizebuf_t *msg, void *ctx), void *ctx);
void SV_StartSound (int ent, vec3_t origin, float *velocity, int seenmask, int channel, const char *sample, int volume, float attenuation, float pitchadj, float timeofs, unsigned int flags);
void QDECL SVQ1_StartSound (float *origin, wedict_t *entity, int channel, const char *sample, int volume, float attenuation, float pitchadj, float timeofs, unsigned int chflags);
@ -1567,7 +1571,7 @@ void SV_MVD_SendInitialGamestate(mvddest_t *dest);
extern demo_t demo; // server demo struct
extern cvar_t sv_demoDir;
extern cvar_t sv_demoDir, sv_demoDirAlt;
extern cvar_t sv_demoAutoRecord;
extern cvar_t sv_demofps;
extern cvar_t sv_demoPings;

View File

@ -3731,6 +3731,14 @@ void SV_Snapshot_BuildQ1(client_t *client, packet_entities_t *pack, pvscamera_t
if (client->gibfilter && SV_GibFilter(ent))
continue;
#ifdef VM_Q1
//mvdsv compat
if (client->hideentity && EDICT_TO_PROG(svprogfuncs, ent) == client->hideentity)
continue;
if (client->hideplayers && e <= sv.allocated_client_slots)
continue;
#endif
}
else
tracecullent = NULL;

View File

@ -19,6 +19,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "quakedef.h"
#include "netinc.h"
#include "fs.h" //for updates
#include <sys/types.h>
#ifndef CLIENTONLY
#define Q2EDICT_NUM(i) (q2edict_t*)((char *)ge->edicts+(i)*ge->edict_size)
@ -70,6 +71,7 @@ cvar_t fraglog_details = CVARD("fraglog_details", "1", "Bitmask\n1: killer+ki
cvar_t zombietime = CVARD("zombietime", "2", "Client slots will not be reused for this number of seconds."); // seconds to sink messages
cvar_t sv_rconlim = CVARFD("sv_rconlim", "4", CVAR_ARCHIVE, "Blocks repeated (invalid) rcon attempts.");
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");
#ifdef SERVERONLY
@ -139,6 +141,7 @@ cvar_t sv_masterport = CVAR("sv_masterport", "0");
cvar_t pext_ezquake_nochunks = CVARD("pext_ezquake_nochunks", "0", "Prevents ezquake clients from being able to use the chunked download extension. This sidesteps numerous ezquake issues, and will make downloads slower but more robust.");
cvar_t sv_reliable_sound = CVARFD("sv_reliable_sound", "0", 0, "Causes all sounds to be sent reliably, so they will not be missed due to packetloss. However, this will cause them to be delayed somewhat, and slightly bursty. This can be overriden using the 'rsnd' userinfo setting (either forced on or forced off). Note: this does not affect sounds attached to particle effects.");
cvar_t sv_gamespeed = CVARAF("sv_gamespeed", "1", "slowmo", 0);
cvar_t sv_csqcdebug = CVARD("sv_csqcdebug", "0", "Inject packet size information for data directed to csqc.");
cvar_t sv_csqc_progname = CVAR("sv_csqc_progname", "csprogs.dat");
@ -1573,7 +1576,6 @@ qboolean SVC_GetChallenge (qboolean respond_dp)
if (svs.gametype == GT_PROGS || svs.gametype == GT_Q1QVM)
{
#ifdef PROTOCOL_VERSION_FTE
unsigned int mask;
//tell the client what fte extensions we support
mask = Net_PextMask(1, false);
@ -1599,7 +1601,6 @@ qboolean SVC_GetChallenge (qboolean respond_dp)
memcpy(over, &lng, sizeof(lng));
over+=sizeof(lng);
}
#endif
if (*net_mtu.string)
mask = net_mtu.ival&~7;
else
@ -1914,6 +1915,7 @@ void SV_ClientProtocolExtensionsChanged(client_t *client)
client->fteprotocolextensions &= Net_PextMask(1, ISNQCLIENT(client));
client->fteprotocolextensions2 &= Net_PextMask(2, ISNQCLIENT(client));
client->ezprotocolextensions1 &= Net_PextMask(3, ISNQCLIENT(client)) & EZPEXT1_SERVERADVERTISE;
//some gamecode can't cope with some extensions for some reasons... and I'm too lazy to fix the code to cope.
if (svs.gametype == GT_HALFLIFE)
@ -2815,7 +2817,7 @@ client_t *SVC_DirectConnect(void)
#ifdef PEXT_Q2BSP
else if (sv.world.worldmodel->fromgame == fg_quake2 && !(newcl->fteprotocolextensions & PEXT_Q2BSP))
{
SV_RejectMessage (protocol, "The server is using a quake 2 level and we don't think your client supports this\nuse 'setinfo iknow 1' to ignore this check\nYou can go to "ENGINEWEBSITE" to get a compatible client\n\nYou may need to enable an option\n\n");
SV_RejectMessage (protocol, "The server is using a q2bsp-format level and we don't think your client supports this\nuse 'setinfo iknow 1' to ignore this check\nYou can go to "ENGINEWEBSITE" to get a compatible client\n\nYou may need to enable an option\n\n");
// Con_Printf("player %s was dropped due to incompatible client\n", name);
// return;
}
@ -2823,7 +2825,7 @@ client_t *SVC_DirectConnect(void)
#ifdef PEXT_Q3BSP
else if (sv.world.worldmodel->fromgame == fg_quake3 && !(newcl->fteprotocolextensions & PEXT_Q3BSP))
{
SV_RejectMessage (protocol, "The server is using a quake 3 level and we don't think your client supports this\nuse 'setinfo iknow 1' to ignore this check\nYou can go to "ENGINEWEBSITE" to get a compatible client\n\nYou may need to enable an option\n\n");
SV_RejectMessage (protocol, "The server is using a q3bsp-format level and we don't think your client supports this\nuse 'setinfo iknow 1' to ignore this check\nYou can go to "ENGINEWEBSITE" to get a compatible client\n\nYou may need to enable an option\n\n");
// Con_Printf("player %s was dropped due to incompatible client\n", name);
// return;
}
@ -3070,6 +3072,7 @@ client_t *SVC_DirectConnect(void)
newcl->challenge = challenge;
newcl->zquake_extensions = atoi(InfoBuf_ValueForKey(&newcl->userinfo, "*z_ext"));
InfoBuf_SetStarKey(&newcl->userinfo, "*z_ext", "");
if (*InfoBuf_ValueForKey(&newcl->userinfo, "*fuhquake")) //fuhquake doesn't claim to support z_ext but does look at our z_ext serverinfo key.
{ //so switch on the bits that it should be sending.
newcl->zquake_extensions |= Z_EXT_PM_TYPE|Z_EXT_PM_TYPE_NEW;
@ -3312,6 +3315,11 @@ client_t *SVC_DirectConnect(void)
newcl->controller = NULL;
#ifdef PEXT_CSQC
if (sv.csqcchecksum && !(newcl->fteprotocolextensions & PEXT_CSQC) && !ISDPCLIENT(newcl))
SV_PrintToClient(newcl, PRINT_HIGH, "This server is using CSQC - you are missing out due to your choice of outdated client / protocol!\n");
#endif
if (!redirect)
{
Sys_ServerActivity();
@ -3353,6 +3361,12 @@ static int dehex(int i)
}
static qboolean Rcon_Validate (void)
{
/*
The rcon protocol sucks.
1) vanilla sent it plain text
2) there's no challenge, so there's no way to block spoofed requests
3) the hashed version of the protocol still has no challenge
*/
const char *realpass = rcon_password.string;
const char *pass = Cmd_Argv(1);
if (!strlen (realpass))
@ -3435,6 +3449,8 @@ void SVC_RemoteCommand (void)
int i;
char remaining[1024];
char adr[MAX_ADR_SIZE];
static unsigned int blockuntil;
unsigned int curtime, inc = 1000/sv_rconlim.value;
{
char *br = SV_BannedReason(&net_from);
@ -3445,8 +3461,18 @@ void SVC_RemoteCommand (void)
}
}
if (!Rcon_Validate ())
if (sv_rconlim.value > 0)
{
curtime = Sys_Milliseconds();
if (1000 < curtime - blockuntil)
blockuntil = curtime - 1000;
if (inc > curtime-blockuntil)
return; //throttle
}
if (!Rcon_Validate())
{
blockuntil += inc;
/*
#ifdef SVRANKING
if (cmd_allowaccess.value) //try and find a username, match the numeric password
@ -3512,6 +3538,9 @@ void SVC_RemoteCommand (void)
Con_TPrintf ("Bad rcon from %s:\t%s\n"
, NET_AdrToString (adr, sizeof(adr), &net_from), net_message.data+4);
if (1)
return;
SV_BeginRedirect (RD_PACKET, com_language);
Con_TPrintf ("Bad rcon_password. Passwords might be logged. Be careful.\n");
@ -3800,25 +3829,47 @@ qboolean SV_ConnectionlessPacket (void)
//its a subtle difference, but means we can avoid wasteful spam for real qw clients.
SVC_GetChallenge ((net_message.cursize==16)?true:false);
}
#if 1//def NQPROT
/*for DP origionally, but dpmaster expects it, and we need dpmaster for custom protocol names*/
else if (!strcmp(c, "getstatus"))
{
{ //q3/dpmaster support
if (sv_public.ival >= 0)
if (SVC_ThrottleInfo())
SVC_GetInfo(Cmd_Args(), true);
}
else if (!strcmp(c, "getinfo"))
{
{ //q3/dpmaster support
if (sv_public.ival >= 0)
if (SVC_ThrottleInfo())
SVC_GetInfo(Cmd_Args(), false);
}
#endif
else if (!strcmp(c, "rcon"))
SVC_RemoteCommand ();
else if (!strcmp(c, "realip"))
{
if (SVC_ThrottleInfo())
SVC_RemoteCommand ();
}
else if (!strcmp(c, "realip") || !strcmp(c, "ip"))
SVC_RealIP ();
/*
else if (!strcmp(c,"lastscores"))
{
if (SVC_ThrottleInfo())
SVC_LastScores ();
}
else if (!strcmp(c,"dlist") || !strcmp(c,"demolist"))
{
if (SVC_ThrottleInfo())
SVC_DemoList ();
}
else if (!strcmp(c,"dlistr") || !strcmp(c,"dlistregex") || !strcmp(c,"demolistr") || !strcmp(c,"demolistregex"))
{
if (SVC_ThrottleInfo())
SVC_DemoListRegex ();
}
else if (!strcmp(c,"qtvusers"))
{
if (SVC_ThrottleInfo())
SVC_QTVUsers ();
}
*/
else if (!PR_GameCodePacket(net_message.data+4))
{
static unsigned int lt;
@ -4838,7 +4889,7 @@ float SV_Frame (void)
if (isDedicated)
{
// FTP_ClientThink();
HTTP_CL_Think();
HTTP_CL_Think(NULL, NULL);
}
#endif
@ -5160,6 +5211,7 @@ void SV_InitLocal (void)
Log_Init();
}
rcon_password.restriction = RESTRICT_MAX; //no cheatie rconers changing rcon passwords...
Cvar_Register (&sv_rconlim, cvargroup_servercontrol);
Cvar_Register (&sv_crypt_rcon, cvargroup_servercontrol);
Cvar_Register (&spectator_password, cvargroup_servercontrol);
@ -5272,6 +5324,7 @@ void SV_InitLocal (void)
Cvar_Register (&sv_csqcdebug, cvargroup_servercontrol);
Cvar_Register (&sv_specprint, cvargroup_serverpermissions);
Cvar_Register (&sv_reliable_sound, cvargroup_serverphysics);
Cvar_Register (&sv_gamespeed, cvargroup_serverphysics);
Cvar_Register (&sv_nqplayerphysics, cvargroup_serverphysics);
Cvar_Register (&pr_allowbutton1, cvargroup_servercontrol);
@ -5826,6 +5879,12 @@ void SV_Init (quakeparms_t *parms)
Cmd_StuffCmds();
Cbuf_Execute ();
Menu_Download_Update();
#ifdef WEBCLIENT
if (Sys_RunInstaller())
Sys_Quit();
#endif
Con_TPrintf ("Exe: %s %s\n", __DATE__, __TIME__);

View File

@ -41,6 +41,7 @@ cvar_t sv_demoMaxDirCount = CVARD("sv_demoMaxDirCount", "500", "Maximum allowed
cvar_t sv_demoMaxDirAge = CVARD("sv_demoMaxDirAge", "0", "Maximum allowed age for demos, any older demos will be deleted when sv_demoClearOld is set (this doesn't prevent recording new demos).");
cvar_t sv_demoClearOld = CVARD("sv_demoClearOld", "0", "Automatically delete demos to keep the demos count reasonable.");
cvar_t sv_demoDir = CVARC("sv_demoDir", "demos", SV_DemoDir_Callback);
cvar_t sv_demoDirAlt = CVARD("sv_demoDir", "", "Provides a fallback directory name for demo downloads, for when sv_demoDir doesn't contain the requested demo.");
cvar_t sv_demofps = CVAR("sv_demofps", "30");
cvar_t sv_demoPings = CVARD("sv_demoPings", "10", "Interval between ping updates in mvds");
cvar_t sv_demoMaxSize = CVARD("sv_demoMaxSize", "", "Demos will be truncated to be no larger than this size.");
@ -1203,6 +1204,7 @@ void MVD_Init (void)
Cvar_Register (&sv_demoMaxDirAge, MVDVARGROUP);
Cvar_Register (&sv_demoClearOld, MVDVARGROUP);
Cvar_Register (&sv_demoDir, MVDVARGROUP);
Cvar_Register (&sv_demoDirAlt, MVDVARGROUP);
Cvar_Register (&sv_demoPrefix, MVDVARGROUP);
Cvar_Register (&sv_demoSuffix, MVDVARGROUP);
Cvar_Register (&sv_demotxt, MVDVARGROUP);

View File

@ -2696,5 +2696,6 @@ void SV_SetMoveVars(void)
movevars.watersinkspeed = *pm_watersinkspeed.string?pm_watersinkspeed.value:60;
movevars.flyfriction = *pm_flyfriction.string?pm_flyfriction.value:4;
movevars.edgefriction = *pm_edgefriction.string?pm_edgefriction.value:2;
movevars.flags = MOVEFLAG_VALID|MOVEFLAG_NOGRAVITYONGROUND|(*pm_edgefriction.string?0:MOVEFLAG_QWEDGEBOX);
}
#endif

View File

@ -30,7 +30,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#define CHAN_ITEM 3
#define CHAN_BODY 4
extern cvar_t sv_gravity, sv_friction, sv_waterfriction, sv_gamespeed, sv_stopspeed, sv_spectatormaxspeed, sv_accelerate, sv_airaccelerate, sv_wateraccelerate, pm_edgefriction;
extern cvar_t sv_gravity, sv_friction, sv_waterfriction, sv_gamespeed, sv_stopspeed, sv_spectatormaxspeed, sv_accelerate, sv_airaccelerate, sv_wateraccelerate, pm_edgefriction, sv_reliable_sound;
extern cvar_t dpcompat_stats;
/*
@ -1016,9 +1016,9 @@ void SV_MulticastProtExt(vec3_t origin, multicast_t to, int dimension_mask, int
SZ_Clear (&sv.multicast);
}
void SV_MulticastCB(vec3_t origin, multicast_t to, int dimension_mask, void (*callback)(client_t *cl, sizebuf_t *msg, void *ctx), void *ctx)
void SV_MulticastCB(vec3_t origin, multicast_t to, const char *reliableinfokey, int dimension_mask, void (*callback)(client_t *cl, sizebuf_t *msg, void *ctx), void *ctx)
{
qboolean reliable = false;
qboolean reliable = false, doreliable;
client_t *client;
qbyte *mask;
@ -1140,7 +1140,15 @@ void SV_MulticastCB(vec3_t origin, multicast_t to, int dimension_mask, void (*ca
if (!split)
continue;
if (reliable)
doreliable = reliable;
if (reliableinfokey)
{ //allow the user to override reliable state according to a userinfo key (primarily "rsnd" right now, but hey).
const char *v = InfoBuf_ValueForKey(&client->userinfo, reliableinfokey);
if (*v)
doreliable = atoi(v);
}
if (doreliable)
{
char msgbuf[8192];
sizebuf_t msg = {0};
@ -1435,14 +1443,14 @@ void SV_StartSound (int ent, vec3_t origin, float *velocity, int seenmask, int c
if (chflags & CF_SV_UNICAST)
{
SV_MulticastCB(origin, reliable ? MULTICAST_ONE_R_SPECS : MULTICAST_ONE_SPECS, seenmask, SV_SoundMulticast, &ctx);
SV_MulticastCB(origin, (reliable||sv_reliable_sound.ival) ? MULTICAST_ONE_R_SPECS : MULTICAST_ONE_SPECS, reliable?NULL:"rsnd", seenmask, SV_SoundMulticast, &ctx);
}
else
{
if (use_phs)
SV_MulticastCB(origin, reliable ? MULTICAST_PHS_R : MULTICAST_PHS, seenmask, SV_SoundMulticast, &ctx);
SV_MulticastCB(origin, (reliable||sv_reliable_sound.ival) ? MULTICAST_PHS_R : MULTICAST_PHS, reliable?NULL:"rsnd", seenmask, SV_SoundMulticast, &ctx);
else
SV_MulticastCB(origin, reliable ? MULTICAST_ALL_R : MULTICAST_ALL, seenmask, SV_SoundMulticast, &ctx);
SV_MulticastCB(origin, (reliable||sv_reliable_sound.ival) ? MULTICAST_ALL_R : MULTICAST_ALL, reliable?NULL:"rsnd", seenmask, SV_SoundMulticast, &ctx);
}
}
@ -2180,7 +2188,7 @@ void SV_CalcClientStats(client_t *client, int statsi[MAX_CL_STATS], float statsf
// statsfi[STAT_MOVEVARS_AIRSPEEDLIMIT_NONQW] = 0;
// statsfi[STAT_MOVEVARS_AIRSTRAFEACCEL_QW] = 0;
// statsfi[STAT_MOVEVARS_AIRCONTROL_POWER] = 2;
statsi [STAT_MOVEFLAGS] = MOVEFLAG_QWCOMPAT;
statsi [STAT_MOVEFLAGS] = MOVEFLAG_VALID|MOVEFLAG_QWCOMPAT;
// statsfi[STAT_MOVEVARS_WARSOWBUNNY_AIRFORWARDACCEL] = 0;
// statsfi[STAT_MOVEVARS_WARSOWBUNNY_ACCEL] = 0;
// statsfi[STAT_MOVEVARS_WARSOWBUNNY_TOPSPEED] = 0;
@ -2807,6 +2815,9 @@ static qboolean SV_SyncInfoBuf(client_t *client)
if (!large)
{ //vanilla-compatible info.
if (!blobdata)
blobdata = "";
if (ISNQCLIENT(client))
{ //except that nq never had any userinfo
const char *s;
@ -2847,6 +2858,8 @@ static qboolean SV_SyncInfoBuf(client_t *client)
InfoSync_Remove(&client->infosync, 0);
return false;
}
if (!blobdata)
bloboffset = 0; //wiped or something? I dunno, don't bug out though.y
sendsize = blobsize - bloboffset;
bufferspace = MAX_BACKBUFLEN - client->netchan.message.cursize;

View File

@ -43,6 +43,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include <fcntl.h>
#include <dirent.h>
#include <time.h>
#include <unistd.h>
#ifdef MULTITHREAD
#include <pthread.h>
@ -98,7 +99,11 @@ qboolean Sys_rmdir (const char *path)
qboolean Sys_remove (const char *path)
{
#ifdef __unix__
return unlink(path);
#else
return system(va("rm \"%s\"", path));
#endif
}
qboolean Sys_Rename (const char *oldfname, const char *newfname)
@ -1132,10 +1137,90 @@ void Sys_ServerActivity(void)
qboolean Sys_RandomBytes(qbyte *string, int len)
{
qboolean res;
qboolean res = false;
int fd = open("/dev/urandom", 0);
res = (read(fd, string, len) == len);
close(fd);
if (fd != -1)
{
res = (read(fd, string, len) == len);
close(fd);
}
return res;
}
#ifdef WEBCLIENT
#include "fs.h"
static qboolean Sys_DoInstall(void)
{
char fname[MAX_QPATH];
float pct = 0;
qboolean applied = false;
#ifdef __unix__
qboolean showprogress = isatty(STDOUT_FILENO);
#else
qboolean showprogress = false;
#endif
#if 1
FS_CreateBasedir(NULL);
#else
char basedir[MAX_OSPATH];
if (!FS_NativePath("", FS_ROOT, basedir, sizeof(basedir)))
return true;
FS_CreateBasedir(basedir);
#endif
*fname = 0;
for(;;)
{
while(FS_DownloadingPackage())
{
const char *cur = "";
float newpct = 50;
HTTP_CL_Think(&cur, &newpct);
if (*cur && Q_strncmp(fname, cur, sizeof(fname)-1))
{
Q_strncpyz(fname, cur, sizeof(fname));
Con_Printf("Downloading: %s\n", fname);
}
if (showprogress && (int)(pct*10) != (int)(newpct*10))
{
pct = newpct;
Sys_Printf("%5.1f%%\r", pct);
}
Sys_Sleep(10/1000.0);
COM_MainThreadWork();
}
if (!applied)
{
if (!PM_MarkUpdates())
break; //no changes to apply
PM_ApplyChanges();
applied = true; //don't keep applying.
continue;
}
break;
}
if (showprogress)
Sys_Printf(" \r");
return true;
}
qboolean Sys_RunInstaller(void)
{
if (COM_CheckParm("-install"))
{ //install THEN run
Sys_DoInstall();
return false;
}
if (COM_CheckParm("-doinstall"))
{
//install only, then quit
return Sys_DoInstall();
}
if (!com_installer)
return false;
return Sys_DoInstall();
}
#endif

View File

@ -1833,4 +1833,10 @@ void Sys_SetAutoUpdateSetting(int newval)
}
#endif
#ifdef WEBCLIENT
qboolean Sys_RunInstaller(void)
{ //not implemented
return false;
}
#endif
#endif

View File

@ -276,16 +276,14 @@ void SV_New_f (void)
return;
}
/* splitt delay
host_client->state = cs_connected;
host_client->connection_started = realtime;
#ifdef SVRANKING
host_client->stats_started = realtime;
#endif*/
// send the info about the new client to all connected clients
// SV_FullClientUpdate (host_client, &sv.reliable_datagram);
// host_client->sendinfo = true;
if (!host_client->pextknown && host_client->zquake_extensions && host_client->netchan.remote_address.type != NA_LOOPBACK)
{
char *msg = "cmd pext\n";
ClientReliableWrite_Begin (host_client, svc_stufftext, 2+strlen(msg));
ClientReliableWrite_String (host_client, msg);
return;
}
host_client->pextknown = true;
gamedir = InfoBuf_ValueForKey (&svs.info, "*gamedir");
if (!gamedir[0])
@ -296,15 +294,6 @@ void SV_New_f (void)
gamedir = "";
}
//NOTE: This doesn't go through ClientReliableWrite since it's before the user
//spawns. These functions are written to not overflow
/* if (host_client->num_backbuf)
{
Con_Printf("WARNING %s: [SV_New] Back buffered (%d0, clearing)\n", host_client->name, host_client->netchan.message.cursize);
host_client->num_backbuf = 0;
SZ_Clear(&host_client->netchan.message);
}
*/
if (svs.netprim.coordsize > 2 && !(host_client->fteprotocolextensions & PEXT_FLOATCOORDS))
{
SV_ClientPrintf(host_client, 2, "\n\n\n\nPlease set cl_nopext to 0 and then reconnect.\nIf that doesn't work, please update your engine - "ENGINEWEBSITE"\n");
@ -317,7 +306,6 @@ void SV_New_f (void)
// send the serverdata
ClientReliableWrite_Byte (host_client, ISQ2CLIENT(host_client)?svcq2_serverdata:svc_serverdata);
#ifdef PROTOCOL_VERSION_FTE
if (host_client->fteprotocolextensions)//let the client know
{
ClientReliableWrite_Long (host_client, PROTOCOL_VERSION_FTE);
@ -331,7 +319,6 @@ void SV_New_f (void)
ClientReliableWrite_Long (host_client, PROTOCOL_VERSION_FTE2);
ClientReliableWrite_Long (host_client, host_client->fteprotocolextensions2);
}
#endif
ClientReliableWrite_Long (host_client, ISQ2CLIENT(host_client)?PROTOCOL_VERSION_Q2:PROTOCOL_VERSION_QW);
ClientReliableWrite_Long (host_client, svs.spawncount);
if (ISQ2CLIENT(host_client))
@ -2249,6 +2236,8 @@ void SV_Begin_f (void)
// and it won't happen if the game was just loaded, so you wind up
// with a permanent head tilt
MSG_WriteByte (&host_client->netchan.message, svc_setangle);
if (host_client->ezprotocolextensions1 & EZPEXT1_SETANGLEREASON)
MSG_WriteByte (&host_client->netchan.message, 0);
MSG_WriteAngle (&host_client->netchan.message, 0 );
MSG_WriteAngle (&host_client->netchan.message, host_client->edict->v->angles[1] );
MSG_WriteAngle (&host_client->netchan.message, 0 );
@ -3032,7 +3021,9 @@ qboolean SV_AllowDownload (const char *name)
return false;
}
if (Q_strncasecmp(name, "maps/", 5) == 0)
if ((Q_strncasecmp(name, "maps/", 5) == 0) ||
(Q_strncasecmp(name, "levelshots/", 11) == 0) ||
(Q_strncasecmp(name, "overviews/", 10) == 0))
return !!allow_download_maps.value;
//skins?
@ -3040,7 +3031,8 @@ qboolean SV_AllowDownload (const char *name)
return !!allow_download_skins.value;
//models
if ((Q_strncasecmp(name, "progs/", 6) == 0) ||
(Q_strncasecmp(name, "models/", 7) == 0))
(Q_strncasecmp(name, "models/", 7) == 0) ||
(Q_strncasecmp(name, "sprites/", 8) == 0))
return !!allow_download_models.value;
//sound
if (Q_strncasecmp(name, "sound/", 6) == 0)
@ -3130,11 +3122,20 @@ static int SV_LocateDownload(const char *name, flocation_t *loc, char **replacem
#ifdef MVD_RECORDING
//mvdsv demo downloading support. demos/ -> demodir (sets up the server paths)
if (!Q_strncasecmp(name, "demos/", 6))
if (!Q_strncasecmp(name, "demos/", 6) && *sv_demoDir.string)
{
Q_snprintfz(tmpname, sizeof(tmpname), "%s/%s", sv_demoDir.string, name+6);
name = tmpname;
Q_snprintfz(tmpname, sizeof(tmpname), "%s/%s", sv_demoDir.string, name+6);
found = FS_FLocateFile(name, FSLF_IFFOUND, loc);
if (!found && *sv_demoDirAlt.string)
{
Q_snprintfz(tmpname, sizeof(tmpname), "%s/%s", sv_demoDirAlt.string, name+6);
found = FS_FLocateFile(name, FSLF_IFFOUND, loc);
}
if (found)
name = tmpname;
}
else
#endif
if (!Q_strncasecmp(name, "package/", 8))
@ -3162,18 +3163,21 @@ static int SV_LocateDownload(const char *name, flocation_t *loc, char **replacem
{
size_t alt;
static const char *alternatives[][4] = {
//orig-path, orig-ext, new-path, new-ext
//orig-path, new-path, orig-ext, new-ext
//nexuiz qc names [sound/]sound/foo.wav but expects sound/foo.ogg and variations of that (the [sound/] is implied, but ignored)
{"", "", ".wav", ".ogg"}, //nexuiz qc names .wav, but the paks use .ogg
{"sound/", "", ".wav", ".wav"}, //nexuiz qc names sound/ but that's normally implied, resulting in doubles that don't exist in the filesystem
{"sound/", "", ".wav", ".ogg"} //both of nexuiz's issues at the same time
{"sound/", "", ".wav", ".ogg"}, //both of nexuiz's issues at the same time
//we request wads from textures/*.wad but they could also be simply *.wad
{"textures/","",".wad", ".wad"}
};
for (alt = 0; alt < countof(alternatives); alt++)
{
char tryalt[MAX_QPATH];
char ext[8];
if (Q_strncasecmp(name, alternatives[alt][0], strlen(alternatives[alt][0])))
if (!Q_strncasecmp(name, alternatives[alt][0], strlen(alternatives[alt][0])))
{
if (*alternatives[alt][2])
{
@ -3220,7 +3224,7 @@ static int SV_LocateDownload(const char *name, flocation_t *loc, char **replacem
if (pakname && strchr(pakname, '/'))
{
extern cvar_t allow_download_packages,allow_download_copyrighted; //non authoritive, but should normally match.
if (allow_download_packages.ival)
if (allow_download_packages.ival && !(loc->search && (loc->search->flags&SPF_BASEPATH)))
{
if (allow_download_copyrighted.ival || !protectedpak)
{
@ -4412,15 +4416,6 @@ qboolean SV_UserInfoIsBasic(const char *infoname)
return false;
}
static void SV_SetInfo_PrintCB (void *ctx, const char *key, const char *value)
{
client_t *cl = ctx;
if (cl->num_backbuf > MAX_BACK_BUFFERS/2)
return; //stop printing if there's too many...
SV_ClientPrintf(cl, PRINT_HIGH, "\t%-20s%s\n", key, value);
}
/*
==================
SV_SetInfo_f
@ -4432,13 +4427,28 @@ void SV_SetInfo_f (void)
{
char oldval[MAX_INFO_KEY];
char *key, *val, *t;
size_t offset, keysize, valsize, k;
size_t offset, keysize, valsize, cursize, k;
qboolean final;
if (Cmd_Argc() == 1)
{
SV_ClientPrintf(host_client, PRINT_HIGH, "User info settings:\n");
InfoBuf_Enumerate(&host_client->userinfo, (void*)host_client, SV_SetInfo_PrintCB);
for (k = 0; k < host_client->userinfo.numkeys; k++)
{
char *partial = key = host_client->userinfo.keys[k].partial?"<PARTIAL>":"";
if (host_client->num_backbuf > MAX_BACK_BUFFERS/2)
break; //stop printing if there's too many...
key = host_client->userinfo.keys[k].name;
val = host_client->userinfo.keys[k].value;
if (host_client->userinfo.keys[k].size != strlen(host_client->userinfo.keys[k].value))
SV_ClientPrintf(host_client, PRINT_HIGH, "\t%-20s%s<BINARY %u BYTES>\n", key, partial, (unsigned int)host_client->userinfo.keys[k].size);
else if (host_client->userinfo.keys[k].size > 64 || strchr(val, '\n') || strchr(val, '\r') || strchr(val, '\t'))
SV_ClientPrintf(host_client, PRINT_HIGH, "\t%-20s%s<%u BYTES>\n", key, partial, (unsigned int)host_client->userinfo.keys[k].size);
else
SV_ClientPrintf(host_client, PRINT_HIGH, "\t%-20s%s%s\n", key, partial, val);
}
SV_ClientPrintf(host_client, PRINT_HIGH, "[%u/%i, %u/%i]\n", (unsigned int)host_client->userinfo.numkeys, sv_userinfo_keylimit.ival, (unsigned int)host_client->userinfo.totalsize, sv_userinfo_bytelimit.ival);
return;
}
@ -4481,12 +4491,16 @@ void SV_SetInfo_f (void)
val = Z_StrDup(val);
}
if (InfoBuf_FindKey(&host_client->userinfo, key, &k))
cursize = strlen(host_client->userinfo.keys[k].name)+2+host_client->userinfo.keys[k].size;
else
cursize = 0;
if (key[0] == '*' && !(ISNQCLIENT(host_client) && !host_client->spawned && !strcmp(key, "*ver"))) //nq clients are allowed to set some * keys if ClientConnect wasn't called yet. FIXME: saved games may still be an issue.
SV_ClientPrintf(host_client, PRINT_HIGH, "setinfo: %s may not be changed mid-game\n", key);
else if (sv_userinfo_keylimit.ival >= 0 && host_client->userinfo.numkeys >= sv_userinfo_keylimit.ival && !offset && *val && !InfoBuf_FindKey(&host_client->userinfo, key, &k)) //when the limit is hit, allow people to freely change existing keys, but not new ones. they can also silently remove any that don't exist yet, too.
SV_ClientPrintf(host_client, PRINT_MEDIUM, "setinfo: userinfo is limited to %i keys. Ignoring setting %s\n", sv_userinfo_keylimit.ival, key);
else if (sv_userinfo_bytelimit.ival >= 0 && host_client->userinfo.totalsize >= sv_userinfo_bytelimit.ival && *val)
else if (valsize && sv_userinfo_bytelimit.ival >= 0 && host_client->userinfo.totalsize-cursize+(keysize+2+valsize) >= sv_userinfo_bytelimit.ival)
{
SV_ClientPrintf(host_client, PRINT_MEDIUM, "setinfo: userinfo is limited to %i bytes. Ignoring setting %s\n", sv_userinfo_bytelimit.ival, key);
if (offset) //kill it if they're part way through sending one, so that they're not penalised by the presence of partials that will never complete.
@ -5972,46 +5986,6 @@ static void SVNQ_Protocols_f(void)
}
}
void SV_Pext_f(void)
{
int i;
char *tag;
char *val;
if (host_client->pextknown)
return;
host_client->pextknown = true;
host_client->fteprotocolextensions = 0;
host_client->fteprotocolextensions2 = 0;
for (i = 1; i < Cmd_Argc(); )
{
tag = Cmd_Argv(i++);
val = Cmd_Argv(i++);
switch(strtoul(tag, NULL, 0))
{
case PROTOCOL_VERSION_FTE:
host_client->fteprotocolextensions = strtoul(val, NULL, 0) & Net_PextMask(1, ISNQCLIENT(host_client));
break;
case PROTOCOL_VERSION_FTE2:
host_client->fteprotocolextensions2 = strtoul(val, NULL, 0) & Net_PextMask(2, ISNQCLIENT(host_client));
break;
}
}
Con_DPrintf("%s now using pext: %x, %x\n", host_client->name, host_client->fteprotocolextensions, host_client->fteprotocolextensions2);
if (!host_client->supportedprotocols && Cmd_Argc() == 1)
Con_DPrintf("%s has a shitty client.\n", host_client->name);
SV_ClientProtocolExtensionsChanged(host_client);
if (ISNQCLIENT(host_client))
SVNQ_New_f();
else
SV_New_f();
}
/*
void SVNQ_ExecuteUserCommand (char *s)
{
@ -6058,6 +6032,54 @@ void SVNQ_ExecuteUserCommand (char *s)
*/
#endif
//used when we can't use our getchallenge handshake for some reason.
//this is both nq (where there's no challenge at all) and qw-via-qwfwd (where the proxy handshakes before talking to the actual server)
void SV_Pext_f(void)
{
int i;
char *tag;
char *val;
if (host_client->pextknown)
return;
host_client->pextknown = true;
host_client->fteprotocolextensions = 0;
host_client->fteprotocolextensions2 = 0;
for (i = 1; i < Cmd_Argc(); )
{
tag = Cmd_Argv(i++);
val = Cmd_Argv(i++);
switch(strtoul(tag, NULL, 0))
{
case PROTOCOL_VERSION_FTE:
host_client->fteprotocolextensions = strtoul(val, NULL, 0) & Net_PextMask(1, ISNQCLIENT(host_client));
break;
case PROTOCOL_VERSION_FTE2:
host_client->fteprotocolextensions2 = strtoul(val, NULL, 0) & Net_PextMask(2, ISNQCLIENT(host_client));
break;
case PROTOCOL_VERSION_EZQUAKE1:
host_client->ezprotocolextensions1 = strtoul(val, NULL, 0) & Net_PextMask(3, ISNQCLIENT(host_client)) & EZPEXT1_SERVERADVERTISE;
break;
}
}
if (!host_client->supportedprotocols && Cmd_Argc() == 1)
Con_DPrintf("%s reports no extended capabilities.\n", host_client->name);
else
Con_DPrintf("%s now using pext: %x, %x, %x\n", host_client->name, host_client->fteprotocolextensions, host_client->fteprotocolextensions2, host_client->ezprotocolextensions1);
SV_ClientProtocolExtensionsChanged(host_client);
#ifdef NQPROT
if (ISNQCLIENT(host_client))
SVNQ_New_f();
else
#endif
SV_New_f();
}
void SV_MVDList_f (void);
void SV_MVDInfo_f (void);
@ -6071,71 +6093,72 @@ typedef struct
ucmd_t ucmds[] =
{
/*connection process*/
{"new", SV_New_f, true},
{"modellist", SVQW_Modellist_f, true},
{"soundlist", SVQW_Soundlist_f, true},
{"prespawn", SVQW_PreSpawn_f, true},
{"spawn", SVQW_Spawn_f, true},
{"begin", SV_Begin_f, true},
{"new", SV_New_f, true},
{"pext", SV_Pext_f, true},
{"modellist", SVQW_Modellist_f, true},
{"soundlist", SVQW_Soundlist_f, true},
{"prespawn", SVQW_PreSpawn_f, true},
{"spawn", SVQW_Spawn_f, true},
{"begin", SV_Begin_f, true},
{"drop", SV_Drop_f},
{"disconnect", SV_Drop_f},
{"pings", SV_Pings_f},
{"drop", SV_Drop_f},
{"disconnect", SV_Drop_f},
{"pings", SV_Pings_f},
{"enablecsqc", SV_EnableClientsCSQC, 2},
{"disablecsqc", SV_DisableClientsCSQC, 2},
// issued by hand at client consoles
{"rate", SV_Rate_f},
{"kill", SV_Kill_f},
{"pause", SV_Pause_f},
{"msg", SV_Msg_f},
/* issued by hand at client console*/
{"rate", SV_Rate_f},
{"kill", SV_Kill_f},
{"pause", SV_Pause_f},
{"msg", SV_Msg_f},
{"efpslist", Cmd_FPSList_f}, //don't conflict with the ktpro one
{"vote", SV_Vote_f},
{"sayone", SV_SayOne_f},
{"say", SV_Say_f},
{"say_team", SV_Say_Team_f},
{"setinfo", SV_SetInfo_f},
{"serverinfo", SV_ShowServerinfo_f},
#ifdef MVD_RECORDING
/*demo/download commands*/
{"demolist", SV_UserCmdMVDList_f},
{"dlist", SV_UserCmdMVDList_f}, //apparently people are too lazy to type.
{"demoinfo", SV_MVDInfo_f},
{"dl", SV_DemoDownload_f},
/*user interactions*/
{"sayone", SV_SayOne_f},
{"say", SV_Say_f},
{"say_team", SV_Say_Team_f},
#ifdef SVRANKING
{"topten", Rank_ListTop10_f},
#endif
{"stopdownload", SV_StopDownload_f},
{"dlsize", SV_DownloadSize_f},
{"download", SV_BeginDownload_f},
{"nextdl", SV_NextDownload_f, true},
{"setinfo", SV_SetInfo_f},
{"serverinfo", SV_ShowServerinfo_f},
/*download/demo commands*/
#ifdef MVD_RECORDING
{"demolist", SV_UserCmdMVDList_f},
{"dlist", SV_UserCmdMVDList_f}, //apparently people are too lazy to type.
//mvdsv has 4 more variants, for 6 total doing the same thing.
{"demoinfo", SV_MVDInfo_f},
{"dl", SV_DemoDownload_f},
#endif
{"stopdownload",SV_StopDownload_f},
{"stopdl", SV_StopDownload_f}, //mvdsv compat
{"dlsize", SV_DownloadSize_f},
{"download", SV_BeginDownload_f},
{"nextdl", SV_NextDownload_f, true},
/*quakeworld specific things*/
{"addseat", Cmd_AddSeat_f}, //splitscreen
{"join", Cmd_Join_f},
{"observe", Cmd_Observe_f},
{"ptrack", SV_PTrack_f}, //ZOID - used with autocam
{"snap", SV_NoSnap_f}, //cheat detection
{"addseat", Cmd_AddSeat_f}, //splitscreen
{"join", Cmd_Join_f},
{"observe", Cmd_Observe_f},
{"ptrack", SV_PTrack_f}, //ZOID - used with autocam
{"snap", SV_NoSnap_f}, //cheat detection
{"enablecsqc", SV_EnableClientsCSQC, 2},
{"disablecsqc", SV_DisableClientsCSQC, 2},
{"vote", SV_Vote_f},
#ifdef SVRANKING
{"topten", Rank_ListTop10_f},
#endif
{"efpslist", Cmd_FPSList_f}, //don't conflict with the ktpro one
{"god", Cmd_God_f},
{"give", Cmd_Give_f},
{"noclip", Cmd_Noclip_f},
{"spiderpig", Cmd_Spiderpig_f},
{"6dof", Cmd_6dof_f},
{"fly", Cmd_Fly_f},
{"notarget", Cmd_Notarget_f},
{"setpos", Cmd_SetPos_f},
/*cheats*/
{"god", Cmd_God_f},
{"give", Cmd_Give_f},
{"noclip", Cmd_Noclip_f},
{"spiderpig", Cmd_Spiderpig_f},
{"6dof", Cmd_6dof_f},
{"fly", Cmd_Fly_f},
{"notarget", Cmd_Notarget_f},
{"setpos", Cmd_SetPos_f},
#ifdef SUBSERVERS
{"ssvtransfer", Cmd_SSV_Transfer_f},//transfer the player to a different map/server
{"ssvsay", Cmd_SSV_AllSay_f}, //transfer the player to a different map/server
{"ssvsay", Cmd_SSV_AllSay_f}, //says realm-wide
{"ssvjoin", Cmd_SSV_Join_f}, //transfer the player to a different map/server
#endif
@ -6144,10 +6167,10 @@ ucmd_t ucmds[] =
#endif
#ifdef VOICECHAT
{"voicetarg", SV_Voice_Target_f},
{"vignore", SV_Voice_Ignore_f}, /*ignore/mute specific player*/
{"muteall", SV_Voice_MuteAll_f}, /*disables*/
{"unmuteall", SV_Voice_UnmuteAll_f}, /*reenables*/
{"voicetarg", SV_Voice_Target_f},
{"vignore", SV_Voice_Ignore_f}, /*ignore/mute specific player*/
{"muteall", SV_Voice_MuteAll_f}, /*disables*/
{"unmuteall", SV_Voice_UnmuteAll_f}, /*reenables*/
#endif
{NULL, NULL}
@ -7072,6 +7095,7 @@ void SV_RunCmd (usercmd_t *ucmd, qboolean recurse)
movevars.flyfriction = *pm_flyfriction.string?pm_flyfriction.value:4;
movevars.edgefriction = *pm_edgefriction.string?pm_edgefriction.value:2;
movevars.coordsize = host_client->netchan.netprim.coordsize;
movevars.flags = MOVEFLAG_VALID|MOVEFLAG_NOGRAVITYONGROUND|(*pm_edgefriction.string?0:MOVEFLAG_QWEDGEBOX);
for (i=0 ; i<3 ; i++)
{
@ -7317,6 +7341,7 @@ void SV_RunCmd (usercmd_t *ucmd, qboolean recurse)
movevars.flyfriction = *pm_flyfriction.string?pm_flyfriction.value:4;
movevars.edgefriction = *pm_edgefriction.string?pm_edgefriction.value:2;
movevars.coordsize = host_client->netchan.netprim.coordsize;
movevars.flags = MOVEFLAG_VALID|MOVEFLAG_NOGRAVITYONGROUND|(*pm_edgefriction.string?0:MOVEFLAG_QWEDGEBOX);
// should already be folded into host_client->maxspeed
// if (sv_player->xv->hasted)

View File

@ -236,7 +236,12 @@ qboolean Sys_GetDesktopParameters(int *width, int *height, int *bpp, int *refres
return false;
}
#ifdef WEBCLIENT
qboolean Sys_RunInstaller(void)
{ //not implemented
return false;
}
#endif
#define SYS_CLIPBOARD_SIZE 256
static char *clipboard_buffer;

View File

@ -82,6 +82,13 @@ nonstatic void(mitem_desktop desktop) M_Options_Video =
fr.add(menuitemslider_spawn(_("Gamma"), "gamma", '1.3 0.5 -0.1', '280 8'), fl, [0, pos], [0, 8]); pos += 8;
fr.add(menuitemslider_spawn(_("Contrast"), "contrast", '0.7 2 0.1', '280 8'), fl, [0, pos], [0, 8]); pos += 8;
fr.add(menuitemslider_spawn(_("Brightness"), "brightness", '0 0.4 0.05', '280 8'), fl, [0, pos], [0, 8]); pos += 8;
fr.add(menuitemcombo_spawn(_("Hardware Gamma"), "vid_hardwaregamma", '280 8',
"0 \"Off\" "
"1 \"Auto\" "
"2 \"Soft\" "
"3 \"Hard\" "
"4 \"Scene Only\" "
), fl, [0, pos], [0, 8]); pos += 8;
addmenuback(m);
};