From ee9c9025a015ef8510d217498b480ca7a875dabc Mon Sep 17 00:00:00 2001 From: Spoike Date: Sat, 23 Mar 2019 07:06:37 +0000 Subject: [PATCH] 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 --- engine/client/cl_demo.c | 7 +- engine/client/cl_ents.c | 9 +- engine/client/cl_main.c | 84 +++-- engine/client/cl_parse.c | 23 +- engine/client/m_download.c | 502 +++++++++++++++------------ engine/client/m_options.c | 5 + engine/client/pr_csqc.c | 9 + engine/client/snd_al.c | 16 + engine/client/snd_dma.c | 50 ++- engine/client/sound.h | 2 + engine/client/sys_droid.c | 8 + engine/client/sys_linux.c | 7 + engine/client/sys_win.c | 9 +- engine/client/view.c | 2 +- engine/client/wad.c | 2 + engine/common/cmd.c | 14 +- engine/common/com_mesh.c | 4 +- engine/common/common.c | 3 - engine/common/common.h | 1 + engine/common/console.h | 2 + engine/common/fs.h | 2 + engine/common/net_chan.c | 4 + engine/common/pmove.c | 4 +- engine/common/pmove.h | 2 +- engine/common/protocol.h | 21 +- engine/common/qvm.c | 12 +- engine/common/zone.h | 1 + engine/http/httpclient.c | 23 +- engine/http/iweb.h | 2 +- engine/server/pr_cmds.c | 1 + engine/server/pr_q1qvm.c | 12 +- engine/server/server.h | 12 +- engine/server/sv_ents.c | 8 + engine/server/sv_main.c | 85 ++++- engine/server/sv_mvd.c | 2 + engine/server/sv_phys.c | 1 + engine/server/sv_send.c | 29 +- engine/server/sv_sys_unix.c | 93 ++++- engine/server/sv_sys_win.c | 6 + engine/server/sv_user.c | 307 ++++++++-------- engine/web/sys_web.c | 7 +- quakec/menusys/menu/options_video.qc | 7 + 42 files changed, 921 insertions(+), 479 deletions(-) diff --git a/engine/client/cl_demo.c b/engine/client/cl_demo.c index eafab733..c290c20d 100644 --- a/engine/client/cl_demo.c +++ b/engine/client/cl_demo.c @@ -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); diff --git a/engine/client/cl_ents.c b/engine/client/cl_ents.c index e4ee067d..b642a6d1 100644 --- a/engine/client/cl_ents.c +++ b/engine/client/cl_ents.c @@ -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); diff --git a/engine/client/cl_main.c b/engine/client/cl_main.c index ab210e5a..2f1b10c1 100644 --- a/engine/client/cl_main.c +++ b/engine/client/cl_main.c @@ -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) diff --git a/engine/client/cl_parse.c b/engine/client/cl_parse.c index b5ed4694..8e1f3f49 100644 --- a/engine/client/cl_parse.c +++ b/engine/client/cl_parse.c @@ -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; } -} \ No newline at end of file +} diff --git a/engine/client/m_download.c b/engine/client/m_download.c index ffc28590..eb71861a 100644 --- a/engine/client/m_download.c +++ b/engine/client/m_download.c @@ -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""; else - status = S_COLOR_CYAN""; + status = S_COLOR_CYAN""; } else if ((p->flags & DPF_PURGE) || !(p->qhash && (p->flags & DPF_CACHED))) status = S_COLOR_CYAN""; @@ -2747,10 +2790,14 @@ void PM_Command_f(void) } else if ((p->flags & (DPF_ENABLED|DPF_CACHED)) == DPF_CACHED) status = S_COLOR_CYAN""; + else if (p->flags & DPF_USERMARKED) + status = S_COLOR_GRAY""; + else if (p->flags & DPF_AUTOMARKED) + status = S_COLOR_GRAY""; 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("\n"); } @@ -2831,7 +2878,7 @@ void PM_Command_f(void) } Con_Printf("\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) { diff --git a/engine/client/m_options.c b/engine/client/m_options.c index 6c3ae42d..68650f7d 100644 --- a/engine/client/m_options.c +++ b/engine/client/m_options.c @@ -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; diff --git a/engine/client/pr_csqc.c b/engine/client/pr_csqc.c index 7895578b..27190c47 100644 --- a/engine/client/pr_csqc.c +++ b/engine/client/pr_csqc.c @@ -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++) diff --git a/engine/client/snd_al.c b/engine/client/snd_al.c index 860af245..86a3ec38 100644 --- a/engine/client/snd_al.c +++ b/engine/client/snd_al.c @@ -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; diff --git a/engine/client/snd_dma.c b/engine/client/snd_dma.c index 2372627a..618ecf8d 100644 --- a/engine/client/snd_dma.c +++ b/engine/client/snd_dma.c @@ -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; } } diff --git a/engine/client/sound.h b/engine/client/sound.h index 9dd7e5b3..372ed5ba 100644 --- a/engine/client/sound.h +++ b/engine/client/sound.h @@ -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; diff --git a/engine/client/sys_droid.c b/engine/client/sys_droid.c index 5d8aaeb8..1fee1883 100644 --- a/engine/client/sys_droid.c +++ b/engine/client/sys_droid.c @@ -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) { diff --git a/engine/client/sys_linux.c b/engine/client/sys_linux.c index 946c8bba..50bee264 100644 --- a/engine/client/sys_linux.c +++ b/engine/client/sys_linux.c @@ -1126,3 +1126,10 @@ qboolean Sys_RandomBytes(qbyte *string, int len) return res; } + +#ifdef WEBCLIENT +qboolean Sys_RunInstaller(void) +{ + return false; +} +#endif \ No newline at end of file diff --git a/engine/client/sys_win.c b/engine/client/sys_win.c index 1cad7092..03ae19d5 100644 --- a/engine/client/sys_win.c +++ b/engine/client/sys_win.c @@ -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) diff --git a/engine/client/view.c b/engine/client/view.c index bb143365..d94c6866 100644 --- a/engine/client/view.c +++ b/engine/client/view.c @@ -1946,7 +1946,7 @@ void R_DrawNameTags(void) if (body) { // Q_snprintfz(fname, sizeof(fname), ""); - 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 diff --git a/engine/client/wad.c b/engine/client/wad.c index 16eb60c7..8f2de264 100644 --- a/engine/client/wad.c +++ b/engine/client/wad.c @@ -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"); } diff --git a/engine/common/cmd.c b/engine/common/cmd.c index e03a4800..4d4aa9a5 100644 --- a/engine/common/cmd.c +++ b/engine/common/cmd.c @@ -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) diff --git a/engine/common/com_mesh.c b/engine/common/com_mesh.c index 1f7dbcf2..043c1c9f 100644 --- a/engine/common/com_mesh.c +++ b/engine/common/com_mesh.c @@ -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) { diff --git a/engine/common/common.c b/engine/common/common.c index b3d426fa..1bf91e75 100644 --- a/engine/common/common.c +++ b/engine/common/common.c @@ -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; diff --git a/engine/common/common.h b/engine/common/common.h index 4acd5a12..d2a2ad68 100644 --- a/engine/common/common.h +++ b/engine/common/common.h @@ -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 diff --git a/engine/common/console.h b/engine/common/console.h index 1898a23b..106a776a 100644 --- a/engine/common/console.h +++ b/engine/common/console.h @@ -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" diff --git a/engine/common/fs.h b/engine/common/fs.h index c615c128..70c4a335 100644 --- a/engine/common/fs.h +++ b/engine/common/fs.h @@ -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); diff --git a/engine/common/net_chan.c b/engine/common/net_chan.c index 456d2916..1562fc53 100644 --- a/engine/common/net_chan.c +++ b/engine/common/net_chan.c @@ -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; } diff --git a/engine/common/pmove.c b/engine/common/pmove.c index 21827075..4448e004 100644 --- a/engine/common/pmove.c +++ b/engine/common/pmove.c @@ -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); diff --git a/engine/common/pmove.h b/engine/common/pmove.h index 57fb67f2..5b5f3197 100644 --- a/engine/common/pmove.h +++ b/engine/common/pmove.h @@ -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; diff --git a/engine/common/protocol.h b/engine/common/protocol.h index cd0916bf..ee7b554d 100644 --- a/engine/common/protocol.h +++ b/engine/common/protocol.h @@ -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) diff --git a/engine/common/qvm.c b/engine/common/qvm.c index 78393f4a..0bb83abe 100644 --- a/engine/common/qvm.c +++ b/engine/common/qvm.c @@ -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 diff --git a/engine/common/zone.h b/engine/common/zone.h index 756233b9..f8868869 100644 --- a/engine/common/zone.h +++ b/engine/common/zone.h @@ -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); diff --git a/engine/http/httpclient.c b/engine/http/httpclient.c index 27416683..6b1c7463 100644 --- a/engine/http/httpclient.c +++ b/engine/http/httpclient.c @@ -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(); diff --git a/engine/http/iweb.h b/engine/http/iweb.h index cf1b9f77..21f1d2dd 100644 --- a/engine/http/iweb.h +++ b/engine/http/iweb.h @@ -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)); diff --git a/engine/server/pr_cmds.c b/engine/server/pr_cmds.c index 14f3841f..46720c3f 100644 --- a/engine/server/pr_cmds.c +++ b/engine/server/pr_cmds.c @@ -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.")}, diff --git a/engine/server/pr_q1qvm.c b/engine/server/pr_q1qvm.c index 9b13af9a..b9304171 100755 --- a/engine/server/pr_q1qvm.c +++ b/engine/server/pr_q1qvm.c @@ -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) diff --git a/engine/server/server.h b/engine/server/server.h index c2678f10..99ce5c83 100644 --- a/engine/server/server.h +++ b/engine/server/server.h @@ -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; diff --git a/engine/server/sv_ents.c b/engine/server/sv_ents.c index dfa6e0e5..57675e86 100644 --- a/engine/server/sv_ents.c +++ b/engine/server/sv_ents.c @@ -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; diff --git a/engine/server/sv_main.c b/engine/server/sv_main.c index a514dd4a..a16c219a 100644 --- a/engine/server/sv_main.c +++ b/engine/server/sv_main.c @@ -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 #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__); diff --git a/engine/server/sv_mvd.c b/engine/server/sv_mvd.c index ad3583d1..68c31e3d 100644 --- a/engine/server/sv_mvd.c +++ b/engine/server/sv_mvd.c @@ -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); diff --git a/engine/server/sv_phys.c b/engine/server/sv_phys.c index 87481e43..254ba49c 100644 --- a/engine/server/sv_phys.c +++ b/engine/server/sv_phys.c @@ -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 diff --git a/engine/server/sv_send.c b/engine/server/sv_send.c index d9a6d0c5..2263df8d 100644 --- a/engine/server/sv_send.c +++ b/engine/server/sv_send.c @@ -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; diff --git a/engine/server/sv_sys_unix.c b/engine/server/sv_sys_unix.c index 6cf6460a..5adcecc3 100644 --- a/engine/server/sv_sys_unix.c +++ b/engine/server/sv_sys_unix.c @@ -43,6 +43,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include #include #include +#include #ifdef MULTITHREAD #include @@ -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 diff --git a/engine/server/sv_sys_win.c b/engine/server/sv_sys_win.c index d3949c9c..4a2d06a1 100644 --- a/engine/server/sv_sys_win.c +++ b/engine/server/sv_sys_win.c @@ -1833,4 +1833,10 @@ void Sys_SetAutoUpdateSetting(int newval) } #endif +#ifdef WEBCLIENT +qboolean Sys_RunInstaller(void) +{ //not implemented + return false; +} +#endif #endif diff --git a/engine/server/sv_user.c b/engine/server/sv_user.c index 4d1e2c71..0d1f3bc7 100644 --- a/engine/server/sv_user.c +++ b/engine/server/sv_user.c @@ -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?"":""; + 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\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) diff --git a/engine/web/sys_web.c b/engine/web/sys_web.c index def53f69..a8d0722b 100644 --- a/engine/web/sys_web.c +++ b/engine/web/sys_web.c @@ -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; diff --git a/quakec/menusys/menu/options_video.qc b/quakec/menusys/menu/options_video.qc index d37ad170..5582e319 100644 --- a/quakec/menusys/menu/options_video.qc +++ b/quakec/menusys/menu/options_video.qc @@ -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); };