From 0c22b8c3448ec51ea761a693a13b46b1b2a79e87 Mon Sep 17 00:00:00 2001 From: Spoike Date: Sun, 24 Feb 2019 08:32:45 +0000 Subject: [PATCH] Some q3 tweaks. git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@5416 fc73d0e0-1445-4013-8a0c-d673dee63da5 --- engine/client/cl_cg.c | 32 +++++++---- engine/client/cl_ents.c | 11 ++-- engine/client/cl_input.c | 2 +- engine/client/cl_main.c | 14 ++++- engine/client/cl_ui.c | 2 +- engine/client/clq3_parse.c | 49 ++++++++++------ engine/client/clq3defs.h | 6 +- engine/client/snd_dma.c | 25 ++++++++ engine/client/sound.h | 6 ++ engine/common/bothdefs.h | 1 + engine/common/cmd.c | 113 ++++++++++++------------------------- engine/common/plugin.c | 8 +-- engine/common/qvm.c | 39 ++++++++----- engine/common/vm.h | 2 +- engine/server/pr_q1qvm.c | 4 +- engine/server/sv_main.c | 2 +- engine/server/svq3_game.c | 6 +- 17 files changed, 182 insertions(+), 140 deletions(-) diff --git a/engine/client/cl_cg.c b/engine/client/cl_cg.c index dfcbc348e..dd3ab94d3 100644 --- a/engine/client/cl_cg.c +++ b/engine/client/cl_cg.c @@ -320,18 +320,28 @@ typedef struct { qbyte weapon; // weapon signed char forwardmove, rightmove, upmove; } q3usercmd_t; -#define CMD_BACKUP UPDATE_BACKUP -#define CMD_MASK UPDATE_MASK -qboolean CGQ3_GetUserCmd(int cmdNumber, q3usercmd_t *ucmd) +#define CMD_BACKUP countof(cl.outframes) +#define CMD_MASK (CMD_BACKUP-1) +static int CGQ3_GetCurrentCmdNumber(void) +{ //Q3 sequences are 1-based, so 1<=idx<=latestsequence are valid + //FTE's sequences are 0-based, so 0<=idx cl.movesequence) - Host_EndGame("CL_GetUserCmd: cmdNumber > ccs.currentUserCmdNumber"); + //q3 does not do partials. + if (cmdNumber >= cl.movesequence) + Host_EndGame("CLQ3_GetUserCmd: %i >= %i", cmdNumber, cl.movesequence); - if (cl.movesequence - cmdNumber >= CMD_BACKUP) - return false; // too old + if (cl.movesequence - (cmdNumber+1) > CMD_BACKUP) + return false; + //note: frames and commands are desynced in q3. cmd = &cl.outframes[(cmdNumber) & CMD_MASK].cmd[0]; ucmd->angles[0] = cmd->angles[0]; ucmd->angles[1] = cmd->angles[1]; @@ -1011,7 +1021,7 @@ static qintptr_t CG_SystemCalls(void *offset, quintptr_t mask, qintptr_t fn, con break; case CG_S_STARTSOUND:// ( vec3_t origin, int entityNum, int entchannel, sfxHandle_t sfx ) - S_StartSound(VM_LONG(arg[1])+1, VM_LONG(arg[2]), S_PrecacheSound(VM_FROMSTRCACHE(arg[3])), VM_POINTER(arg[0]), NULL, 1, 1, 0, 0, 0); + S_StartSound(VM_LONG(arg[1])+1, VM_LONG(arg[2]), S_PrecacheSound(VM_FROMSTRCACHE(arg[3])), VM_POINTER(arg[0]), NULL, 1, 1, 0, 0, CF_CLI_NODUPES); break; case CG_S_ADDLOOPINGSOUND: @@ -1121,7 +1131,7 @@ static qintptr_t CG_SystemCalls(void *offset, quintptr_t mask, qintptr_t fn, con break; case CG_GETCURRENTCMDNUMBER: - VM_LONG(ret) = cl.movesequence-1; + VM_LONG(ret) = CGQ3_GetCurrentCmdNumber(); break; case CG_GETUSERCMD: VALIDATEPOINTER(arg[1], sizeof(q3usercmd_t)); @@ -1290,7 +1300,7 @@ static qintptr_t EXPORT_FN CG_SystemCallsNative(qintptr_t arg, ...) args[9]=va_arg(argptr, qintptr_t); va_end(argptr); - return CG_SystemCalls(NULL, (unsigned)~0, arg, args); + return CG_SystemCalls(NULL, ~(quintptr_t)0, arg, args); } int CG_Refresh(void) @@ -1343,7 +1353,7 @@ void CG_Start (void) Z_FreeTags(CGTAGNUM); SCR_BeginLoadingPlaque(); - cgvm = VM_Create("vm/cgame", com_nogamedirnativecode.ival?NULL:CG_SystemCallsNative, CG_SystemCallsVM); + cgvm = VM_Create("cgame", com_nogamedirnativecode.ival?NULL:CG_SystemCallsNative, "vm/cgame", CG_SystemCallsVM); if (cgvm) { //hu... cgame doesn't appear to have a query version call! SCR_EndLoadingPlaque(); diff --git a/engine/client/cl_ents.c b/engine/client/cl_ents.c index b652ec5a0..c720cc206 100644 --- a/engine/client/cl_ents.c +++ b/engine/client/cl_ents.c @@ -5554,6 +5554,7 @@ void CL_SetSolidEntities (void) packet_entities_t *pak; entity_state_t *state; physent_t *pent; + model_t *mod; memset(&pmove.physents[0], 0, sizeof(physent_t)); pmove.physents[0].model = cl.worldmodel; @@ -5575,18 +5576,20 @@ void CL_SetSolidEntities (void) { /*bsp model size*/ if (state->modelindex <= 0) continue; - if (!cl.model_precache[state->modelindex]) + mod = cl.model_precache[state->modelindex]; + if (!mod) continue; /*vanilla protocols have no 'solid' information. all entities get assigned ES_SOLID_BSP, even if its not actually solid. so we need to make sure that item pickups are not erroneously considered solid, but doors etc are. - yes, this probably means that externally loaded models will be predicted non-solid - you'll need to upgrade your network protocol for the gamecode to be able to specify solidity. + normally, ONLY inline models are considered solid when we have no solid info. + monsters will always be non-solid, too. */ - if (!(cls.fteprotocolextensions2 & PEXT2_REPLACEMENTDELTAS) && !((*cl.model_precache[state->modelindex]->name == '*' || cl.model_precache[state->modelindex]->numsubmodels) && cl.model_precache[state->modelindex]->funcs.NativeTrace)) + if (!(cls.fteprotocolextensions2 & PEXT2_REPLACEMENTDELTAS) && mod->numsubmodels <= 1) continue; pent = &pmove.physents[pmove.numphysent]; memset(pent, 0, sizeof(physent_t)); - pent->model = cl.model_precache[state->modelindex]; + pent->model = mod; if (pent->model->loadstate != MLS_LOADED) continue; VectorCopy (state->angles, pent->angles); diff --git a/engine/client/cl_input.c b/engine/client/cl_input.c index 5d39939e6..48c4a8f8a 100644 --- a/engine/client/cl_input.c +++ b/engine/client/cl_input.c @@ -34,7 +34,7 @@ static cvar_t cl_movement = CVARD("cl_movement","1", "Specifies whether to send cvar_t cl_nodelta = CVAR("cl_nodelta","0"); -static cvar_t cl_c2sdupe = CVAR("cl_c2sdupe", "0"); +cvar_t cl_c2sdupe = CVAR("cl_c2sdupe", "0"); cvar_t cl_c2spps = CVAR("cl_c2spps", "0"); cvar_t cl_c2sImpulseBackup = CVAR("cl_c2sImpulseBackup","3"); cvar_t cl_netfps = CVAR("cl_netfps", "150"); diff --git a/engine/client/cl_main.c b/engine/client/cl_main.c index 09376a783..ce6198c3c 100644 --- a/engine/client/cl_main.c +++ b/engine/client/cl_main.c @@ -178,7 +178,7 @@ cvar_t cl_gunanglez = CVAR("cl_gunanglez", "0"); cvar_t cl_proxyaddr = CVAR("cl_proxyaddr", ""); cvar_t cl_sendguid = CVARD("cl_sendguid", "", "Send a randomly generated 'globally unique' id to servers, which can be used by servers for score rankings and stuff. Different servers will see different guids. Delete the 'qkey' file in order to appear as a different user.\nIf set to 2, all servers will see the same guid. Be warned that this can show other people the guid that you're using."); -cvar_t cl_downloads = CVARFD("cl_downloads", "1", CVAR_NOTFROMSERVER, "Allows you to block all automatic downloads."); +cvar_t cl_downloads = CVARAFD("cl_downloads", "1", /*q3*/"cl_allowDownload", CVAR_NOTFROMSERVER, "Allows you to block all automatic downloads."); cvar_t cl_download_csprogs = CVARFD("cl_download_csprogs", "1", CVAR_NOTFROMSERVER, "Download updated client gamecode if available. Warning: If you clear this to avoid downloading vm code, you should also clear cl_download_packages."); cvar_t cl_download_redirection = CVARFD("cl_download_redirection", "2", CVAR_NOTFROMSERVER, "Follow download redirection to download packages instead of individual files. Also allows the server to send nearly arbitary download commands.\n2: allows redirection only to named packages files (and demos/*.mvd), which is a bit safer."); cvar_t cl_download_mapsrc = CVARFD("cl_download_mapsrc", "", CVAR_ARCHIVE, "Specifies an http location prefix for map downloads. EG: \"http://example.com/path/quakemaps/\""); @@ -3496,10 +3496,18 @@ client_connect: //fixme: make function cls.state = ca_connected; if (cls.netchan.remote_address.type != NA_LOOPBACK) { + switch(cls.protocol) + { + case CP_QUAKEWORLD: Con_DPrintf("QW "); break; + case CP_NETQUAKE: Con_Printf ("NQ "); break; + case CP_QUAKE2: Con_Printf ("Q2 "); break; + case CP_QUAKE3: Con_Printf ("Q3 "); break; + default: break; + } if (cls.netchan.remote_address.prot == NP_DTLS || cls.netchan.remote_address.prot == NP_TLS || cls.netchan.remote_address.prot == NP_WSS) - Con_TPrintf ("Connected (^2encrypted^7).\n"); + Con_TPrintf ("Connected (^[^2encrypted\\tip\\Any passwords will be sent securely, but may still be logged^]).\n"); else - Con_TPrintf ("Connected (^1plain-text^7).\n"); + Con_TPrintf ("Connected (^[^1plain-text\\tip\\"CON_WARNING"Do not type passwords as they can potentially be seen by network sniffers^]).\n"); } #ifdef QUAKESPYAPI allowremotecmd = false; // localid required now for remote cmds diff --git a/engine/client/cl_ui.c b/engine/client/cl_ui.c index 1f62ab3f7..7513bd7ec 100644 --- a/engine/client/cl_ui.c +++ b/engine/client/cl_ui.c @@ -1636,7 +1636,7 @@ void UI_Start (void) ui_width = vid.width; ui_height = vid.height; - uivm = VM_Create("vm/ui", com_nogamedirnativecode.ival?NULL:UI_SystemCallsNative, UI_SystemCallsVM); + uivm = VM_Create("ui", com_nogamedirnativecode.ival?NULL:UI_SystemCallsNative, "vm/ui", UI_SystemCallsVM); if (uivm) { apiversion = VM_Call(uivm, UI_GETAPIVERSION, 6); diff --git a/engine/client/clq3_parse.c b/engine/client/clq3_parse.c index aeaceaafc..d9fe7fc49 100644 --- a/engine/client/clq3_parse.c +++ b/engine/client/clq3_parse.c @@ -47,7 +47,7 @@ qboolean CG_FillQ3Snapshot(int snapnum, snapshot_t *snapshot) snapshot->numEntities = snap->numEntities; for (i=0; inumEntities; i++) { - memcpy(&snapshot->entities[i], &ccs.parseEntities[(snap->firstEntity+i) & PARSE_ENTITIES_MASK], sizeof(snapshot->entities[0])); + memcpy(&snapshot->entities[i], &ccs.parseEntities[(snap->firstEntity+i) & Q3PARSE_ENTITIES_MASK], sizeof(snapshot->entities[0])); } memcpy( &snapshot->areamask, snap->areabits, sizeof( snapshot->areamask ) ); @@ -108,7 +108,7 @@ static void CLQ3_DeltaEntity( clientSnap_t *frame, int newnum, q3entityState_t * { q3entityState_t *state; - state = &ccs.parseEntities[ccs.firstParseEntity & PARSE_ENTITIES_MASK]; + state = &ccs.parseEntities[ccs.firstParseEntity & Q3PARSE_ENTITIES_MASK]; if( unchanged ) { @@ -155,7 +155,7 @@ static void CLQ3_ParsePacketEntities( clientSnap_t *oldframe, clientSnap_t *newf } else { - oldstate = &ccs.parseEntities[oldframe->firstEntity & PARSE_ENTITIES_MASK]; + oldstate = &ccs.parseEntities[oldframe->firstEntity & Q3PARSE_ENTITIES_MASK]; oldnum = oldstate->number; } @@ -193,7 +193,7 @@ static void CLQ3_ParsePacketEntities( clientSnap_t *oldframe, clientSnap_t *newf } else { - oldstate = &ccs.parseEntities[(oldframe->firstEntity + numentities) & PARSE_ENTITIES_MASK]; + oldstate = &ccs.parseEntities[(oldframe->firstEntity + numentities) & Q3PARSE_ENTITIES_MASK]; oldnum = oldstate->number; } } @@ -213,7 +213,7 @@ static void CLQ3_ParsePacketEntities( clientSnap_t *oldframe, clientSnap_t *newf } else { - oldstate = &ccs.parseEntities[(oldframe->firstEntity + numentities) & PARSE_ENTITIES_MASK]; + oldstate = &ccs.parseEntities[(oldframe->firstEntity + numentities) & Q3PARSE_ENTITIES_MASK]; oldnum = oldstate->number; } continue; @@ -244,7 +244,7 @@ static void CLQ3_ParsePacketEntities( clientSnap_t *oldframe, clientSnap_t *newf } else { - oldstate = &ccs.parseEntities[(oldframe->firstEntity + numentities) & PARSE_ENTITIES_MASK]; + oldstate = &ccs.parseEntities[(oldframe->firstEntity + numentities) & Q3PARSE_ENTITIES_MASK]; oldnum = oldstate->number; } } @@ -289,12 +289,12 @@ void CLQ3_ParseSnapshot(void) { // The frame that the server did the delta from // is too old, so we can't reconstruct it properly. - Con_Printf( "Delta frame too old.\n" ); + Con_DPrintf( "Delta frame too old.\n" ); } else if(ccs.firstParseEntity - oldsnap->firstEntity > - MAX_PARSE_ENTITIES - MAX_ENTITIES_IN_SNAPSHOT) + Q3MAX_PARSE_ENTITIES - MAX_ENTITIES_IN_SNAPSHOT) { - Con_Printf( "Delta parse_entities too old.\n" ); + Con_DPrintf( "Delta parse_entities too old.\n" ); } else { @@ -371,8 +371,8 @@ void CLQ3_ParseDownload(void) if (dl->size == (unsigned int)-1) { s = MSG_ReadString(); - Con_Printf("\nDownload refused:\n %s\n", s); CL_DownloadFailed(dl->remotename, dl); + Host_EndGame("%s", s); return; } @@ -441,6 +441,7 @@ static qboolean CLQ3_SendDownloads(char *rc, char *rn) char tempname[MAX_QPATH]; char crc[64]; vfsfile_t *f; + extern cvar_t cl_downloads; rc = COM_ParseOut(rc, crc, sizeof(crc)); rn = COM_Parse(rn); if (!*com_token) @@ -468,8 +469,14 @@ static qboolean CLQ3_SendDownloads(char *rc, char *rn) if (!FS_GenCachedPakName(va("%s.tmp", com_token), crc, tempname, sizeof(tempname))) continue; + if (!cl_downloads.ival) + { + Con_Printf(CON_WARNING "Need to download %s.pk3, but downloads are disabled\n", com_token); + continue; + } + //fixme: request to download it - Con_Printf("Sending request to download %s\n", com_token); + Con_Printf("Sending request to download %s.pk3\n", com_token); CLQ3_SendClientCommand("download %s.pk3", com_token); ccs.downloadchunknum = 0; dl = Z_Malloc(sizeof(*dl)); @@ -897,6 +904,7 @@ void CLQ3_SendCmd(usercmd_t *cmd) int cmdcount, key; usercmd_t *to, *from; extern int keycatcher; + extern cvar_t cl_nodelta, cl_c2sdupe; //reuse the q1 array cmd->servertime = cl.servertime*1000; @@ -927,10 +935,13 @@ void CLQ3_SendCmd(usercmd_t *cmd) cmd->buttons |= 2; //add in the 'at console' button cl.outframes[cl.movesequence&CMD_MASK].cmd[0] = *cmd; + cl.movesequence++; + //FIXME: q3 generates a new command every video frame, but a new packet at a more limited rate. + //FIXME: we should return here if its not yet time for a network frame. frame = &cl.outframes[cls.netchan.outgoing_sequence & CMD_MASK]; - frame->cmd_sequence = cl.movesequence++; + frame->cmd_sequence = cl.movesequence; frame->server_message_num = ccs.serverMessageNum; frame->server_time = cl.gametime; frame->client_time = Sys_DoubleTime()*1000; @@ -955,15 +966,19 @@ void CLQ3_SendCmd(usercmd_t *cmd) MSG_WriteBits(&msg, 0, 8); } - i = (cls.netchan.outgoing_sequence-1); + i = cls.netchan.outgoing_sequence; + i -= bound(0, cl_c2sdupe.ival, 5); //extra age, if desired + i--; + if (i < cls.netchan.outgoing_sequence-CMD_MASK) + i = cls.netchan.outgoing_sequence-CMD_MASK; oldframe = &cl.outframes[i & CMD_MASK]; cmdcount = cl.movesequence - oldframe->cmd_sequence; if (cmdcount > CMD_MASK) cmdcount = CMD_MASK; + // begin a client move command, if any - if( cmdcount ) + if (cmdcount) { - extern cvar_t cl_nodelta; if(cl_nodelta.value || !ccs.snap.valid || ccs.snap.serverMessageNum != ccs.serverMessageNum) MSG_WriteBits(&msg, clcq3_nodeltaMove, 8); // no compression @@ -977,8 +992,8 @@ void CLQ3_SendCmd(usercmd_t *cmd) string = ccs.serverCommands[ccs.lastServerCommandNum & TEXTCMD_MASK]; key = ccs.fs_key ^ ccs.serverMessageNum ^ StringKey(string, 32); - // send this and the previous cmds in the message, so - // if the last packet was dropped, it can be recovered + //note that q3 uses timestamps so sequences are not important + //we can also send dupes without issue. from = &nullcmd; for (i = cl.movesequence-cmdcount; i < cl.movesequence; i++) { diff --git a/engine/client/clq3defs.h b/engine/client/clq3defs.h index 27a48d795..0ccb5f5d2 100644 --- a/engine/client/clq3defs.h +++ b/engine/client/clq3defs.h @@ -202,8 +202,8 @@ typedef struct frame_s { int serverTime; } q3frame_t; -#define MAX_PARSE_ENTITIES 1024 -#define PARSE_ENTITIES_MASK (MAX_PARSE_ENTITIES-1) +#define Q3MAX_PARSE_ENTITIES 2048 +#define Q3PARSE_ENTITIES_MASK (Q3MAX_PARSE_ENTITIES-1) #define MAX_STRING_CHARS 1024 #define TEXTCMD_BACKUP 64 // size of reliable text commands buffer, must be power of two @@ -234,7 +234,7 @@ typedef struct { clientSnap_t snapshots[Q3UPDATE_BACKUP]; clientSnap_t snap; - q3entityState_t parseEntities[MAX_PARSE_ENTITIES]; + q3entityState_t parseEntities[Q3MAX_PARSE_ENTITIES]; q3entityState_t baselines[MAX_GENTITIES]; diff --git a/engine/client/snd_dma.c b/engine/client/snd_dma.c index 83e77c0be..2508fb71f 100644 --- a/engine/client/snd_dma.c +++ b/engine/client/snd_dma.c @@ -2568,6 +2568,9 @@ channel_t *SND_PickChannel(soundcardinfo_t *sc, int entnum, int entchannel) if (sc->total_chans <= oldest) sc->total_chans = oldest+1; +#ifdef Q3CLIENT //presumably we should be using this instead of pos for oldest, but blurgh. + sc->channel[oldest].starttime = Sys_Milliseconds(); +#endif return &sc->channel[oldest]; } @@ -2963,6 +2966,28 @@ void S_StartSound(int entnum, int entchannel, sfx_t *sfx, vec3_t origin, vec3_t S_LockMixer(); for (sc = sndcardinfo; sc; sc = sc->next) { +#ifdef Q3CLIENT + if (flags & CF_CLI_NODUPES) + { //don't start too many simultaneous sounds. q3 sucks or something. + int active = 0, i; + unsigned int time = Sys_Milliseconds(); + for (i = 0; i < sc->total_chans; i++) + { //as per q3, channel isn't important. + if (sc->channel[i].entnum == entnum && sc->channel[i].sfx == sfx) + { + //never allow a new sound within 50ms of the previous one + if (time - sc->channel[i].starttime < 50) + break; + active++; + } + } + if (active >= 4 || i < sc->total_chans) + { + Con_DPrintf("CF_CLI_NODUPES strikes again!\n"); + break; + } + } +#endif // pick a channel to play on target_chan = SND_PickChannel(sc, entnum, entchannel); if (!target_chan) diff --git a/engine/client/sound.h b/engine/client/sound.h index 4475cacb8..9dd7e5b3f 100644 --- a/engine/client/sound.h +++ b/engine/client/sound.h @@ -115,6 +115,9 @@ typedef struct #define CF_SV_SENDVELOCITY 512 // serverside hint that velocity is important #define CF_CLI_AUTOSOUND 1024 // generated from q2 entities, which avoids breaking regular sounds, using it outside the sound system will probably break things. #define CF_CLI_INACTIVE 2048 // try to play even when inactive +#ifdef Q3CLIENT +#define CF_CLI_NODUPES 4096 // block multiple identical sounds being started on the same entity within rapid succession. required by quake3. +#endif #define CF_NETWORKED (CF_NOSPACIALISE|CF_NOREVERB|CF_FORCELOOP|CF_FOLLOW/*|CF_RESERVEDN*/) typedef struct @@ -130,6 +133,9 @@ typedef struct vec3_t velocity; // velocity of sound effect vec_t dist_mult; // distance multiplier (attenuation/clipK) int master_vol; // 0-255 master volume +#ifdef Q3CLIENT + unsigned int starttime; // start time, to replicate q3's 50ms embargo on duped sounds. +#endif } channel_t; struct soundcardinfo_s; diff --git a/engine/common/bothdefs.h b/engine/common/bothdefs.h index 25b87ea16..1c9b4693c 100644 --- a/engine/common/bothdefs.h +++ b/engine/common/bothdefs.h @@ -645,6 +645,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #define ARCH_CPU_POSTFIX "x64" #else #define ARCH_CPU_POSTFIX "amd64" + #define ARCH_ALTCPU_POSTFIX "x86_64" #endif #endif #elif defined(_M_IX86) || defined(__i386__) diff --git a/engine/common/cmd.c b/engine/common/cmd.c index cf78ba856..244edbecc 100644 --- a/engine/common/cmd.c +++ b/engine/common/cmd.c @@ -1621,7 +1621,42 @@ char *Cmd_ExpandString (const char *data, char *dest, int destlen, int *accessle if (c == '"') quotes++; - if (c == '$' && (!(quotes&1) || dpcompat_console.ival)) + if (c == '%' && !(quotes&1) && !dpcompat_console.ival) + { //QW262/ezquake does this. kinda annoying. + char *end; + if (data[1] == '%') + { + str = "%"; + data+=2; + } + else if (data[1] == '#') + { + str = va("\"%s\"", Cmd_Args()); + data+=2; + } + else if (data[1] == '*') + { + str = Cmd_Args(); + data+=2; + } + else if ((i=strtol(data+1, &end, 10))) + { + data = end; + str = Cmd_Argv(i); + } + else + { + data++; + str = "%"; //some kind of encoding error + } + + // check buffer size + if (len + strlen(str) >= destlen-1) + break; + strcpy(&dest[len], str); + len += strlen(str); + } + else if (c == '$' && (!(quotes&1) || dpcompat_console.ival)) { data++; if (*data == '$') @@ -1741,75 +1776,6 @@ char *Cmd_ExpandString (const char *data, char *dest, int destlen, int *accessle return dest; } -static char *Cmd_ExpandStringArguments (char *data, char *dest, int destlen) -{ - char c; - int quotes = 0; - int len = 0; - - char *str, *strend; - int old_len; - while ( (c = *data) != 0) - { - if (c == '"') - quotes++; - - if (c == '%' && !(quotes&1)) - { - if (data[1] == '%') - { - str = "%"; - old_len = 2; - } - else if (data[1] == '#') - { - str = va("\"%s\"", Cmd_Args()); - old_len = 2; - } - else if (data[1] == '*') - { - str = Cmd_Args(); - old_len = 2; - } - else if (strtol(data+1, &strend, 10)) - { - str = Cmd_Argv(atoi(data+1)); - old_len = strend - data; - } - else - { - str = NULL; - old_len = 0; - } - - if (str) - { - // check buffer size - if (len + strlen(str) >= destlen-1) - break; - - strcpy(&dest[len], str); - len += strlen(str); - dest[len] = 0; - data += old_len; - - continue; - } - } - - dest[len] = c; - data++; - len++; - dest[len] = 0; - if (len >= destlen-1) - break; - } - - dest[len] = 0; - - return dest; -} - /* ============ Cmd_TokenizeString @@ -2805,7 +2771,6 @@ static void Cmd_ExecuteStringGlobalsAreEvil (const char *text, int level) // if the alias value is a command or cvar and // the alias is called with parameters, add them //unless we're mimicing dp, or the alias has explicit expansions (or macros) in which case it can do its own damn args - if (dpcompat_console.ival) { char *ignoringquoteswasstupid; Cmd_ExpandString(a->value, dest, sizeof(dest), &execlevel, !Cmd_IsInsecure()?true:false, true); @@ -2821,7 +2786,7 @@ static void Cmd_ExecuteStringGlobalsAreEvil (const char *text, int level) if ((a->restriction?a->restriction:rcon_level.ival) > execlevel) return; } - else if (!strchr(a->value, '$')) + if (!dpcompat_console.ival) { if (Cmd_Argc() > 1 && (!strncmp(a->value, "cmd ", 4) || (!strchr(a->value, ' ') && !strchr(a->value, '\t') && (Cvar_FindVar(a->value) || (Cmd_Exists(a->value) && a->value[0] != '+' && a->value[0] != '-')))) @@ -2830,11 +2795,7 @@ static void Cmd_ExecuteStringGlobalsAreEvil (const char *text, int level) Cbuf_InsertText (Cmd_Args(), execlevel, false); Cbuf_InsertText (" ", execlevel, false); } - - Cmd_ExpandStringArguments (a->value, dest, sizeof(dest)); } - else - Q_strncpyz(dest, a->value, sizeof(dest)); Cbuf_InsertText (dest, execlevel, false); #ifdef HAVE_CLIENT diff --git a/engine/common/plugin.c b/engine/common/plugin.c index cc9dff904..8a8e73926 100644 --- a/engine/common/plugin.c +++ b/engine/common/plugin.c @@ -286,14 +286,14 @@ static plugin_t *Plug_Load(const char *file, int type) if (!newplug->vm && (type & PLUG_NATIVE) && !Q_strncasecmp(file, "fteplug_", 8) && !Q_strcasecmp(ARCH_DL_POSTFIX+1, COM_FileExtension(file, temp, sizeof(temp)))) { COM_StripExtension(file, temp, sizeof(temp)); - newplug->vm = VM_Create(temp, Plug_SystemCallsNative, NULL); + newplug->vm = VM_Create(temp, Plug_SystemCallsNative, NULL, NULL); } if (!newplug->vm && (type & PLUG_NATIVE)) - newplug->vm = VM_Create(va("fteplug_%s_", file), Plug_SystemCallsNative, NULL); + newplug->vm = VM_Create(va("fteplug_%s_", file), Plug_SystemCallsNative, NULL, NULL); if (!newplug->vm && (type & PLUG_NATIVE)) - newplug->vm = VM_Create(va("fteplug_%s", file), Plug_SystemCallsNative, NULL); + newplug->vm = VM_Create(va("fteplug_%s", file), Plug_SystemCallsNative, NULL, NULL); if (!newplug->vm && (type & PLUG_QVM)) - newplug->vm = VM_Create(file, NULL, Plug_SystemCallsVM); + newplug->vm = VM_Create(NULL, NULL, file, Plug_SystemCallsVM); if (!newplug->vm && (type & PLUG_NATIVE)) { unsigned int u; diff --git a/engine/common/qvm.c b/engine/common/qvm.c index f11b5caf5..78393f4aa 100644 --- a/engine/common/qvm.c +++ b/engine/common/qvm.c @@ -76,7 +76,10 @@ struct vm_s { qboolean QVM_LoadDLL(vm_t *vm, const char *name, qboolean binroot, void **vmMain, sys_calldll_t syscall) { void (EXPORT_FN *dllEntry)(sys_calldll_t syscall); - char dllname_arch[MAX_OSPATH]; //id compatiblehttps://slashdot.org/ + char dllname_archpri[MAX_OSPATH]; //id compatible +#ifdef ARCH_ALTCPU_POSTFIX + char dllname_archsec[MAX_OSPATH]; //id compatible +#endif char dllname_anycpu[MAX_OSPATH];//simple dllhandle_t *hVM; @@ -91,7 +94,10 @@ qboolean QVM_LoadDLL(vm_t *vm, const char *name, qboolean binroot, void **vmMain {NULL, NULL}, }; - snprintf(dllname_arch, sizeof(dllname_arch), "%s"ARCH_CPU_POSTFIX ARCH_DL_POSTFIX, name); + snprintf(dllname_archpri, sizeof(dllname_archpri), "%s"ARCH_CPU_POSTFIX ARCH_DL_POSTFIX, name); +#ifdef ARCH_ALTCPU_POSTFIX + snprintf(dllname_archsec, sizeof(dllname_archsec), "%s"ARCH_ALTCPU_POSTFIX ARCH_DL_POSTFIX, name); +#endif snprintf(dllname_anycpu, sizeof(dllname_anycpu), "%s" ARCH_DL_POSTFIX, name); hVM=NULL; @@ -101,12 +107,12 @@ qboolean QVM_LoadDLL(vm_t *vm, const char *name, qboolean binroot, void **vmMain { Con_DPrintf("Attempting to load native library: %s\n", name); - if (!hVM && FS_NativePath(dllname_arch, FS_BINARYPATH, fname, sizeof(fname))) + if (!hVM && FS_NativePath(dllname_archpri, FS_BINARYPATH, fname, sizeof(fname))) hVM = Sys_LoadLibrary(fname, funcs); if (!hVM && FS_NativePath(dllname_anycpu, FS_BINARYPATH, fname, sizeof(fname))) hVM = Sys_LoadLibrary(fname, funcs); - if (!hVM && FS_NativePath(dllname_arch, FS_ROOT, fname, sizeof(fname))) + if (!hVM && FS_NativePath(dllname_archpri, FS_ROOT, fname, sizeof(fname))) hVM = Sys_LoadLibrary(fname, funcs); if (!hVM && FS_NativePath(dllname_anycpu, FS_ROOT, fname, sizeof(fname))) hVM = Sys_LoadLibrary(fname, funcs); @@ -138,11 +144,20 @@ qboolean QVM_LoadDLL(vm_t *vm, const char *name, qboolean binroot, void **vmMain { if (!hVM) { - snprintf (fname, sizeof(fname), "%s%s", gpath, dllname_arch); + snprintf (fname, sizeof(fname), "%s%s", gpath, dllname_archpri); Con_DLPrintf(2, "Loading native: %s\n", fname); hVM = Sys_LoadLibrary(fname, funcs); } +#ifdef ARCH_ALTCPU_POSTFIX + if (!hVM) + { + snprintf (fname, sizeof(fname), "%s%s", gpath, dllname_archsec); + Con_DLPrintf(2, "Loading native: %s\n", fname); + hVM = Sys_LoadLibrary(fname, funcs); + } +#endif + if (!hVM) { snprintf (fname, sizeof(fname), "%s%s", gpath, dllname_anycpu); @@ -981,17 +996,15 @@ vm_t *VM_CreateBuiltin(const char *name, sys_calldll_t syscalldll, qintptr_t (*i /* ** VM_Create */ -vm_t *VM_Create(const char *name, sys_calldll_t syscalldll, sys_callqvm_t syscallqvm) +vm_t *VM_Create(const char *dllname, sys_calldll_t syscalldll, const char *qvmname, sys_callqvm_t syscallqvm) { vm_t *vm; - if(!name || !*name) - Sys_Error("VM_Create: bad parms"); vm = Z_Malloc(sizeof(vm_t)); // prepare vm struct memset(vm, 0, sizeof(vm_t)); - Q_strncpyz(vm->filename, name, sizeof(vm->filename)); + Q_strncpyz(vm->filename, "", sizeof(vm->filename)); vm->syscalldll=syscalldll; vm->syscallqvm=syscallqvm; @@ -1001,9 +1014,9 @@ vm_t *VM_Create(const char *name, sys_calldll_t syscalldll, sys_callqvm_t syscal { if (!COM_CheckParm("-nodlls") && !COM_CheckParm("-nosos")) //:) { - if(QVM_LoadDLL(vm, name, !syscallqvm, (void**)&vm->vmMain, syscalldll)) + if(QVM_LoadDLL(vm, dllname, !syscallqvm, (void**)&vm->vmMain, syscalldll)) { - Con_DPrintf("Creating native machine \"%s\"\n", name); + Con_DPrintf("Creating native machine \"%s\"\n", dllname); vm->type=VM_NATIVE; return vm; } @@ -1013,9 +1026,9 @@ vm_t *VM_Create(const char *name, sys_calldll_t syscalldll, sys_callqvm_t syscal if (syscallqvm) { - if(QVM_LoadVM(vm, name, syscallqvm)) + if(QVM_LoadVM(vm, qvmname, syscallqvm)) { - Con_DPrintf("Creating virtual machine \"%s\"\n", name); + Con_DPrintf("Creating virtual machine \"%s\"\n", qvmname); vm->type=VM_BYTECODE; return vm; } diff --git a/engine/common/vm.h b/engine/common/vm.h index e0752e738..5784664e4 100644 --- a/engine/common/vm.h +++ b/engine/common/vm.h @@ -21,7 +21,7 @@ typedef struct vm_s vm_t; void VM_PrintInfo(vm_t *vm); vm_t *VM_CreateBuiltin(const char *name, sys_calldll_t syscalldll, qintptr_t (*init)(qintptr_t *args)); -vm_t *VM_Create(const char *name, sys_calldll_t syscalldll, sys_callqvm_t syscallqvm); +vm_t *VM_Create(const char *dllname, sys_calldll_t syscalldll, const char *qvmname, sys_callqvm_t syscallqvm); const char *VM_GetFilename(vm_t *vm); void VM_Destroy(vm_t *vm); //qboolean VM_Restart(vm_t *vm); diff --git a/engine/server/pr_q1qvm.c b/engine/server/pr_q1qvm.c index b5e216b9e..9b13af9a1 100755 --- a/engine/server/pr_q1qvm.c +++ b/engine/server/pr_q1qvm.c @@ -2152,9 +2152,9 @@ qboolean PR_LoadQ1QVM(void) Q1QVM_Shutdown(true); - q1qvm = VM_Create("qwprogs", com_nogamedirnativecode.ival?NULL:syscallnative, syscallqvm); + q1qvm = VM_Create("qwprogs", com_nogamedirnativecode.ival?NULL:syscallnative, "qwprogs", syscallqvm); if (!q1qvm) - q1qvm = VM_Create("qwprogs", syscallnative, NULL); + q1qvm = VM_Create("qwprogs", syscallnative, "qwprogs", NULL); if (!q1qvm) { if (svprogfuncs == &q1qvmprogfuncs) diff --git a/engine/server/sv_main.c b/engine/server/sv_main.c index 7fb45dd75..7ad5e5580 100644 --- a/engine/server/sv_main.c +++ b/engine/server/sv_main.c @@ -64,7 +64,7 @@ extern cvar_t password; #endif cvar_t spectator_password = CVARF("spectator_password", "", CVAR_NOUNSAFEEXPAND); // password for entering as a sepctator -cvar_t allow_download = CVARD("allow_download", "1", "If 1, permits downloading. Set to 0 to unconditionally block *ALL* downloads."); +cvar_t allow_download = CVARAD("allow_download", /*q3*/"sv_allowDownload", "1", "If 1, permits downloading. Set to 0 to unconditionally block *ALL* downloads."); cvar_t allow_download_skins = CVARD("allow_download_skins", "1", "0 blocks downloading of any file in the skins/ directory"); cvar_t allow_download_models = CVARD("allow_download_models", "1", "0 blocks downloading of any file in the progs/ or models/ directory"); cvar_t allow_download_sounds = CVARD("allow_download_sounds", "1", "0 blocks downloading of any file in the sound/ directory"); diff --git a/engine/server/svq3_game.c b/engine/server/svq3_game.c index 75a407e1e..74229cc21 100644 --- a/engine/server/svq3_game.c +++ b/engine/server/svq3_game.c @@ -862,7 +862,7 @@ static void SVQ3_Adjust_Area_Portal_State(q3sharedEntity_t *ge, qboolean open) } #define VALIDATEPOINTER(o,l) if ((int)o + l >= mask || VM_POINTER(o) < offset) SV_Error("Call to game trap %u passes invalid pointer\n", (unsigned int)fn); //out of bounds. -static qintptr_t Q3G_SystemCalls(void *offset, unsigned int mask, qintptr_t fn, const qintptr_t *arg) +static qintptr_t Q3G_SystemCalls(void *offset, quintptr_t mask, qintptr_t fn, const qintptr_t *arg) { int ret = 0; switch(fn) @@ -1615,7 +1615,7 @@ static qintptr_t EXPORT_FN Q3G_SystemCallsNative(qintptr_t arg, ...) args[12]=va_arg(argptr, qintptr_t); va_end(argptr); - return Q3G_SystemCalls(NULL, ~0, arg, args); + return Q3G_SystemCalls(NULL, ~(quintptr_t)0, arg, args); } void SVQ3_ShutdownGame(void) @@ -1890,7 +1890,7 @@ qboolean SVQ3_InitGame(void) SVQ3_ShutdownGame(); - q3gamevm = VM_Create("vm/qagame", com_nogamedirnativecode.ival?NULL:Q3G_SystemCallsNative, Q3G_SystemCallsVM); + q3gamevm = VM_Create("qagame", com_nogamedirnativecode.ival?NULL:Q3G_SystemCallsNative, "vm/qagame", Q3G_SystemCallsVM); if (!q3gamevm) return false;