From 2bedc32ff97e73a548df1382523528b7dbcdc5d7 Mon Sep 17 00:00:00 2001 From: Spoike Date: Tue, 23 Oct 2018 07:09:06 +0000 Subject: [PATCH] Misc tweaks. Fix potentially serious crash with sprites+csqc tracelines. Reworked fallback mouse cursor. Fix decals on q3 bmodels. Double-click to select a work to copy is now implemented. git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@5323 fc73d0e0-1445-4013-8a0c-d673dee63da5 --- CMakeLists.txt | 7 ++ engine/Makefile | 4 +- engine/client/cl_ents.c | 2 +- engine/client/cl_main.c | 66 ++++++------ engine/client/cl_pred.c | 1 + engine/client/cl_screen.c | 109 ++++++++++++++++--- engine/client/console.c | 101 +++++++++++++++++- engine/client/image.c | 2 +- engine/client/in_win.c | 2 +- engine/client/keys.c | 179 ++++++++++++++++++++------------ engine/client/merged.h | 2 +- engine/client/pr_csqc.c | 67 +++++++----- engine/client/r_2d.c | 2 +- engine/client/sys_win.c | 64 +++--------- engine/client/view.c | 4 +- engine/client/wad.c | 2 +- engine/client/winquake.h | 2 +- engine/common/bothdefs.h | 8 +- engine/common/common.h | 4 +- engine/common/config_fteqw.h | 1 + engine/common/console.h | 51 +++++---- engine/common/fs.c | 161 ++++++++++++++++------------ engine/common/net.h | 1 + engine/common/net_ssl_gnutls.c | 6 +- engine/common/net_ssl_winsspi.c | 4 +- engine/common/net_wins.c | 107 ++++++++++++++++--- engine/common/netinc.h | 10 ++ engine/common/pr_bgcmd.c | 9 +- engine/common/q1bsp.c | 11 +- engine/common/sha1.c | 2 +- engine/gl/gl_font.c | 2 + engine/gl/gl_model.h | 2 +- engine/gl/gl_shader.c | 22 +++- engine/gl/gl_vidlinuxglx.c | 54 ++-------- engine/gl/gl_vidsdl.c | 41 +++----- engine/http/httpclient.c | 2 +- engine/qclib/qcc.h | 3 + engine/qclib/qcc_pr_comp.c | 97 ++++++++++++----- engine/qclib/qcc_pr_lex.c | 20 +++- engine/qclib/qccmain.c | 44 ++++++-- engine/server/net_preparse.c | 72 ++++++++----- engine/server/pr_cmds.c | 38 +++++++ engine/server/server.h | 2 +- engine/server/sv_ccmds.c | 7 +- engine/server/sv_ents.c | 3 +- engine/server/sv_main.c | 13 ++- engine/server/sv_phys.c | 36 ++++--- engine/server/sv_user.c | 37 ++----- engine/server/world.c | 2 +- 49 files changed, 968 insertions(+), 520 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 876a014a5..722962278 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -195,6 +195,7 @@ ELSEIF(${UNIX}) #linux(ish) engine/client/sys_linux.c engine/common/sys_linux_threads.c engine/common/net_ssl_gnutls.c +# engine/common/net_ssl_openssl.c engine/client/snd_al.c engine/client/snd_alsa.c @@ -241,8 +242,14 @@ ELSEIF(${UNIX}) #linux(ish) engine/server/sv_sys_unix.c engine/common/sys_linux_threads.c engine/common/net_ssl_gnutls.c +# engine/common/net_ssl_openssl.c ) SET(FTESV_LIBS ${ZLIB_LIBRARIES} m ${CMAKE_DL_LIBS} pthread) + +# SET(FTE_DEFINES ${FTE_DEFINES};HAVE_OPENSSL) +# SET(FTESV_DEFINES ${FTESV_DEFINES};HAVE_OPENSSL) +# SET(FTE_LIBS ${FTE_LIBS} ssl crypto) +# SET(FTESV_LIBS ${FTE_LIBS} ssl crypto) ELSEIF(1) #SDL # FIND_PACKAGE(Freetype REQUIRED) # INCLUDE_DIRECTORIES(engine/libs engine/libs/freetype2/include) diff --git a/engine/Makefile b/engine/Makefile index d4956a4f0..aef92f4d3 100644 --- a/engine/Makefile +++ b/engine/Makefile @@ -1638,8 +1638,8 @@ BASELDFLAGS:=-L$(ARCHLIBS) $(BASELDFLAGS) .default: help all: rel -rel: sv-rel m-rel mingl-rel qcc-rel -dbg: sv-dbg m-dbg mingl-dbg qcc-dbg +rel: sv-rel m-rel qcc-rel +dbg: sv-dbg m-dbg qcc-dbg relcl: glcl-rel mcl-rel profile: sv-profile gl-profile mingl-profile diff --git a/engine/client/cl_ents.c b/engine/client/cl_ents.c index 862c5c4c6..c263aa058 100644 --- a/engine/client/cl_ents.c +++ b/engine/client/cl_ents.c @@ -5496,7 +5496,7 @@ void CL_SetSolidEntities (void) 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. */ - if (!(cls.fteprotocolextensions2 & PEXT2_REPLACEMENTDELTAS) && !((*cl.model_precache[state->modelindex]->name == '*' || cl.model_precache[state->modelindex]->numsubmodels) && cl.model_precache[state->modelindex]->hulls[1].firstclipnode)) + if (!(cls.fteprotocolextensions2 & PEXT2_REPLACEMENTDELTAS) && !((*cl.model_precache[state->modelindex]->name == '*' || cl.model_precache[state->modelindex]->numsubmodels) && cl.model_precache[state->modelindex]->funcs.NativeTrace)) continue; pent = &pmove.physents[pmove.numphysent]; diff --git a/engine/client/cl_main.c b/engine/client/cl_main.c index 7aa1e6d27..f817a8929 100644 --- a/engine/client/cl_main.c +++ b/engine/client/cl_main.c @@ -2973,7 +2973,7 @@ void CL_ConnectionlessPacket (void) unsigned int curtime = Sys_Milliseconds(); unsigned long pext = 0, pext2 = 0, huffcrc=0, mtu=0; #ifdef HAVE_DTLS - qboolean candtls = false; + int candtls = 0; //0=no,1=optional,2=mandatory #endif char guidhash[256]; @@ -3183,6 +3183,10 @@ void CL_ConnectionlessPacket (void) //c2s DTLS(getchallenge) //DTLS(etc) + //getchallenge has to be done twice, with the outer one only reporting whether dtls can/should be used. + //this means the actual connect packet is already over dtls, which protects the user's userinfo. + //FIXME: do rcon via dtls too, but requires tracking pending rcon packets until the handshake completes. + //server says it can do tls. char *pkt = va("%c%c%c%cdtlsconnect %i", 255, 255, 255, 255, connectinfo.challenge); NET_SendPacket (NS_CLIENT, strlen(pkt), pkt, &net_from); @@ -3440,9 +3444,9 @@ client_connect: //fixme: make function if (cls.netchan.remote_address.type != NA_LOOPBACK) { 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 (encrypted).\n"); + Con_TPrintf ("Connected (^2encrypted^7).\n"); else - Con_TPrintf ("Connected (plain-text).\n"); + Con_TPrintf ("Connected (^1plain-text^7).\n"); } #ifdef QUAKESPYAPI allowremotecmd = false; // localid required now for remote cmds @@ -5666,12 +5670,12 @@ double Host_Frame (double time) if (cl.paused) cl.gametimemark += time; - idle = (cls.state == ca_disconnected) || + idle = (cls.state == ca_disconnected) || #ifdef VM_UI - UI_MenuState() != 0 || + UI_MenuState() != 0 || #endif - Key_Dest_Has(kdm_gmenu) || - Key_Dest_Has(kdm_emenu) || + Key_Dest_Has(kdm_gmenu) || + Key_Dest_Has(kdm_emenu) || Key_Dest_Has(kdm_editor) || !vid.activeapp || cl.paused @@ -5724,7 +5728,7 @@ double Host_Frame (double time) if (sv.state && cls.state != ca_active) { maxfpsignoreserver = false; - maxfps = 0; + maxfps = cl_maxfps.ival; } else #endif @@ -6042,9 +6046,6 @@ void CL_StartCinematicOrMenu(void) Con_ClearNotify(); - TP_ExecTrigger("f_startup", true); - Cbuf_Execute (); - if (com_installer) { com_installer = false; @@ -6055,12 +6056,15 @@ void CL_StartCinematicOrMenu(void) #endif } + if (!sv_state && !cls.demoinfile && !cls.state && !*cls.servername && !Media_PlayingFullScreen()) + { + TP_ExecTrigger("f_startup", true); + Cbuf_Execute (); + } + //and any startup cinematics #ifdef HAVE_MEDIA_DECODER -#ifndef CLIENTONLY - if (!sv.state) -#endif - if (!cls.demoinfile && !cls.state && !*cls.servername && !Media_PlayingFullScreen()) + if (!sv_state && !cls.demoinfile && !cls.state && !*cls.servername && !Media_PlayingFullScreen()) { int ol_depth; int idcin_depth; @@ -6091,30 +6095,25 @@ void CL_StartCinematicOrMenu(void) } #endif - if (!cls.demoinfile && !cls.state && !*cls.servername && !Media_PlayingFullScreen()) + if (!sv_state && !cls.demoinfile && !cls.state && !*cls.servername && !Media_PlayingFullScreen()) { -#ifndef CLIENTONLY - if (!sv.state) -#endif + if (qrenderer > QR_NONE && !Key_Dest_Has(kdm_emenu)) { - if (qrenderer > QR_NONE && !Key_Dest_Has(kdm_emenu)) - { #ifndef NOBUILTINMENUS - if (!cls.state && !Key_Dest_Has(kdm_emenu) && !*FS_GetGamedir(false)) - M_Menu_Mods_f(); + if (!cls.state && !Key_Dest_Has(kdm_emenu) && !*FS_GetGamedir(false)) + M_Menu_Mods_f(); #endif - if (!cls.state && !Key_Dest_Has(kdm_emenu) && cl_demoreel.ival) - { - cls.demonum = 0; - CL_NextDemo(); - } - if (!cls.state && !Key_Dest_Has(kdm_emenu)) - //if we're (now) meant to be using csqc for menus, make sure that its running. - if (!CSQC_UnconnectedInit()) - M_ToggleMenu_f(); + if (!cls.state && !Key_Dest_Has(kdm_emenu) && cl_demoreel.ival) + { + cls.demonum = 0; + CL_NextDemo(); } - //Con_ForceActiveNow(); + if (!cls.state && !Key_Dest_Has(kdm_emenu)) + //if we're (now) meant to be using csqc for menus, make sure that its running. + if (!CSQC_UnconnectedInit()) + M_ToggleMenu_f(); } + //Con_ForceActiveNow(); } } @@ -6367,6 +6366,7 @@ void Host_Init (quakeparms_t *parms) Sys_Quit(); return; } + PM_Shutdown(); //will restart later as needed, but we need to be sure that no files are open or anything. } V_Init (); NET_Init (); diff --git a/engine/client/cl_pred.c b/engine/client/cl_pred.c index fd5772969..cc9b55838 100644 --- a/engine/client/cl_pred.c +++ b/engine/client/cl_pred.c @@ -1166,6 +1166,7 @@ void CL_PredictMovePNum (int seat) } if (i == pe->num_entities && pv->nolocalplayer) { + return; fromstate = &nullstate; nopred = true; } diff --git a/engine/client/cl_screen.c b/engine/client/cl_screen.c index 7662472f6..ab087f8fc 100644 --- a/engine/client/cl_screen.c +++ b/engine/client/cl_screen.c @@ -991,27 +991,104 @@ void SCR_DrawCursor(void) oldcurs = key_customcursor[cmod].handle; if (rf->VID_CreateCursor && strcmp(key_customcursor[cmod].name, "none")) { + image_t dummytex; + flocation_t loc; + char bestname[MAX_QPATH]; + unsigned int bestflags; + qbyte *rgbadata; + uploadfmt_t format; + void *filedata = NULL; + int filelen = 0, width, height; + key_customcursor[cmod].handle = NULL; - if (!key_customcursor[cmod].handle && *key_customcursor[cmod].name) + + memset(&dummytex, 0, sizeof(dummytex)); + dummytex.flags = IF_NOREPLACE; //no dds files + *bestname = 0; + + //first try the named image, if possible + if (!filedata && *key_customcursor[cmod].name) { - image_t dummytex; - flocation_t loc; - char bestname[MAX_QPATH]; - unsigned int bestflags; - memset(&dummytex, 0, sizeof(dummytex)); dummytex.ident = key_customcursor[cmod].name; - dummytex.flags = IF_NOREPLACE; //no dds files if (Image_LocateHighResTexture(&dummytex, &loc, bestname, sizeof(bestname), &bestflags)) - key_customcursor[cmod].handle = rf->VID_CreateCursor(bestname, key_customcursor[cmod].hotspot[0], key_customcursor[cmod].hotspot[1], key_customcursor[cmod].scale); - else - key_customcursor[cmod].handle = rf->VID_CreateCursor(key_customcursor[cmod].name, key_customcursor[cmod].hotspot[0], key_customcursor[cmod].hotspot[1], key_customcursor[cmod].scale); + filelen = FS_LoadFile(bestname, &filedata); + } + if (!filedata) + { + dummytex.ident = "gfx/cursor.lmp"; + if (Image_LocateHighResTexture(&dummytex, &loc, bestname, sizeof(bestname), &bestflags)) + filelen = FS_LoadFile(bestname, &filedata); + } + if (!filedata) + { + static qbyte lamecursor[] = + { +#define W 0x8f,0x8f,0x8f,0xff, +#define B 0x00,0x00,0x00,0xff, +#define T 0x00,0x00,0x00,0x00, + W T T T T T T T + W W T T T T T T + W B W T T T T T + W B B W T T T T + + W B B B W T T T + W B B B B W T T + W B B B B B W T + W B B B B B B W + + W B B B B W W W + W B W B B W T T + W W T W B B W T + W T T W B B W T + + T T T T W B B W + T T T T W B B W + T T T T T W W T +#undef W +#undef B + }; + key_customcursor[cmod].handle = rf->VID_CreateCursor(lamecursor, 8, 15, PTI_LLLA8, 0, 0, 1); //try the fallback + } + else if (!filedata) + FS_FreeFile(filedata); //format not okay, just free it. + else + { //raw file loaded. + rgbadata = ReadRawImageFile(filedata, filelen, &width, &height, &format, true, bestname); + FS_FreeFile(filedata); + if (rgbadata) + { //image loaded properly, yay + if ((format==PTI_RGBX8 || format==PTI_LLLX8) && !strchr(bestname, ':')) + { //people seem to insist on using jpgs, which don't have alpha. + //so screw over the alpha channel if needed. + unsigned int alpha_width, alpha_height, p; + char aname[MAX_QPATH]; + unsigned char *alphadata; + char *alph; + size_t alphsize; + char ext[8]; + COM_StripExtension(bestname, aname, sizeof(aname)); + COM_FileExtension(bestname, ext, sizeof(ext)); + Q_strncatz(aname, "_alpha.", sizeof(aname)); + Q_strncatz(aname, ext, sizeof(aname)); + alphsize = FS_LoadFile(aname, (void**)&alph); + if (alph) + { + if ((alphadata = ReadRawImageFile(alph, alphsize, &alpha_width, &alpha_height, &format, true, aname))) + { + if (alpha_width == width && alpha_height == height) + for (p = 0; p < alpha_width*alpha_height; p++) + rgbadata[(p<<2) + 3] = (alphadata[(p<<2) + 0] + alphadata[(p<<2) + 1] + alphadata[(p<<2) + 2])/3; + BZ_Free(alphadata); + } + FS_FreeFile(alph); + } + format = (format==PTI_LLLX8)?PTI_LLLA8:PTI_RGBA8; + } + + key_customcursor[cmod].handle = rf->VID_CreateCursor(rgbadata, width, height, format, key_customcursor[cmod].hotspot[0], key_customcursor[cmod].hotspot[1], key_customcursor[cmod].scale); //try the fallback + BZ_Free(rgbadata); + } } - if (!key_customcursor[cmod].handle) - key_customcursor[cmod].handle = rf->VID_CreateCursor("gfx/cursor.tga", key_customcursor[cmod].hotspot[0], key_customcursor[cmod].hotspot[1], key_customcursor[cmod].scale); //try the fallback - if (!key_customcursor[cmod].handle) - key_customcursor[cmod].handle = rf->VID_CreateCursor("gfx/cursor.png", key_customcursor[cmod].hotspot[0], key_customcursor[cmod].hotspot[1], key_customcursor[cmod].scale); //try the fallback - if (!key_customcursor[cmod].handle) - key_customcursor[cmod].handle = rf->VID_CreateCursor("gfx/cursor.lmp", key_customcursor[cmod].hotspot[0], key_customcursor[cmod].hotspot[1], key_customcursor[cmod].scale); //try the fallback } else key_customcursor[cmod].handle = NULL; diff --git a/engine/client/console.c b/engine/client/console.c index e8629a947..04bedbf96 100644 --- a/engine/client/console.c +++ b/engine/client/console.c @@ -697,6 +697,11 @@ void Con_Init (void) con_main.linebuffered = Con_ExecuteLine; con_main.commandcompletion = true; +// con_main.flags |= CONF_ISWINDOW; + con_main.wnd_w = 640; + con_main.wnd_h = 480; + con_main.wnd_x = 0; + con_main.wnd_y = 0; Q_strncpyz(con_main.title, "MAIN", sizeof(con_main.title)); Q_strncpyz(con_main.prompt, "]", sizeof(con_main.prompt)); @@ -2571,7 +2576,7 @@ void Con_DrawConsole (int lines, qboolean noback) } //draw main console... - if (lines > 0) + if (lines > 0 && !(con_current->flags & CONF_ISWINDOW)) { int top; #ifdef QTERM @@ -2935,18 +2940,106 @@ static qbyte Con_IsTokenChar(unsigned int chr) return true; if (chr == '(' || chr == ')' || chr == '{' || chr == '}') return false; - if (chr == '.' || chr == '/' || chr == '\\') - return 2; + if (chr == '/' || chr == '\\') + return 2; //on left only + if (chr == '.' || chr == ':') + return 3; //disallow only if followed by whitespace if (chr >= 'a' && chr <= 'z') return true; if (chr >= 'A' && chr <= 'Z') return true; if (chr >= '0' && chr <= '9') return true; - if (chr == '[' || chr == ']' || chr == '_' || chr == ':') + if (chr == '[' || chr == ']' || chr == '_') return true; return false; } +void Con_ExpandConsoleSelection(console_t *con) +{ + conchar_t *cur, *n; + conline_t *l; + conchar_t *lstart; + conchar_t *lend; + unsigned int cf, uc; + + //no selection to expand... + if (!con->selstartline || !con->selendline) + return; + + l = con->selstartline; + lstart = (conchar_t*)(l+1); + cur = lstart + con->selstartoffset; + + if (con->selstartline == con->selendline) + { + if (con->selstartoffset+1 == con->selendoffset) + { + //they only selected a single char? + //fix that up to select the entire token + while (cur > lstart) + { + cur--; + uc = (*cur & CON_CHARMASK); + if (!Con_IsTokenChar(uc)) + { + cur++; + break; + } + if (*cur == CON_LINKSTART) + break; + } + for (n = lstart+con->selendoffset; con->selendoffset < l->length; ) + { + n = Font_Decode(n, &cf, &uc); + if (Con_IsTokenChar(uc)==3) + continue; + + if (Con_IsTokenChar(uc)==1 && lstart[con->selendoffset] != CON_LINKEND) + con->selendoffset = n-lstart; + else + break; + } + /*while (con->selendoffset > l->length) + { + uc = (((conchar_t*)(l+1))[con->selendoffset] & CON_CHARMASK); + if (Con_IsTokenChar(uc) == 2) + con->selendoffset--; + else + break; + }*/ + } + } + + //scan backwards to find any link enclosure + for(lend = cur-1; lend >= (conchar_t*)(l+1); lend--) + { + if (*lend == CON_LINKSTART) + { + //found one + cur = lend; + break; + } + if (*lend == CON_LINKEND) + { + //some other link ended here. don't use its start. + break; + } + } + //scan forwards to find the end of the selected link + if (l->length && cur < (conchar_t*)(l+1)+l->length && *cur == CON_LINKSTART) + { + for(lend = (conchar_t*)(con->selendline+1) + con->selendoffset; lend < (conchar_t*)(con->selendline+1) + con->selendline->length; lend++) + { + if (*lend == CON_LINKEND) + { + con->selendoffset = lend+1 - (conchar_t*)(con->selendline+1); + break; + } + } + } + + con->selstartoffset = cur-(conchar_t*)(l+1); +} char *Con_CopyConsole(console_t *con, qboolean nomarkup, qboolean onlyiflink) { conchar_t *cur; diff --git a/engine/client/image.c b/engine/client/image.c index 0f3f777f3..7472cca44 100644 --- a/engine/client/image.c +++ b/engine/client/image.c @@ -5358,7 +5358,7 @@ static pixel32_t *Image_Block_Decode(qbyte *fte_restrict in, size_t insize, int sizediff = insize - blockbytes*((w+blockwidth-1)/blockwidth)*((h+blockheight-1)/blockheight); if (sizediff) { - Con_Printf("Image_Block_Decode: %s data size is %u, expected %u\n\n", Image_FormatName(encoding), insize, insize-sizediff); + Con_Printf("Image_Block_Decode: %s data size is %u, expected %u\n\n", Image_FormatName(encoding), (unsigned int)insize, (unsigned int)(insize-sizediff)); if (sizediff < 0) return NULL; } diff --git a/engine/client/in_win.c b/engine/client/in_win.c index 28172ff5f..e3cf5a263 100644 --- a/engine/client/in_win.c +++ b/engine/client/in_win.c @@ -162,7 +162,7 @@ qboolean mouseactive; static cvar_t in_joystick = CVARAF("joystick","0", "in_joystick", CVAR_ARCHIVE); static qboolean joy_advancedinit; -static DWORD joy_flags; +static DWORD joy_flags = JOY_RETURNALL|JOY_RETURNCENTERED; #define MAX_JOYSTICKS 8 static struct wjoy_s { qboolean isxinput; //xinput device diff --git a/engine/client/keys.c b/engine/client/keys.c index ad33e341f..e4c6cb024 100644 --- a/engine/client/keys.c +++ b/engine/client/keys.c @@ -671,7 +671,7 @@ qboolean Key_GetConsoleSelectionBox(console_t *con, int *sx, int *sy, int *ex, i { *sx = *sy = *ex = *ey = 0; - if (con->buttonsdown == CB_SCROLL) + if (con->buttonsdown == CB_SCROLL || con->buttonsdown == CB_SCROLL_R) { //left-mouse. //scroll the console with the mouse. trigger links on release. @@ -1071,6 +1071,52 @@ void Key_DefaultLinkClicked(console_t *con, char *text, char *info) } } +void Key_HandleConsoleLink(console_t *con, char *buffer) +{ + if (!buffer) + return; + if (buffer[0] == '^' && buffer[1] == '[') + { + //looks like it might be a link! + char *end = NULL; + char *info; + for (info = buffer + 2; *info; ) + { + if (info[0] == '^' && info[1] == ']') + break; //end of tag, with no actual info, apparently + if (*info == '\\') + break; + else if (info[0] == '^' && info[1] == '^') + info+=2; + else + info++; + } + for(end = info; *end; ) + { + if (end[0] == '^' && end[1] == ']') + { + //okay, its a valid link that they clicked + *end = 0; +#ifdef PLUGINS + if (!Plug_ConsoleLink(buffer+2, info, con->name)) +#endif +#ifdef CSQC_DAT + if (!CSQC_ConsoleLink(buffer+2, info)) +#endif + { + Key_DefaultLinkClicked(con, buffer+2, info); + } + + break; + } + if (end[0] == '^' && end[1] == '^') + end+=2; + else + end++; + } + } +} + #define Key_IsTouchScreen() false void Key_ConsoleRelease(console_t *con, int key, unsigned int unicode) { @@ -1083,33 +1129,48 @@ void Key_ConsoleRelease(console_t *con, int key, unsigned int unicode) if (con->selstartline) { if (con->selstartline == con->selendline && con->selendoffset <= con->selstartoffset+1) - con->flags &= ~CONF_KEEPSELECTION; - else - con->flags |= CONF_KEEPSELECTION; - if (con->userdata) { - if (con->flags & CONF_BACKSELECTION) - { - con->userline = con->selendline; - con->useroffset = con->selendoffset; - } + con->flags &= ~CONF_KEEPSELECTION; + if (keydown[K_LSHIFT] || keydown[K_RSHIFT]) + ; else { - con->userline = con->selstartline; - con->useroffset = con->selstartoffset; + buffer = Con_CopyConsole(con, false, true); + if (buffer) + { + Key_HandleConsoleLink(con, buffer); + Z_Free(buffer); + } + } + } + else + { + con->flags |= CONF_KEEPSELECTION; + if (con->userdata) + { + if (con->flags & CONF_BACKSELECTION) + { + con->userline = con->selendline; + con->useroffset = con->selendoffset; + } + else + { + con->userline = con->selstartline; + con->useroffset = con->selstartoffset; + } + } + + buffer = Con_CopyConsole(con, true, false); //don't keep markup if we're copying to the clipboard + if (buffer) + { + Sys_SaveClipboard(CBT_SELECTION, buffer); + Z_Free(buffer); } } } con->buttonsdown = CB_NONE; - - buffer = Con_CopyConsole(con, true, false); //don't keep markup if we're copying to the clipboard - if (buffer) - { - Sys_SaveClipboard(CBT_SELECTION, buffer); - Z_Free(buffer); - } } - if (key == K_MOUSE1 && con->buttonsdown == CB_SCROLL) + if ((key == K_MOUSE1 && con->buttonsdown == CB_SCROLL) || (key == K_MOUSE2 && con->buttonsdown == CB_SCROLL_R)) { con->buttonsdown = CB_NONE; if (abs(con->mousedown[0] - con->mousecursor[0]) < 5 && abs(con->mousedown[1] - con->mousecursor[1]) < 5) @@ -1138,48 +1199,7 @@ void Key_ConsoleRelease(console_t *con, int key, unsigned int unicode) Key_ConsoleInsert(buffer); } else - { - if (buffer[0] == '^' && buffer[1] == '[') - { - //looks like it might be a link! - char *end = NULL; - char *info; - for (info = buffer + 2; *info; ) - { - if (info[0] == '^' && info[1] == ']') - break; //end of tag, with no actual info, apparently - if (*info == '\\') - break; - else if (info[0] == '^' && info[1] == '^') - info+=2; - else - info++; - } - for(end = info; *end; ) - { - if (end[0] == '^' && end[1] == ']') - { - //okay, its a valid link that they clicked - *end = 0; -#ifdef PLUGINS - if (!Plug_ConsoleLink(buffer+2, info, con->name)) -#endif -#ifdef CSQC_DAT - if (!CSQC_ConsoleLink(buffer+2, info)) -#endif - { - Key_DefaultLinkClicked(con, buffer+2, info); - } - - break; - } - if (end[0] == '^' && end[1] == '^') - end+=2; - else - end++; - } - } - } + Key_HandleConsoleLink(con, buffer); Z_Free(buffer); } else @@ -1553,6 +1573,7 @@ qboolean Key_Console (console_t *con, int key, unsigned int unicode) qboolean ctrl = keydown[K_LCTRL] || keydown[K_RCTRL]; qboolean shift = keydown[K_LSHIFT] || keydown[K_RSHIFT]; int rkey = key; + char *buffer; //weirdness for the keypad. if ((unicode >= '0' && unicode <= '9') || unicode == '.' || key < 0) @@ -1576,6 +1597,7 @@ qboolean Key_Console (console_t *con, int key, unsigned int unicode) if ((key == K_MOUSE1 || key == K_MOUSE2)) { + int olddown[2] = {con->mousedown[0],con->mousedown[1]}; if (con->flags & CONF_ISWINDOW) if (con->mousecursor[0] < -8 || con->mousecursor[1] < 0 || con->mousecursor[0] > con->wnd_w || con->mousecursor[1] > con->wnd_h) return true; @@ -1609,8 +1631,12 @@ qboolean Key_Console (console_t *con, int key, unsigned int unicode) { if (con->redirect && con->redirect(con, unicode, key)) return true; - con->buttonsdown = CB_COPY; + con->flags &= ~CONF_KEEPSELECTION; + if (Key_IsTouchScreen()) //o.O mouse2+touchscreen? really? + con->buttonsdown = CB_COPY; + else + con->buttonsdown = CB_SCROLL_R; } else { @@ -1625,13 +1651,38 @@ qboolean Key_Console (console_t *con, int key, unsigned int unicode) { if (con->redirect && con->redirect(con, unicode, key)) return true; - if (Key_IsTouchScreen()) + if (Key_IsTouchScreen() || con->mousecursor[0] > ((con->flags & CONF_ISWINDOW)?con->wnd_w-16:vid.width)-8) { //just scroll the console up/down con->buttonsdown = CB_SCROLL; } else { //selecting text. woo. + if (realtime < con->mousedowntime + 0.4 + && con->mousecursor[0] >= olddown[0]-3 && con->mousecursor[0] <= olddown[0]+3 + && con->mousecursor[1] >= olddown[1]-3 && con->mousecursor[1] <= olddown[1]+3 + ) + { //this was a double-click... expand the selection to the entire word + //FIXME: detect tripple-clicks to select the entire line + Con_ExpandConsoleSelection(con); + con->flags |= CONF_KEEPSELECTION; + + buffer = Con_CopyConsole(con, true, false); //don't keep markup if we're copying to the clipboard + if (buffer) + { + Sys_SaveClipboard(CBT_SELECTION, buffer); + Z_Free(buffer); + } + return true; + } + con->mousedowntime = realtime; + con->buttonsdown = CB_SELECT; + + if (shift) + { + con->mousedown[0] = olddown[0]; + con->mousedown[1] = olddown[1]; + } } con->flags &= ~CONF_KEEPSELECTION; } diff --git a/engine/client/merged.h b/engine/client/merged.h index fa119ed2f..42c738569 100644 --- a/engine/client/merged.h +++ b/engine/client/merged.h @@ -424,7 +424,7 @@ typedef struct rendererinfo_s { void (*VID_SwapBuffers) (void); //force a buffer swap, regardless of what's displayed. qboolean (*VID_ApplyGammaRamps) (unsigned int size, unsigned short *ramps); - void *(*VID_CreateCursor) (const char *filename, float hotx, float hoty, float scale); //may be null, stub returns null + void *(*VID_CreateCursor) (const qbyte *imagedata, int width, int height, uploadfmt_t format, float hotx, float hoty, float scale); //may be null, stub returns null qboolean (*VID_SetCursor) (void *cursor); //may be null void (*VID_DestroyCursor) (void *cursor); //may be null diff --git a/engine/client/pr_csqc.c b/engine/client/pr_csqc.c index 9c9cf8beb..5e275ec06 100644 --- a/engine/client/pr_csqc.c +++ b/engine/client/pr_csqc.c @@ -2467,8 +2467,8 @@ static void QCBUILTIN PF_cs_getstati(pubprogfuncs_t *prinst, struct globalvars_s int stnum = G_FLOAT(OFS_PARM0); if (stnum < 0 || stnum >= MAX_CL_STATS) { - G_FLOAT(OFS_RETURN) = 0; - PR_RunWarning(prinst, "invalid stat index"); + G_INT(OFS_RETURN) = 0; + PR_RunWarning(prinst, "PF_cs_getstati: invalid stat index (%i)\n", stnum); } else if (stnum >= 128 && csqc_isdarkplaces && cls.protocol != CP_NETQUAKE && !CPNQ_IS_DP) { //dpp7 stats are fucked. @@ -2486,7 +2486,7 @@ static void QCBUILTIN PF_cs_getstatbits(pubprogfuncs_t *prinst, struct globalvar if (stnum < 0 || stnum >= MAX_CL_STATS) { G_FLOAT(OFS_RETURN) = 0; - PR_RunWarning(prinst, "invalid stat index"); + PR_RunWarning(prinst, "PF_cs_getstatbits: invalid stat index (%i)\n", stnum); } else if (prinst->callargc > 1) { @@ -2515,14 +2515,14 @@ static void QCBUILTIN PF_cs_getstats(pubprogfuncs_t *prinst, struct globalvars_s if (stnum < 0 || stnum >= MAX_CL_STATS) { G_INT(OFS_RETURN) = 0; - PR_RunWarning(prinst, "invalid stat index"); + PR_RunWarning(prinst, "PF_cs_getstats: invalid stat index (%i)\n", stnum); } else if (cls.fteprotocolextensions & PEXT_CSQC) RETURN_TSTRING(csqc_playerview->statsstr[stnum]); - else if (stnum >= MAX_CL_STATS-3) + else if (stnum >= MAX_CL_STATS-3) //we'll be reading the following 3 extra stats too. { G_INT(OFS_RETURN) = 0; - PR_RunWarning(prinst, "invalid stat index"); + PR_RunWarning(prinst, "PF_cs_getstats: invalid packed-string stat index (%i)\n", stnum); } else { @@ -5751,7 +5751,7 @@ static void QCBUILTIN PF_cs_getplayerstat(pubprogfuncs_t *prinst, struct globalv } } - +void CL_CalcCrouch (playerview_t *pv); static void QCBUILTIN PF_V_CalcRefdef(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) { //this function is essentially an overcomplicated way to shirk from defining your own view bobbing. csqcedict_t *ent = (csqcedict_t*)G_EDICT(prinst, OFS_PARM0); @@ -5777,7 +5777,7 @@ static void QCBUILTIN PF_V_CalcRefdef(pubprogfuncs_t *prinst, struct globalvars_ CL_DecayLights (); - CL_ClearEntityLists(); +// CL_ClearEntityLists(); V_ClearRefdef(csqc_playerview); r_refdef.drawsbar = false; //csqc defaults to no sbar. @@ -5787,6 +5787,7 @@ static void QCBUILTIN PF_V_CalcRefdef(pubprogfuncs_t *prinst, struct globalvars_ VectorCopy(ent->v->origin, csqc_playerview->simorg); VectorCopy (ent->v->velocity, csqc_playerview->simvel); csqc_playerview->onground = !!((int)ent->v->flags & FL_ONGROUND); + CL_CalcCrouch (csqc_playerview); V_CalcRefdef(csqc_playerview); //set up the defaults VectorCopy(savedvel, csqc_playerview->simvel); @@ -7094,32 +7095,42 @@ static void *CSQC_FindMainProgs(size_t *sz, const char *name, unsigned int check if (!file) { const char *progsname = InfoBuf_ValueForKey(&cl.serverinfo, "*csprogsname"); - if (*progsname && cls.state) - file = COM_LoadTempFile (progsname, FSLF_IGNOREPURE, sz); - if (!file && strcmp(progsname, "csprogs.dat")) - file = COM_LoadTempFile ("csprogs.dat", FSLF_IGNOREPURE, sz); - - if (file && !cls.demoplayback) //allow them to use csprogs.dat if playing a demo, and don't care about the checksum + flocation_t loc={0}; + vfsfile_t *f; + qboolean found = false; + if (!found && *progsname && cls.state) + found = FS_FLocateFile(progsname, FSLF_IGNOREPURE, &loc); + if (!found && strcmp(progsname, "csprogs.dat")) + found = FS_FLocateFile("csprogs.dat", FSLF_IGNOREPURE, &loc); + if (found && (f=FS_OpenReadLocation(&loc))) { - if (checksum && !csprogs_promiscuous) - { - if (!CSQC_ValidateMainCSProgs(file, *sz, checksum, checksize)) - file = NULL; + *sz = VFS_GETLEN(f); + file = Hunk_TempAlloc (*sz); + VFS_READ(f, file, *sz); + VFS_CLOSE(f); - //we write the csprogs into our archive if it was loaded from outside of there. - //this is to ensure that demos will play on the same machine later on... - //this is unreliable though, and redundant if we're writing the csqc into the demos themselves. - //also kinda irrelevant with sv_pure. - //FIXME: don't back up if it was in a package. + if (file && !cls.demoplayback) //allow them to use csprogs.dat if playing a demo, and don't care about the checksum + { + if (checksum && !csprogs_promiscuous) + { + if (!CSQC_ValidateMainCSProgs(file, *sz, checksum, checksize)) + file = NULL; + + //we write the csprogs into our archive if it was loaded from outside of there. + //this is to ensure that demos will play on the same machine later on... + //this is unreliable though, and redundant if we're writing the csqc into the demos themselves. + //also kinda irrelevant with sv_pure. + //FIXME: don't back up if it was in a package. #ifndef FTE_TARGET_WEB - if (file + if (file && !sv_state && !FS_WhichPackForLocation(&loc, false) #if !defined(CLIENTONLY) && defined(MVD_RECORDING) - && !sv_demo_write_csqc.ival + && !sv_demo_write_csqc.ival #endif - ) - //back it up - COM_WriteFile(newname, FS_GAMEONLY, file, *sz); + ) + //back it up + COM_WriteFile(newname, FS_GAMEONLY, file, *sz); #endif + } } } } diff --git a/engine/client/r_2d.c b/engine/client/r_2d.c index c730c733c..4812094d4 100644 --- a/engine/client/r_2d.c +++ b/engine/client/r_2d.c @@ -1294,7 +1294,7 @@ void R2D_PolyBlend (void) return; - if (bordersize && bordersize < r_refdef.vrect.width && bordersize < r_refdef.vrect.height) + if (r_refdef.playerview->bordertint[3]) { vec2_t points[4]; vec2_t tcoords[4]; diff --git a/engine/client/sys_win.c b/engine/client/sys_win.c index 95127b8b9..b06d4410b 100644 --- a/engine/client/sys_win.c +++ b/engine/client/sys_win.c @@ -4228,6 +4228,11 @@ static void Sys_QueryDesktopParameters(void) void Sys_Sleep (double seconds) { +if (seconds < 0) +seconds = 0; +if (seconds > 1) +seconds = 1; +Con_Printf("Sys_Sleep%g\n", seconds); Sleep(seconds * 1000); } @@ -4235,57 +4240,19 @@ void Sys_Sleep (double seconds) HCURSOR hArrowCursor, hCustomCursor; -void *WIN_CreateCursor(const char *filename, float hotx, float hoty, float scale) +void *WIN_CreateCursor(const qbyte *imagedata, int width, int height, uploadfmt_t format, float hotx, float hoty, float scale) { - int width, height; BITMAPV4HEADER bi; DWORD x,y; HCURSOR hAlphaCursor = NULL; ICONINFO ii; HDC maindc; - qbyte *rgbadata, *rgbadata_start, *bgradata, *bgradata_start; - uploadfmt_t format; - void *filedata; - int filelen; - if (!filename || !*filename) + const qbyte *rgbadata; + qbyte *bgradata, *bgradata_start; + void *scaled = NULL; + if (!imagedata) return NULL; - filelen = FS_LoadFile(filename, &filedata); - if (!filedata) - return NULL; - - rgbadata_start = ReadRawImageFile(filedata, filelen, &width, &height, &format, true, "cursor"); - FS_FreeFile(filedata); - if (!rgbadata_start) - return NULL; - - if ((format==PTI_RGBX8 || format==PTI_LLLX8) && !strchr(filename, ':')) - { //people seem to insist on using jpgs, which don't have alpha. - //screw over the alpha channel if needed. - unsigned int alpha_width, alpha_height, p; - char aname[MAX_QPATH]; - unsigned char *alphadata; - char *alph; - size_t alphsize; - char ext[8]; - uploadfmt_t alphaformat; - COM_StripExtension(filename, aname, sizeof(aname)); - COM_FileExtension(filename, ext, sizeof(ext)); - Q_strncatz(aname, "_alpha.", sizeof(aname)); - Q_strncatz(aname, ext, sizeof(aname)); - alphsize = FS_LoadFile(filename, (void**)&alph); - if (alph) - { - if ((alphadata = ReadRawImageFile(alph, alphsize, &alpha_width, &alpha_height, &alphaformat, true, aname))) - { - if (alpha_width == width && alpha_height == height) - for (p = 0; p < alpha_width*alpha_height; p++) - rgbadata_start[(p<<2) + 3] = (alphadata[(p<<2) + 0] + alphadata[(p<<2) + 1] + alphadata[(p<<2) + 2])/3; - BZ_Free(alphadata); - } - FS_FreeFile(alph); - } - } // FIXME: CreateIconIndirect does NOT understand DPI scaling, and will show a tiny cursor in such cases. // we should rescale scale by vid_conautoscale etc. @@ -4298,11 +4265,10 @@ void *WIN_CreateCursor(const char *filename, float hotx, float hoty, float scale if (nw <= 0 || nh <= 0 || nw > 128 || nh > 128) //don't go crazy. return NULL; nd = BZ_Malloc(nw*nh*4); - Image_ResampleTexture((unsigned int*)rgbadata_start, width, height, (unsigned int*)nd, nw, nh); + Image_ResampleTexture((unsigned int*)imagedata, width, height, (unsigned int*)nd, nw, nh); width = nw; height = nh; - BZ_Free(rgbadata_start); - rgbadata_start = nd; + imagedata = scaled = nd; } memset(&bi,0, sizeof(bi)); @@ -4327,11 +4293,11 @@ void *WIN_CreateCursor(const char *filename, float hotx, float hoty, float scale if (!ii.hbmColor) { - BZ_Free(rgbadata_start); + BZ_Free(scaled); return NULL; } - for (rgbadata=rgbadata_start,y=0;yscreentint; } else @@ -792,7 +792,7 @@ void V_CalcBlend (float *hw_blend) /*flashing things should not change hardware gamma ramps - windows is too slow*/ /*splitscreen should only use hw gamma ramps if they're all equal, and they're probably not*/ /*hw blends may also not be supported or may be disabled*/ - if (gl_cshiftenabled.value) + if (gl_cshiftenabled.ival == 2) blend = pv->bordertint; //show the colours only on the borders so we don't blind ourselves else if (j == CSHIFT_BONUS || j == CSHIFT_DAMAGE || gl_nohwblend.ival || !r2d_canhwgamma || cl.splitclients > 1) blend = pv->screentint; diff --git a/engine/client/wad.c b/engine/client/wad.c index bd86c68a9..91473855a 100644 --- a/engine/client/wad.c +++ b/engine/client/wad.c @@ -27,7 +27,7 @@ void *wadmutex; void Wads_Flush (void){} qboolean Wad_NextDownload (void){return true;} void *W_GetLumpName (const char *name, size_t *size, qbyte *type) {return NULL;} -qbyte *W_GetTexture(const char *name, int *width, int *height, qboolean *usesalpha){return NULL;} +qbyte *W_GetTexture(const char *name, int *width, int *height, uploadfmt_t *format){return NULL;} void W_LoadWadFile (char *filename){} void W_Shutdown (void){} void CL_Skygroup_f(void){} diff --git a/engine/client/winquake.h b/engine/client/winquake.h index 2460d3935..ee95c06f6 100644 --- a/engine/client/winquake.h +++ b/engine/client/winquake.h @@ -128,7 +128,7 @@ extern qboolean mouseinitialized; //extern HANDLE hinput, houtput; extern HCURSOR hArrowCursor, hCustomCursor; -void *WIN_CreateCursor(const char *filename, float hotx, float hoty, float scale); +void *WIN_CreateCursor(const qbyte *imagedata, int width, int height, uploadfmt_t format, float hotx, float hoty, float scale); qboolean WIN_SetCursor(void *cursor); void WIN_DestroyCursor(void *cursor); void WIN_WindowCreated(HWND window); diff --git a/engine/common/bothdefs.h b/engine/common/bothdefs.h index 6bc46a9eb..56998b6d6 100644 --- a/engine/common/bothdefs.h +++ b/engine/common/bothdefs.h @@ -368,6 +368,10 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #define HAVE_CLIENT #endif +#ifndef HAVE_SERVER + #undef MVD_RECORDING +#endif + //software rendering is just too glitchy, don't use it - unless its the only choice. #if defined(SWQUAKE) && !defined(_DEBUG) && !defined(__DJGPP__) #undef SWQUAKE @@ -620,10 +624,10 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #undef USE_EGL #endif -#if defined(HAVE_WINSSPI) || defined(HAVE_GNUTLS) +#if defined(HAVE_GNUTLS) || defined(HAVE_OPENSSL) || defined(HAVE_WINSSPI) #define HAVE_SSL #endif -#if defined(HAVE_GNUTLS) || defined(HAVE_WINSSPI) +#if defined(HAVE_GNUTLS) || defined(HAVE_OPENSSL) || defined(HAVE_WINSSPI) //FIXME: HAVE_WINSSPI does not work as a server. //FIXME: advertising dtls without a valid certificate will probably bug out if a client tries to auto-upgrade. //FIXME: we don't cache server certs diff --git a/engine/common/common.h b/engine/common/common.h index 01f6f36c1..e070f4c70 100644 --- a/engine/common/common.h +++ b/engine/common/common.h @@ -534,7 +534,7 @@ void FS_ReferenceControl(unsigned int refflag, unsigned int resetflags); typedef struct vfsfile_s { int (QDECL *ReadBytes) (struct vfsfile_s *file, void *buffer, int bytestoread); - int (QDECL *WriteBytes) (struct vfsfile_s *file, const void *buffer, int bytestoread); + int (QDECL *WriteBytes) (struct vfsfile_s *file, const void *buffer, int bytestowrite); qboolean (QDECL *Seek) (struct vfsfile_s *file, qofs_t pos); //returns false for error qofs_t (QDECL *Tell) (struct vfsfile_s *file); qofs_t (QDECL *GetLen) (struct vfsfile_s *file); //could give some lag @@ -812,6 +812,8 @@ qbyte COM_BlockSequenceCRCByte (qbyte *base, int length, int sequence); qbyte Q2COM_BlockSequenceCRCByte (qbyte *base, int length, int sequence); typedef size_t hashfunc_t(unsigned char *digest, size_t maxdigestsize, size_t numstrings, const unsigned char **strings, size_t *stringlens); +#define SHA1 SHA1_quake +#define HMAC HMAC_quake hashfunc_t SHA1_m; //int SHA1_m(char *digest, size_t maxdigestsize, size_t numstrings, const char **strings, size_t *stringlens); //#define SHA1(digest,maxdigestsize,string,stringlen) SHA1_m(digest, maxdigestsize, 1, &string, &stringlen) diff --git a/engine/common/config_fteqw.h b/engine/common/config_fteqw.h index 16d28b0b1..7631d0c56 100644 --- a/engine/common/config_fteqw.h +++ b/engine/common/config_fteqw.h @@ -119,6 +119,7 @@ #define HAVE_PACKET //we can send unreliable messages! #define HAVE_TCP //we can create/accept TCP connections. #define HAVE_GNUTLS //on linux +//#define HAVE_OPENSSL //on linux. hardlinked, so typically set only via the makefile. #define HAVE_WINSSPI //on windows #define FTPSERVER //sv_ftp cvar. #define WEBCLIENT //uri_get+any internal downloads etc diff --git a/engine/common/console.h b/engine/common/console.h index 8b92f423c..5b9431196 100644 --- a/engine/common/console.h +++ b/engine/common/console.h @@ -113,26 +113,35 @@ typedef struct conline_s { } conline_t; //majority of these are mututally exclusive. the bits allow multiple. -#define CB_NONE 0 -#define CB_SCROLL 1 -#define CB_COPY 2 -#define CB_CLOSE 3 -#define CB_MOVE 4 -#define CB_ACTIONBAR 5 -#define CB_SELECT 6 -#define CB_SIZELEFT (1u<<29) -#define CB_SIZERIGHT (1u<<30) -#define CB_SIZEBOTTOM (1u<<31) -#define CONF_HIDDEN 1 /*do not show in the console list (unless active)*/ -#define CONF_NOTIFY 2 /*text printed to console also appears as notify lines*/ -#define CONF_NOTIFY_BOTTOM 4 /*align the bottom*/ -#define CONF_NOTIFY_RIGHT 8 -//#define CONF_NOTIMES 16 -#define CONF_KEYFOCUSED 32 -#define CONF_ISWINDOW 64 -#define CONF_NOWRAP 128 -#define CONF_KEEPSELECTION 256 //there's text selected, keep it selected. -#define CONF_BACKSELECTION 512 //a hint that the text was selected from the end +enum +{ + CB_NONE = 0, + CB_SCROLL = 1, + CB_COPY = 2, + CB_CLOSE = 3, + CB_MOVE = 4, + CB_ACTIONBAR = 5, + CB_SELECT = 6, + CB_SCROLL_R = 7, + + //the flags part + CB_SIZELEFT = (1u<<29), + CB_SIZERIGHT = (1u<<30), + CB_SIZEBOTTOM = (1u<<31), +}; +enum +{ + CONF_HIDDEN = 1u<<0, /*do not show in the console list (unless active)*/ + CONF_NOTIFY = 1u<<1, /*text printed to console also appears as notify lines*/ + CONF_NOTIFY_BOTTOM = 1u<<2, /*align the bottom*/ + CONF_NOTIFY_RIGHT = 1u<<3, + //CONF_NOTIMES = 1u<<4, + CONF_KEYFOCUSED = 1u<<5, + CONF_ISWINDOW = 1u<<6, + CONF_NOWRAP = 1u<<7, + CONF_KEEPSELECTION = 1u<<8, //there's text selected, keep it selected. + CONF_BACKSELECTION = 1u<<9, //a hint that the text was selected from the end +}; typedef struct console_s { int id; @@ -186,6 +195,7 @@ typedef struct console_s int mousedown[2]; //x,y position that the current buttons were clicked. unsigned int buttonsdown; int mousecursor[2]; //x,y + float mousedowntime; //time mouse1 last went down, to detect double-clicks struct console_s *next; } console_t; @@ -220,6 +230,7 @@ void Con_History_Load(void); struct font_s; void Con_DrawOneConsole(console_t *con, qboolean focused, struct font_s *font, float fx, float fy, float fsx, float fsy, float lineagelimit); void Con_DrawConsole (int lines, qboolean noback); +void Con_ExpandConsoleSelection(console_t *con); char *Con_CopyConsole(console_t *con, qboolean nomarkup, qboolean onlyiflink); void Con_Print (const char *txt); void Con_CenterPrint(const char *txt); diff --git a/engine/common/fs.c b/engine/common/fs.c index 5235362c5..cbb855521 100644 --- a/engine/common/fs.c +++ b/engine/common/fs.c @@ -14,6 +14,7 @@ void FS_BeginManifestUpdates(void); static void QDECL fs_game_callback(cvar_t *var, char *oldvalue); +static void COM_InitHomedir(ftemanifest_t *man); hashtable_t filesystemhash; qboolean com_fschanged = true; qboolean com_installer = false; @@ -550,7 +551,7 @@ static qboolean FS_Manifest_ParseTokens(ftemanifest_t *man) Z_Free(man->defaultexec); man->defaultexec = Z_StrDup(Cmd_Argv(1)); } - else if (!Q_strcasecmp(cmd, "bind") || !Q_strcasecmp(cmd, "set") || !Q_strcasecmp(cmd, "seta")) + else if (!Q_strcasecmp(cmd, "bind") || !Q_strcasecmp(cmd, "set") || !Q_strcasecmp(cmd, "seta") || !Q_strcasecmp(cmd, "alias")) { Z_StrCat(&man->defaultoverrides, va("%s %s\n", Cmd_Argv(0), Cmd_Args())); } @@ -5607,6 +5608,7 @@ qboolean FS_ChangeGame(ftemanifest_t *man, qboolean allowreloadconfigs, qboolean { qboolean oldhome = com_homepathenabled; + COM_InitHomedir(man); com_homepathenabled = com_homepathusable; if (man->disablehomedir && !COM_CheckParm("-usehome")) @@ -6145,56 +6147,21 @@ void FS_ArbitraryFile_c(int argn, const char *partial, struct xcommandargcomplet } } -/* -================ -COM_InitFilesystem - -note: does not actually load any packs, just makes sure the basedir+cvars+etc is set up. vfs_fopens will still fail. -================ -*/ -void COM_InitFilesystem (void) +static void COM_InitHomedir(ftemanifest_t *man) { - int i; - + int i; char *ev; qboolean usehome; - FS_RegisterDefaultFileSystems(); - - Cmd_AddCommand("fs_restart", FS_ReloadPackFiles_f); - Cmd_AddCommandD("fs_changegame", FS_ChangeGame_f, "Switch between different manifests (or registered games)"); - Cmd_AddCommandD("fs_changemod", FS_ChangeMod_f, "Provides the backend functionality of a transient online installer. Eg, for quaddicted's map/mod database."); - Cmd_AddCommand("fs_showmanifest", FS_ShowManifest_f); - Cmd_AddCommand ("fs_flush", COM_RefreshFSCache_f); - Cmd_AddCommandAD("dir", COM_Dir_f, FS_ArbitraryFile_c, "Displays filesystem listings. Accepts wildcards."); //q3 like - Cmd_AddCommandD("path", COM_Path_f, "prints a list of current search paths."); - Cmd_AddCommandAD("flocate", COM_Locate_f, FS_ArbitraryFile_c, "Searches for a named file, and displays where it can be found in the OS's filesystem"); //prints the pak or whatever where this file can be found. - - -// -// -basedir -// Overrides the system supplied base directory (under id1) -// - i = COM_CheckParm ("-basedir"); - if (i && i < com_argc-1) - strcpy (com_gamepath, com_argv[i+1]); - else - strcpy (com_gamepath, host_parms.basedir); - - FS_CleanDir(com_gamepath, sizeof(com_gamepath)); - - - Cvar_Register(&cfg_reload_on_gamedir, "Filesystem"); - Cvar_Register(&com_fs_cache, "Filesystem"); - Cvar_Register(&fs_gamename, "Filesystem"); - Cvar_Register(&pm_downloads_url, "Filesystem"); - Cvar_Register(&pm_autoupdate, "Filesystem"); - Cvar_Register(&com_protocolname, "Server Info"); - Cvar_Register(&com_protocolversion, "Server Info"); - Cvar_Register(&fs_game, "Filesystem"); -#ifdef Q2SERVER - Cvar_Register(&fs_gamedir, "Filesystem"); - Cvar_Register(&fs_basedir, "Filesystem"); + //FIXME: this should come from the manifest, as fte_GAME or something +#ifdef _WIN32 + #define HOMESUBDIR FULLENGINENAME +#else + #ifdef GAME_SHORTNAME + #define HOMESUBDIR GAME_SHORTNAME + #else + #define HOMESUBDIR "fte" + #endif #endif usehome = false; @@ -6221,7 +6188,7 @@ void COM_InitFilesystem (void) if (dSHGetFolderPathW(NULL, 0x5, NULL, 0, wfolder) == S_OK) { narrowen(folder, sizeof(folder), wfolder); - Q_snprintfz(com_homepath, sizeof(com_homepath), "%s/My Games/%s/", folder, FULLENGINENAME); + Q_snprintfz(com_homepath, sizeof(com_homepath), "%s/My Games/%s/", folder, HOMESUBDIR); } } // if (shfolder) @@ -6231,12 +6198,12 @@ void COM_InitFilesystem (void) { ev = getenv("USERPROFILE"); if (ev) - Q_snprintfz(com_homepath, sizeof(com_homepath), "%s/My Documents/My Games/%s/", ev, FULLENGINENAME); + Q_snprintfz(com_homepath, sizeof(com_homepath), "%s/My Documents/My Games/%s/", ev, HOMESUBDIR); } #ifdef NPFTE if (!*com_homepath) - Q_snprintfz(com_homepath, sizeof(com_homepath), "/%s/", FULLENGINENAME); + Q_snprintfz(com_homepath, sizeof(com_homepath), "/%s/", HOMESUBDIR); //as a browser plugin, always use their home directory usehome = true; #else @@ -6319,29 +6286,33 @@ void COM_InitFilesystem (void) char newhome[MAX_OSPATH]; struct stat s; -#ifdef GAME_SHORTNAME -#define HOMESUBDIR GAME_SHORTNAME -#else -#define HOMESUBDIR "fte" //FIXME: this should come from the manifest, as fte_GAME or something -#endif - - if (ev[strlen(ev)-1] == '/') - Q_snprintfz(oldhome, sizeof(oldhome), "%s."HOMESUBDIR"/", ev); - else - Q_snprintfz(oldhome, sizeof(oldhome), "%s/."HOMESUBDIR"/", ev); - xdghome = getenv("XDG_DATA_HOME"); if (!xdghome || !*xdghome) xdghome = va("%s/.local/share", ev); - if (xdghome[strlen(xdghome)-1] == '/') - Q_snprintfz(newhome, sizeof(newhome), "%s"HOMESUBDIR"/", xdghome); + if (man && man->installation) + { + if (xdghome[strlen(xdghome)-1] == '/') + Q_snprintfz(com_homepath, sizeof(com_homepath), "%s%s/", xdghome, *man->installation?man->installation:HOMESUBDIR); + else + Q_snprintfz(com_homepath, sizeof(com_homepath), "%s/%s/", xdghome, *man->installation?man->installation:HOMESUBDIR); + } else - Q_snprintfz(newhome, sizeof(newhome), "%s/"HOMESUBDIR"/", xdghome); + { + if (xdghome[strlen(xdghome)-1] == '/') + Q_snprintfz(newhome, sizeof(newhome), "%s%s/", xdghome, HOMESUBDIR); + else + Q_snprintfz(newhome, sizeof(newhome), "%s/%s/", xdghome, HOMESUBDIR); - if (stat(newhome, &s) == -1 && stat(oldhome, &s) != -1) - Q_strncpyz(com_homepath, oldhome, sizeof(com_homepath)); - else - Q_strncpyz(com_homepath, newhome, sizeof(com_homepath)); + if (ev[strlen(ev)-1] == '/') + Q_snprintfz(oldhome, sizeof(oldhome), "%s.%s/", ev, HOMESUBDIR); + else + Q_snprintfz(oldhome, sizeof(oldhome), "%s/.%s/", ev, HOMESUBDIR); + + if (stat(newhome, &s) == -1 && stat(oldhome, &s) != -1) + Q_strncpyz(com_homepath, oldhome, sizeof(com_homepath)); + else + Q_strncpyz(com_homepath, newhome, sizeof(com_homepath)); + } usehome = true; // always use home on unix unless told not to } #endif @@ -6364,6 +6335,60 @@ void COM_InitFilesystem (void) com_homepathenabled = com_homepathusable; +} + +/* +================ +COM_InitFilesystem + +note: does not actually load any packs, just makes sure the basedir+cvars+etc is set up. vfs_fopens will still fail. +================ +*/ +void COM_InitFilesystem (void) +{ + int i; + + + FS_RegisterDefaultFileSystems(); + + Cmd_AddCommand("fs_restart", FS_ReloadPackFiles_f); + Cmd_AddCommandD("fs_changegame", FS_ChangeGame_f, "Switch between different manifests (or registered games)"); + Cmd_AddCommandD("fs_changemod", FS_ChangeMod_f, "Provides the backend functionality of a transient online installer. Eg, for quaddicted's map/mod database."); + Cmd_AddCommand("fs_showmanifest", FS_ShowManifest_f); + Cmd_AddCommand ("fs_flush", COM_RefreshFSCache_f); + Cmd_AddCommandAD("dir", COM_Dir_f, FS_ArbitraryFile_c, "Displays filesystem listings. Accepts wildcards."); //q3 like + Cmd_AddCommandD("path", COM_Path_f, "prints a list of current search paths."); + Cmd_AddCommandAD("flocate", COM_Locate_f, FS_ArbitraryFile_c, "Searches for a named file, and displays where it can be found in the OS's filesystem"); //prints the pak or whatever where this file can be found. + + +// +// -basedir +// Overrides the system supplied base directory (under id1) +// + i = COM_CheckParm ("-basedir"); + if (i && i < com_argc-1) + strcpy (com_gamepath, com_argv[i+1]); + else + strcpy (com_gamepath, host_parms.basedir); + + FS_CleanDir(com_gamepath, sizeof(com_gamepath)); + + + Cvar_Register(&cfg_reload_on_gamedir, "Filesystem"); + Cvar_Register(&com_fs_cache, "Filesystem"); + Cvar_Register(&fs_gamename, "Filesystem"); + Cvar_Register(&pm_downloads_url, "Filesystem"); + Cvar_Register(&pm_autoupdate, "Filesystem"); + Cvar_Register(&com_protocolname, "Server Info"); + Cvar_Register(&com_protocolversion, "Server Info"); + Cvar_Register(&fs_game, "Filesystem"); +#ifdef Q2SERVER + Cvar_Register(&fs_gamedir, "Filesystem"); + Cvar_Register(&fs_basedir, "Filesystem"); +#endif + + COM_InitHomedir(NULL); + fs_readonly = COM_CheckParm("-readonly"); fs_thread_mutex = Sys_CreateMutex(); diff --git a/engine/common/net.h b/engine/common/net.h index b7f168015..c020a9b81 100644 --- a/engine/common/net.h +++ b/engine/common/net.h @@ -183,6 +183,7 @@ qboolean NET_DTLS_Decode(struct ftenet_connections_s *col); qboolean NET_DTLS_Disconnect(struct ftenet_connections_s *col, netadr_t *to); void NET_DTLS_Timeouts(struct ftenet_connections_s *col); #endif +extern cvar_t timeout; //============================================================================ diff --git a/engine/common/net_ssl_gnutls.c b/engine/common/net_ssl_gnutls.c index cc6ff17f2..29b97fc3a 100644 --- a/engine/common/net_ssl_gnutls.c +++ b/engine/common/net_ssl_gnutls.c @@ -1087,7 +1087,7 @@ static qboolean SSL_InitConnection(gnutlsfile_t *newf, qboolean isserver, qboole return true; } -vfsfile_t *FS_OpenSSL(const char *hostname, vfsfile_t *source, qboolean isserver) +vfsfile_t *GNUTLS_OpenVFS(const char *hostname, vfsfile_t *source, qboolean isserver) { gnutlsfile_t *newf; @@ -1127,7 +1127,7 @@ vfsfile_t *FS_OpenSSL(const char *hostname, vfsfile_t *source, qboolean isserver return &newf->funcs; } -int TLS_GetChannelBinding(vfsfile_t *vf, qbyte *binddata, size_t *bindsize) +int GNUTLS_GetChannelBinding(vfsfile_t *vf, qbyte *binddata, size_t *bindsize) { gnutls_datum_t cb; gnutlsfile_t *f = (gnutlsfile_t*)vf; @@ -1337,7 +1337,7 @@ const dtlsfuncs_t *GNUDTLS_InitClient(void) qboolean SSL_InitGlobal(qboolean isserver) {return false;} vfsfile_t *FS_OpenSSL(const char *hostname, vfsfile_t *source, qboolean isserver) {return NULL;} -int TLS_GetChannelBinding(vfsfile_t *vf, qbyte *binddata, size_t *bindsize) {return -1;} +int GNUTLS_GetChannelBinding(vfsfile_t *vf, qbyte *binddata, size_t *bindsize) {return -1;} const dtlsfuncs_t *GNUDTLS_InitClient(void) {return NULL;} const dtlsfuncs_t *GNUDTLS_InitServer(void) {return NULL;} #endif diff --git a/engine/common/net_ssl_winsspi.c b/engine/common/net_ssl_winsspi.c index ce483258d..080ad37e2 100644 --- a/engine/common/net_ssl_winsspi.c +++ b/engine/common/net_ssl_winsspi.c @@ -1012,7 +1012,7 @@ static qboolean QDECL SSPI_Close (struct vfsfile_s *file) } #include -vfsfile_t *FS_OpenSSL(const char *servername, vfsfile_t *source, qboolean server) +vfsfile_t *SSPI_OpenVFS(const char *servername, vfsfile_t *source, qboolean server) { sslfile_t *newf; int i = 0; @@ -1095,7 +1095,7 @@ typedef struct _SecPkgContext_Bindings SEC_CHANNEL_BINDINGS *Bindings; } SecPkgContext_Bindings, *PSecPkgContext_Bindings; #endif -int TLS_GetChannelBinding(vfsfile_t *vf, qbyte *binddata, size_t *bindsize) +int SSPI_GetChannelBinding(vfsfile_t *vf, qbyte *binddata, size_t *bindsize) { int ret; sslfile_t *f = (sslfile_t*)vf; diff --git a/engine/common/net_wins.c b/engine/common/net_wins.c index 7aadc4bdc..aa491f7b6 100644 --- a/engine/common/net_wins.c +++ b/engine/common/net_wins.c @@ -120,13 +120,16 @@ int UDP6_OpenSocket (int port); #ifdef HAVE_IPX void IPX_CloseSocket (int socket); #endif +cvar_t timeout = CVARD("timeout","65", "Connections will time out if no packets are received for this duration of time."); // seconds without any message cvar_t net_hybriddualstack = CVARD("net_hybriddualstack", "1", "Uses hybrid ipv4+ipv6 sockets where possible. Not supported on xp or below."); cvar_t net_fakeloss = CVARFD("net_fakeloss", "0", CVAR_CHEAT, "Simulates packetloss in both receiving and sending, on a scale from 0 to 1."); cvar_t net_enabled = CVARD("net_enabled", "1", "If 0, disables all network access, including name resolution and socket creation. Does not affect loopback/internal connections."); #if defined(TCPCONNECT) && !defined(CLIENTONLY) cvar_t net_enable_qizmo = CVARD("net_enable_qizmo", "1", "Enables compatibility with qizmo's tcp connections serverside. Frankly, using sv_port_tcp without this is a bit pointless."); cvar_t net_enable_qtv = CVARD("net_enable_qtv", "1", "Listens for qtv proxies, or clients using the qtvplay command."); +#if defined(HAVE_SSL) cvar_t net_enable_tls = CVARD("net_enable_tls", "1", "If enabled, binary data sent to a non-tls tcp port will be interpretted as a tls handshake (enabling https or wss over the same tcp port."); +#endif cvar_t net_enable_http = CVARD("net_enable_http", "0", "If enabled, tcp ports will accept http clients, potentially serving large files which could distrupt gameplay."); cvar_t net_enable_websockets = CVARD("net_enable_websockets", "1", "If enabled, tcp ports will accept websocket game clients."); cvar_t net_enable_webrtcbroker = CVARD("net_enable_webrtcbroker", "0", "If 1, tcp ports will accept websocket connections from clients trying to broker direct webrtc connections. This should be low traffic, but might involve a lot of mostly-idle connections."); @@ -2035,6 +2038,44 @@ qboolean NET_IsLoopBackAddress (netadr_t *adr) return adr->type == NA_LOOPBACK; } + +#ifdef HAVE_SSL +vfsfile_t *FS_OpenSSL(const char *hostname, vfsfile_t *source, qboolean isserver) +{ + vfsfile_t *f = NULL; +#ifdef HAVE_GNUTLS + if (!f) + f = GNUTLS_OpenVFS(hostname, source, isserver); +#endif +#ifdef HAVE_OPENSSL + if (!f) + f = OSSL_OpenVFS(hostname, source, isserver); +#endif +#ifdef HAVE_WINSSPI + if (!f) + f = SSPI_OpenVFS(hostname, source, isserver); +#endif + return f; +} +int TLS_GetChannelBinding(vfsfile_t *stream, qbyte *data, size_t *datasize) +{ + int r = -1; +#ifdef HAVE_GNUTLS + if (r == -1) + r = GNUTLS_GetChannelBinding(stream, data, datasize); +#endif +#ifdef HAVE_OPENSSL + if (r == -1) + r = OSSL_GetChannelBinding(stream, data, datasize); +#endif +#ifdef HAVE_WINSSPI + if (r == -1) + r = SSPI_GetChannelBinding(stream, data, datasize); +#endif + return r; +} +#endif + ///////////////////////////////////////////// //loopback stuff @@ -2495,34 +2536,56 @@ struct dtlspeer_s void NET_DTLS_Timeouts(ftenet_connections_t *col) { - struct dtlspeer_s *peer; + struct dtlspeer_s *peer, **link; if (!col) return; - for (peer = col->dtls; peer; peer = peer->next) + for (link = &col->dtls; (peer=*link); ) { + if (peer->timeout < realtime) + { + peer->funcs->DestroyContext(peer->dtlsstate); + *link = peer->next; + continue; + } + peer->funcs->Timeouts(peer->dtlsstate); + link = &peer->next; } } const dtlsfuncs_t *DTLS_InitServer(void) { -#if defined(HAVE_GNUTLS) - return GNUDTLS_InitServer(); -#elif defined(HAVE_WINSSPI) - return SSPI_DTLS_InitServer(); -#else - return NULL; + const dtlsfuncs_t *f = NULL; +#ifdef HAVE_GNUTLS + if (!f) + f = GNUDTLS_InitServer(); #endif +#ifdef HAVE_OPENSSL + if (!f) + f = OSSL_InitServer(); +#endif +#ifdef HAVE_WINSSPI + if (!f) + f = SSPI_DTLS_InitServer(); +#endif + return f; } const dtlsfuncs_t *DTLS_InitClient(void) { + const dtlsfuncs_t *f = NULL; #ifdef HAVE_WINSSPI - return SSPI_DTLS_InitClient(); -#elif defined(HAVE_GNUTLS) - return GNUDTLS_InitClient(); -#else - return NULL; + if (!f) + f = SSPI_DTLS_InitClient(); #endif +#ifdef HAVE_GNUTLS + if (!f) + f = GNUDTLS_InitClient(); +#endif +#ifdef HAVE_OPENSSL + if (!f) + f = OSSL_InitClient(); +#endif + return f; } static neterr_t NET_SendPacketCol (ftenet_connections_t *collection, int length, const void *data, netadr_t *to); @@ -2533,6 +2596,7 @@ static neterr_t FTENET_DTLS_DoSendPacket(void *cbctx, const qbyte *data, size_t } qboolean NET_DTLS_Create(ftenet_connections_t *col, netadr_t *to) { + extern cvar_t timeout; struct dtlspeer_s *peer; if (to->prot != NP_DGRAM) return false; @@ -2554,6 +2618,8 @@ qboolean NET_DTLS_Create(ftenet_connections_t *col, netadr_t *to) peer->funcs = DTLS_InitClient(); if (peer->funcs) peer->dtlsstate = peer->funcs->CreateContext(NET_BaseAdrToString(hostname, sizeof(hostname), to), peer, FTENET_DTLS_DoSendPacket, col->islisten); + + peer->timeout = realtime+timeout.value; if (peer->dtlsstate) { if (peer->next) @@ -2616,11 +2682,13 @@ static neterr_t FTENET_DTLS_SendPacket(ftenet_connections_t *col, int length, co qboolean NET_DTLS_Decode(ftenet_connections_t *col) { + extern cvar_t timeout; struct dtlspeer_s *peer; for (peer = col->dtls; peer; peer = peer->next) { if (NET_CompareAdr(&peer->addr, &net_from)) { + peer->timeout = realtime+timeout.value; //refresh the timeout if our peer is still alive. switch(peer->funcs->Received(peer->dtlsstate, net_message.data, net_message.cursize)) { case NETERR_DISCONNECTED: @@ -7137,12 +7205,22 @@ void NET_PrintConnectionsStatus(ftenet_connections_t *collection) } #ifdef HAVE_DTLS + if (developer.ival) { struct dtlspeer_s *dtls; char adr[64]; for (dtls = collection->dtls; dtls; dtls = dtls->next) Con_Printf("dtls: %s\n", NET_AdrToString(adr, sizeof(adr), &dtls->addr)); } + else + { + struct dtlspeer_s *dtls; + int c = 0; + for (dtls = collection->dtls; dtls; dtls = dtls->next) + c++; + if (c) + Con_Printf("dtls connections : %i\n", c); + } #endif } @@ -7720,6 +7798,7 @@ void NET_Init (void) #endif } + Cvar_Register(&timeout, "networking"); Cvar_Register(&net_hybriddualstack, "networking"); Cvar_Register(&net_fakeloss, "networking"); @@ -7912,7 +7991,9 @@ void SVNET_RegisterCvars(void) #if defined(TCPCONNECT) && !defined(CLIENTONLY) Cvar_Register (&net_enable_qizmo, "networking"); Cvar_Register (&net_enable_qtv, "networking"); +#if defined(HAVE_SSL) Cvar_Register (&net_enable_tls, "networking"); +#endif Cvar_Register (&net_enable_http, "networking"); Cvar_Register (&net_enable_websockets, "networking"); Cvar_Register (&net_enable_webrtcbroker, "networking"); diff --git a/engine/common/netinc.h b/engine/common/netinc.h index f70410d71..342fd5b62 100644 --- a/engine/common/netinc.h +++ b/engine/common/netinc.h @@ -311,14 +311,24 @@ typedef struct dtlsfuncs_s } dtlsfuncs_t; const dtlsfuncs_t *DTLS_InitServer(void); const dtlsfuncs_t *DTLS_InitClient(void); +#endif #ifdef HAVE_WINSSPI + vfsfile_t *SSPI_OpenVFS(const char *hostname, vfsfile_t *source, qboolean isserver); + int SSPI_GetChannelBinding(vfsfile_t *vf, qbyte *binddata, size_t *bindsize); const dtlsfuncs_t *SSPI_DTLS_InitServer(void); //returns NULL if there's no cert available. const dtlsfuncs_t *SSPI_DTLS_InitClient(void); //should always return something, if implemented. #endif #ifdef HAVE_GNUTLS + vfsfile_t *GNUTLS_OpenVFS(const char *hostname, vfsfile_t *source, qboolean isserver); + int GNUTLS_GetChannelBinding(vfsfile_t *vf, qbyte *binddata, size_t *bindsize); const dtlsfuncs_t *GNUDTLS_InitServer(void); //returns NULL if there's no cert available. const dtlsfuncs_t *GNUDTLS_InitClient(void); //should always return something, if implemented. #endif +#ifdef HAVE_OPENSSL + vfsfile_t *OSSL_OpenVFS(const char *hostname, vfsfile_t *source, qboolean isserver); + int OSSL_GetChannelBinding(vfsfile_t *vf, qbyte *binddata, size_t *bindsize); + const dtlsfuncs_t *OSSL_InitServer(void); //returns NULL if there's no cert available. + const dtlsfuncs_t *OSSL_InitClient(void); //should always return something, if implemented. #endif diff --git a/engine/common/pr_bgcmd.c b/engine/common/pr_bgcmd.c index 5d4e5d0a1..79444020c 100644 --- a/engine/common/pr_bgcmd.c +++ b/engine/common/pr_bgcmd.c @@ -380,7 +380,10 @@ int QDECL QCEditor (pubprogfuncs_t *prinst, const char *filename, int *line, int return DEBUG_TRACE_ABORT; if (!*filename || !line || !*line) //don't try editing an empty line, it won't work { - Con_Printf("Unable to debug, please disable optimisations\n"); + if (!*filename) + Con_Printf("Unable to debug, please disable optimisations\n"); + else + Con_Printf("Unable to debug, please provide line number info\n"); if (fatal) return DEBUG_TRACE_ABORT; return DEBUG_TRACE_OFF; @@ -5724,8 +5727,8 @@ void QCBUILTIN PF_gettime (pubprogfuncs_t *prinst, struct globalvars_s *pr_globa case 0: //cached time at start of frame G_FLOAT(OFS_RETURN) = realtime; break; - case 1: //actual time - G_FLOAT(OFS_RETURN) = Sys_DoubleTime(); + case 1: //actual time, ish. we round to milliseconds to reduce spectre exposure + G_FLOAT(OFS_RETURN) = (qint64_t)(Sys_DoubleTime()*1000) / 1000.0; break; //case 2: //highres.. looks like time into the frame //case 3: //uptime diff --git a/engine/common/q1bsp.c b/engine/common/q1bsp.c index 6737f9af1..afb429d44 100644 --- a/engine/common/q1bsp.c +++ b/engine/common/q1bsp.c @@ -627,7 +627,16 @@ void Mod_ClipDecal(struct model_s *mod, vec3_t center, vec3_t normal, vec3_t tan #endif #ifdef Q3BSPS else if (cl.worldmodel->fromgame == fg_quake3) - Q3BSP_ClipDecalToNodes(&dec, mod->rootnode); + { + if (mod->submodelof) + { + msurface_t *surf; + for (surf = mod->surfaces+mod->firstmodelsurface, p = 0; p < mod->nummodelsurfaces; p++, surf++) + Fragment_Mesh(&dec, surf->mesh, surf->texinfo); + } + else + Q3BSP_ClipDecalToNodes(&dec, mod->rootnode); + } #endif #ifdef TERRAIN diff --git a/engine/common/sha1.c b/engine/common/sha1.c index b50a0ae5d..2b118d4e2 100644 --- a/engine/common/sha1.c +++ b/engine/common/sha1.c @@ -16,7 +16,7 @@ This file came to FTE via EzQuake. /* #define SHA1HANDSOFF * Copies data before messing with it. */ #define SHA1HANDSOFF -//#include "quakedef.h" +#include "quakedef.h" #include #define BigLong(l) (((unsigned char*)&l)[0]<<24) | (((unsigned char*)&l)[1]<<16) | (((unsigned char*)&l)[2]<<8) | (((unsigned char*)&l)[3]<<0) diff --git a/engine/gl/gl_font.c b/engine/gl/gl_font.c index 4a440a688..47395d688 100644 --- a/engine/gl/gl_font.c +++ b/engine/gl/gl_font.c @@ -1528,6 +1528,8 @@ qboolean Font_LoadFreeTypeFont(struct font_s *f, int height, const char *fontfil error = pFT_New_Face(fontlib, va("/usr/share/fonts/%s", fontfilename), 0, &face); if (error) error = pFT_New_Face(fontlib, va("/usr/share/fonts/truetype/%s.ttf", fontfilename), 0, &face); + if (error) //just to give a chance of the same names working on more than one os, with the right package installed. + error = pFT_New_Face(fontlib, va("/usr/share/fonts/truetype/msttcorefonts/%s.ttf", fontfilename), 0, &face); } #endif if (!error) diff --git a/engine/gl/gl_model.h b/engine/gl/gl_model.h index 087e191ab..714acf111 100644 --- a/engine/gl/gl_model.h +++ b/engine/gl/gl_model.h @@ -172,7 +172,7 @@ m*_t structures are in-memory #define EF_BLUE (1<<6) #define EF_RED (1<<7) #define H2EF_NODRAW (1<<7) //this is going to get complicated... emulated server side. -#define DPEF_NOGUNBOB (1<<8) //viewmodel attachment does not bob +#define DPEF_NOGUNBOB (1<<8) //viewmodel attachment does not bob. only applies to viewmodelforclient/RF_WEAPONMODEL #define EF_FULLBRIGHT (1<<9) //abslight=1 #define DPEF_FLAME (1<<10) //'onfire' #define DPEF_STARDUST (1<<11) //'showering sparks' diff --git a/engine/gl/gl_shader.c b/engine/gl/gl_shader.c index d7bef6246..115308964 100644 --- a/engine/gl/gl_shader.c +++ b/engine/gl/gl_shader.c @@ -7273,6 +7273,8 @@ char *Shader_GetShaderBody(shader_t *s, char *fname, size_t fnamesize) if (fnamesize) { + *fname = 0; + if (parsename) { unsigned int key; @@ -7297,8 +7299,24 @@ char *Shader_GetShaderBody(shader_t *s, char *fname, size_t fnamesize) } } } - else - *fname = 0; + + if (!strchr(parsename, ':')) + { + //if the named shader is a .shader file then just directly load it. + const char *token = COM_GetFileExtension(parsename, NULL); + if (!strcmp(token, ".shader") || !*token) + { + char shaderfile[MAX_QPATH]; + if (!*token) + { + Q_snprintfz(shaderfile, sizeof(shaderfile), "%s.shader", parsename); + if (COM_FCheckExists(shaderfile)) + Q_snprintfz(fname, fnamesize, "%s:%i", shaderfile, 1); + } + else if (COM_FCheckExists(parsename)) + Q_snprintfz(fname, fnamesize, "%s:%i", parsename, 1); + } + } } #ifdef _DEBUG diff --git a/engine/gl/gl_vidlinuxglx.c b/engine/gl/gl_vidlinuxglx.c index b81fd9b3e..23202821f 100644 --- a/engine/gl/gl_vidlinuxglx.c +++ b/engine/gl/gl_vidlinuxglx.c @@ -2744,50 +2744,11 @@ static void *X11VID_CreateCursorRGBA(const qbyte *rgbacursor, size_t w, size_t h Z_Free(cursor); return NULL; } -static void *X11VID_CreateCursor(const char *filename, float hotx, float hoty, float scale) +static void *X11VID_CreateCursor(const qbyte *imagedata, int width, int height, uploadfmt_t format, float hotx, float hoty, float scale) { void *r; - qbyte *rgbadata; - uploadfmt_t format; - void *filedata; - int filelen, width, height; - if (!filename || !*filename) + if (!imagedata) return NULL; - filelen = FS_LoadFile(filename, &filedata); - if (!filedata) - return NULL; - - rgbadata = ReadRawImageFile(filedata, filelen, &width, &height, &format, true, filename); - FS_FreeFile(filedata); - if (!rgbadata) - return NULL; - - if ((format==PTI_RGBX8 || format==PTI_LLLX8) && !strchr(filename, ':')) - { //people seem to insist on using jpgs, which don't have alpha. - //so screw over the alpha channel if needed. - unsigned int alpha_width, alpha_height, p; - char aname[MAX_QPATH]; - unsigned char *alphadata; - char *alph; - size_t alphsize; - char ext[8]; - COM_StripExtension(filename, aname, sizeof(aname)); - COM_FileExtension(filename, ext, sizeof(ext)); - Q_strncatz(aname, "_alpha.", sizeof(aname)); - Q_strncatz(aname, ext, sizeof(aname)); - alphsize = FS_LoadFile(filename, (void**)&alph); - if (alph) - { - if ((alphadata = ReadRawImageFile(alph, alphsize, &alpha_width, &alpha_height, &format, true, aname))) - { - if (alpha_width == width && alpha_height == height) - for (p = 0; p < alpha_width*alpha_height; p++) - rgbadata[(p<<2) + 3] = (alphadata[(p<<2) + 0] + alphadata[(p<<2) + 1] + alphadata[(p<<2) + 2])/3; - BZ_Free(alphadata); - } - FS_FreeFile(alph); - } - } if (scale != 1) { @@ -2798,15 +2759,14 @@ static void *X11VID_CreateCursor(const char *filename, float hotx, float hoty, f if (nw <= 0 || nh <= 0 || nw > 128 || nh > 128) //don't go crazy. return NULL; nd = BZ_Malloc(nw*nh*4); - Image_ResampleTexture((unsigned int*)rgbadata, width, height, (unsigned int*)nd, nw, nh); + Image_ResampleTexture((unsigned int*)imagedata, width, height, (unsigned int*)nd, nw, nh); width = nw; height = nh; - BZ_Free(rgbadata); - rgbadata = nd; + r = X11VID_CreateCursorRGBA(nd, width, height, hotx, hoty); + BZ_Free(nd); } - - r = X11VID_CreateCursorRGBA(rgbadata, width, height, hotx, hoty); - BZ_Free(rgbadata); + else + r = X11VID_CreateCursorRGBA(imagedata, width, height, hotx, hoty); return r; } diff --git a/engine/gl/gl_vidsdl.c b/engine/gl/gl_vidsdl.c index aa2bd2ef9..bb37ec264 100644 --- a/engine/gl/gl_vidsdl.c +++ b/engine/gl/gl_vidsdl.c @@ -60,25 +60,11 @@ static void *GLVID_getsdlglfunction(char *functionname) #endif #if SDL_MAJOR_VERSION >= 2 -void *GLVID_CreateCursor (const char *filename, float hotx, float hoty, float scale) +void *GLVID_CreateCursor (const qbyte *imagedata, int width, int height, uploadfmt_t format, float hotx, float hoty, float scale) { - int width; - int height; SDL_Cursor *curs; SDL_Surface *surf; - qbyte *rgbadata_start; - qboolean hasalpha; - void *filedata; - int filelen; - if (!filename || !*filename) - return NULL; - filelen = FS_LoadFile(filename, &filedata); - if (!filedata) - return NULL; - - rgbadata_start = Read32BitImageFile(filedata, filelen, &width, &height, &hasalpha, "cursor"); - FS_FreeFile(filedata); - if (!rgbadata_start) + if (!imagedata) return NULL; if (scale != 1) @@ -90,17 +76,20 @@ void *GLVID_CreateCursor (const char *filename, float hotx, float hoty, float if (nw <= 0 || nh <= 0 || nw > 128 || nh > 128) //don't go crazy. return NULL; nd = BZ_Malloc(nw*nh*4); - Image_ResampleTexture((unsigned int*)rgbadata_start, width, height, (unsigned int*)nd, nw, nh); - width = nw; - height = nh; - BZ_Free(rgbadata_start); - rgbadata_start = nd; - } + Image_ResampleTexture((unsigned int*)imagedata, width, height, (unsigned int*)nd, nw, nh); - surf = SDL_CreateRGBSurfaceFrom(rgbadata_start, width, height, 32, width*4, 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000); - curs = SDL_CreateColorCursor(surf, hotx, hoty); - SDL_FreeSurface(surf); - BZ_Free(rgbadata_start); + surf = SDL_CreateRGBSurfaceFrom(nd, nw, nh, 32, nw*4, 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000); + curs = SDL_CreateColorCursor(surf, hotx, hoty); + SDL_FreeSurface(surf); + + BZ_Free(nd); + } + else + { + surf = SDL_CreateRGBSurfaceFrom((void*)imagedata, width, height, 32, width*4, 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000); + curs = SDL_CreateColorCursor(surf, hotx, hoty); + SDL_FreeSurface(surf); + } return curs; } qboolean GLVID_SetCursor (void *cursor) diff --git a/engine/http/httpclient.c b/engine/http/httpclient.c index 8f7d849ef..274166837 100644 --- a/engine/http/httpclient.c +++ b/engine/http/httpclient.c @@ -375,7 +375,7 @@ void Cookie_Monster(void) //path) I'm going to call this an optimisation feature and not bother with it... hopefully there won't be too many sites that have sub-paths or third-party stuff... gah. //httponly) irrelevant until we support javascript... which we don't. //secure) assumed to be true. https:// vs http:// are thus completely independant. sorry. -//expires) gah, parsing time values sucks! plus we don't have persistent storage. +//expires) gah, parsing time values sucks! plus we don't have persistent storage. All cookies are session cookies. void Cookie_Parse(char *domain, int secure, char *line, char *end) { char *e; diff --git a/engine/qclib/qcc.h b/engine/qclib/qcc.h index 34f57cf78..2405684ea 100644 --- a/engine/qclib/qcc.h +++ b/engine/qclib/qcc.h @@ -706,6 +706,7 @@ QCC_type_t *QCC_PR_GenFunctionType (QCC_type_t *rettype, struct QCC_typeparam_s char *QCC_PR_ParseName (void); CompilerConstant_t *QCC_PR_DefineName(char *name); struct QCC_typeparam_s *QCC_PR_FindStructMember(QCC_type_t *t, const char *membername, unsigned int *out_ofs); +QCC_type_t *QCC_PR_PointerType (QCC_type_t *pointsto); const char *QCC_VarAtOffset(QCC_sref_t ref); @@ -730,6 +731,8 @@ void QCC_PR_ParsePrintSRef (int warningtype, QCC_sref_t sref); void VARGS QCC_PR_ParseErrorPrintDef (int errortype, QCC_def_t *def, const char *error, ...); void VARGS QCC_PR_ParseErrorPrintSRef (int errortype, QCC_sref_t sref, const char *error, ...); +QCC_type_t *QCC_PR_MakeThiscall(QCC_type_t *orig, QCC_type_t *thistype); + int QCC_WarningForName(const char *name); char *QCC_NameForWarning(int idx); diff --git a/engine/qclib/qcc_pr_comp.c b/engine/qclib/qcc_pr_comp.c index ed1ab3caf..11d3ed3fb 100644 --- a/engine/qclib/qcc_pr_comp.c +++ b/engine/qclib/qcc_pr_comp.c @@ -9,6 +9,14 @@ #include #endif +#ifdef _MSC_VER +#define longlong __int64 +#define LL(x) x##i64 +#else +#define longlong long long +#define LL(x) x##ll +#endif + /* TODO: *foo++ = 5; @@ -236,7 +244,8 @@ QCC_sref_t QCC_MakeTranslateStringConst(const char *value); QCC_sref_t QCC_MakeStringConst(const char *value); QCC_sref_t QCC_MakeStringConstLength(const char *value, int length); QCC_sref_t QCC_MakeFloatConst(float value); -QCC_sref_t QCC_MakeIntConst(int value); +QCC_sref_t QCC_MakeFloatConstFromInt(longlong llvalue); +QCC_sref_t QCC_MakeIntConst(longlong llvalue); QCC_sref_t QCC_MakeVectorConst(float a, float b, float c); enum @@ -2181,7 +2190,7 @@ static int QCC_PR_RoundFloatConst(const QCC_eval_t *eval) float val = eval->_float; int ival = val; if (val != (float)ival) - QCC_PR_ParseWarning(WARN_OVERFLOW, "Constant float operand not an integer value"); + QCC_PR_ParseWarning(WARN_OVERFLOW, "Constant float operand %f will be truncated to %i", val, ival); return ival; } @@ -4553,7 +4562,7 @@ static void QCC_VerifyFormatString (const char *funcname, QCC_ref_t **arglist, u { case 0: if (argpos < argcount && argn_last < argcount) - QCC_PR_ParseWarning(WARN_FORMATSTRING, "%s: surplus trailing arguments for format", funcname); + QCC_PR_ParseWarning(WARN_FORMATSTRING, "%s: surplus trailing %s%s%s argument(s) for format %s\"%s\"%s", funcname, col_symbol, TypeName(ARGCTYPE(argpos), temp, sizeof(temp)), col_none, col_name, strings + formatstring->string, col_none); return; case '%': if(*++s == '%') @@ -4575,7 +4584,7 @@ static void QCC_VerifyFormatString (const char *funcname, QCC_ref_t **arglist, u width = strtol(s, &err, 10); if(!err) { - QCC_PR_ParseWarning(WARN_FORMATSTRING, "%s: bad format string: %s", funcname, s0); + QCC_PR_ParseWarning(WARN_FORMATSTRING, "%s: bad format string: %s%s%s", funcname, col_name, s0, col_none); return; } if(*err == '$') @@ -4621,7 +4630,7 @@ noflags: arg = strtol(s, &err, 10); if(!err || *err != '$') { - QCC_PR_ParseWarning(WARN_FORMATSTRING, "%s: invalid format string: %s", funcname, s0); + QCC_PR_ParseWarning(WARN_FORMATSTRING, "%s: invalid format string: %s%s%s", funcname, col_name, s0, col_none); return; } s = err + 1; @@ -4636,7 +4645,7 @@ noflags: strtol(s, &err, 10); if(!err) { - QCC_PR_ParseWarning(WARN_FORMATSTRING, "%s: invalid format string: %s", funcname, s0); + QCC_PR_ParseWarning(WARN_FORMATSTRING, "%s: invalid format string: %s%s%s", funcname, col_name, s0, col_none); return; } s = err; @@ -4656,7 +4665,7 @@ noflags: arg = strtol(s, &err, 10); if(!err || *err != '$') { - QCC_PR_ParseWarning(WARN_FORMATSTRING, "%s: invalid format string: %s", funcname, s0); + QCC_PR_ParseWarning(WARN_FORMATSTRING, "%s: invalid format string: %s%s%s", funcname, col_name, s0, col_none); return; } s = err + 1; @@ -4672,14 +4681,14 @@ noflags: strtol(s, &err, 10); if(!err) { - QCC_PR_ParseWarning(WARN_FORMATSTRING, "%s: invalid format string: %s", funcname, s0); + QCC_PR_ParseWarning(WARN_FORMATSTRING, "%s: invalid format string: %s%s%s", funcname, col_name, s0, col_none); return; } s = err; } else { - QCC_PR_ParseWarning(WARN_FORMATSTRING, "%s: invalid format string: %s", funcname, s0); + QCC_PR_ParseWarning(WARN_FORMATSTRING, "%s: invalid format string: %s%s%s", funcname, col_name, s0, col_none); return; } } @@ -4744,7 +4753,7 @@ nolength: break; default: { - QCC_PR_ParseWarning(WARN_FORMATSTRING, "%s: %s requires float at arg %i (got %s)", funcname, formatbuf, thisarg+1, TypeName(ARGCTYPE(thisarg), temp, sizeof(temp))); + QCC_PR_ParseWarning(WARN_FORMATSTRING, "%s: %s%s%s requires float at arg %i (got %s%s%s)", funcname, col_name, formatbuf, col_none, thisarg+1, col_symbol, TypeName(ARGCTYPE(thisarg), temp, sizeof(temp)), col_none); } break; } @@ -4759,7 +4768,7 @@ nolength: case ev_variant: break; default: - QCC_PR_ParseWarning(WARN_FORMATSTRING, "%s: %s requires pointer at arg %i (got %s)", funcname, formatbuf, thisarg+1, TypeName(ARGCTYPE(thisarg), temp, sizeof(temp))); + QCC_PR_ParseWarning(WARN_FORMATSTRING, "%s: %s%s%s requires pointer at arg %i (got %s%s%s)", funcname, col_name, formatbuf, col_none, thisarg+1, col_symbol, TypeName(ARGCTYPE(thisarg), temp, sizeof(temp)), col_none); break; } } @@ -4775,7 +4784,7 @@ nolength: break; //fallthrough default: - QCC_PR_ParseWarning(WARN_FORMATSTRING, "%s: %s requires int at arg %i (got %s)", funcname, formatbuf, thisarg+1, TypeName(ARGCTYPE(thisarg), temp, sizeof(temp))); + QCC_PR_ParseWarning(WARN_FORMATSTRING, "%s: %s%s%s requires int at arg %i (got %s%s%s)", funcname, col_name, formatbuf, col_none, thisarg+1, col_symbol, TypeName(ARGCTYPE(thisarg), temp, sizeof(temp)), col_none); break; } } @@ -4790,12 +4799,12 @@ nolength: case ev_variant: break; default: - QCC_PR_ParseWarning(WARN_FORMATSTRING, "%s: %s requires vector at arg %i (got %s)", funcname, formatbuf, thisarg+1, TypeName(ARGCTYPE(thisarg), temp, sizeof(temp))); + QCC_PR_ParseWarning(WARN_FORMATSTRING, "%s: %s%s%s requires vector at arg %i (got %s%s%s)", funcname, col_name, formatbuf, col_none, thisarg+1, col_symbol, TypeName(ARGCTYPE(thisarg), temp, sizeof(temp)), col_none); break; } } else - QCC_PR_ParseWarning(WARN_FORMATSTRING, "%s: %s requires intvector at arg %i (got %s)", funcname, formatbuf, thisarg+1, TypeName(ARGCTYPE(thisarg), temp, sizeof(temp))); + QCC_PR_ParseWarning(WARN_FORMATSTRING, "%s: %s%s%s requires intvector at arg %i (got %s%s%s)", funcname, col_name, formatbuf, col_none, thisarg+1, col_symbol, TypeName(ARGCTYPE(thisarg), temp, sizeof(temp)), col_none); break; case 's': case 'S': @@ -4805,12 +4814,12 @@ nolength: case ev_variant: break; default: - QCC_PR_ParseWarning(WARN_FORMATSTRING, "%s: %s requires string at arg %i", funcname, formatbuf, thisarg+1, TypeName(ARGCTYPE(thisarg), temp, sizeof(temp))); + QCC_PR_ParseWarning(WARN_FORMATSTRING, "%s: %s%s%s requires string at arg %i (got %s%s%s)", funcname, col_name, formatbuf, col_none, thisarg+1, col_symbol, TypeName(ARGCTYPE(thisarg), temp, sizeof(temp)), col_none); break; } break; default: - QCC_PR_ParseWarning(WARN_FORMATSTRING, "%s: invalid format string: %s", funcname, s0); + QCC_PR_ParseWarning(WARN_FORMATSTRING, "%s: invalid format string: %s%s%s", funcname, col_name, s0, col_none); return; } s++; @@ -5877,7 +5886,7 @@ static QCC_sref_t QCC_PR_ParseFunctionCall (QCC_ref_t *funcref) //warning, the f if (t) { QCC_PR_Expect(")"); - return QCC_MakeIntConst(t->size * 4); + return QCC_PR_Statement(&pr_opcodes[OP_ADD_PIW], QCC_MakeIntConst(0), QCC_MakeIntConst(t->size), NULL); } else { @@ -6523,9 +6532,13 @@ QCC_sref_t QCC_MakeSRef(QCC_def_t *def, unsigned int ofs, QCC_type_t *type) //int varchecks; //int typechecks; extern hashtable_t floatconstdefstable; -QCC_sref_t QCC_MakeIntConst(int value) +QCC_sref_t QCC_MakeIntConst(longlong llvalue) { QCC_def_t *cn; + int value = llvalue; + + if (value != llvalue) + QCC_PR_ParseWarning(WARN_OVERFLOW, "Constant int operand %lld will be truncated to %i", llvalue, value); cn = Hash_GetKey(&floatconstdefstable, value); if (cn) @@ -7806,17 +7819,40 @@ QCC_ref_t *QCC_PR_ParseRefValue (QCC_ref_t *refbuf, QCC_type_t *assumeclass, pbo if (assumeclass && assumeclass->parentclass) { //try getting a member. QCC_type_t *type; - for(type = assumeclass; type && !d.cast; type = type->parentclass) + if (assumeclass->type == ev_struct) { - //look for virtual things - QC_snprintfz(membername, sizeof(membername), "%s::"MEMBERFIELDNAME, type->name, name); - d = QCC_PR_GetSRef (NULL, membername, pr_scope, false, 0, false); + unsigned int ofs; + struct QCC_typeparam_s *p = QCC_PR_FindStructMember(assumeclass, name, &ofs); + if (p) + { + QCC_sref_t ths; + ths = QCC_PR_GetSRef(QCC_PR_PointerType(pr_classtype), "this", pr_scope, false, 0, false); + if (ths.cast) + { + ths.cast = QCC_PR_PointerType(p->type); + + if (d.sym->arraysize) + { + //FIXME: this should result in a pointer type, and not this->member[0] + } + return QCC_PR_ParseRefArrayPointer(refbuf, QCC_PR_BuildRef(refbuf, REF_POINTER, ths, QCC_MakeIntConst(ofs), p->type, false), allowarrayassign, makearraypointers); + } + } } - for(type = assumeclass; type && !d.cast; type = type->parentclass) + else { - //look for non-virtual things (functions: after virtual stuff, because this will find the actual function def too) - QC_snprintfz(membername, sizeof(membername), "%s::%s", type->name, name); - d = QCC_PR_GetSRef (NULL, membername, pr_scope, false, 0, false); + for(type = assumeclass; type && !d.cast; type = type->parentclass) + { + //look for virtual things + QC_snprintfz(membername, sizeof(membername), "%s::"MEMBERFIELDNAME, type->name, name); + d = QCC_PR_GetSRef (NULL, membername, pr_scope, false, 0, false); + } + for(type = assumeclass; type && !d.cast; type = type->parentclass) + { + //look for non-virtual things (functions: after virtual stuff, because this will find the actual function def too) + QC_snprintfz(membername, sizeof(membername), "%s::%s", type->name, name); + d = QCC_PR_GetSRef (NULL, membername, pr_scope, false, 0, false); + } } } if (!d.cast) @@ -15452,6 +15488,8 @@ void QCC_PR_ParseDefs (char *classname, pbool fatal) allocatenew = true; if (classname) { + unsigned int ofs; + struct QCC_typeparam_s *p; char *membername = name; name = qccHunkAlloc(strlen(classname) + strlen(name) + 3); sprintf(name, "%s::%s", classname, membername); @@ -15460,6 +15498,13 @@ void QCC_PR_ParseDefs (char *classname, pbool fatal) allocatenew = false; else if (!defclass || !defclass->parentclass) QCC_PR_ParseError(ERR_NOTANAME, "%s is not a class\n", classname); + + if (defclass->type == ev_struct) + { + p = QCC_PR_FindStructMember(defclass, membername, &ofs); + if (p && p->isvirtual) + type = QCC_PR_MakeThiscall(type, defclass); + } } else defclass = NULL; diff --git a/engine/qclib/qcc_pr_lex.c b/engine/qclib/qcc_pr_lex.c index de01e78d0..7edb83bce 100644 --- a/engine/qclib/qcc_pr_lex.c +++ b/engine/qclib/qcc_pr_lex.c @@ -2081,13 +2081,13 @@ static void QCC_PR_LexNumber (void) num*=base; num += c-'0'; } - else if (c >= 'a' && c <= 'f' && base > 10) + else if (c >= 'a' && c <= 'z' && c < 'a'+base-10) { pr_token[tokenlen++] = c; num*=base; num += c -'a'+10; } - else if (c >= 'A' && c <= 'F' && base > 10) + else if (c >= 'A' && c <= 'Z' && c < 'A'+base-10) { pr_token[tokenlen++] = c; num*=base; @@ -2145,7 +2145,7 @@ static void QCC_PR_LexNumber (void) if ((longlong)pr_immediate._int != (longlong)num) { if (((longlong)pr_immediate._int & LL(0xffffffff80000000)) != LL(0xffffffff80000000)) - QCC_PR_ParseWarning(WARN_OVERFLOW, "numerical overflow"); + QCC_PR_ParseWarning(WARN_OVERFLOW, "numerical overflow"); } return; } @@ -4797,7 +4797,7 @@ char *pr_parm_argcount_name; int recursivefunctiontype; -static QCC_type_t *QCC_PR_MakeThiscall(QCC_type_t *orig, QCC_type_t *thistype) +QCC_type_t *QCC_PR_MakeThiscall(QCC_type_t *orig, QCC_type_t *thistype) { QCC_type_t ftype = *orig; @@ -4807,9 +4807,12 @@ static QCC_type_t *QCC_PR_MakeThiscall(QCC_type_t *orig, QCC_type_t *thistype) ftype.params = qccHunkAlloc(sizeof(*ftype.params) * ftype.num_parms); memcpy(ftype.params+1, orig->params, sizeof(*ftype.params) * orig->num_parms); ftype.params[0].paramname = "this"; - ftype.params[0].type = QCC_PointerTypeTo(thistype); + ftype.params[0].type = QCC_PR_PointerType(thistype); ftype.params[0].isvirtual = true; + memmove(&pr_parm_names[1], &pr_parm_names[0], sizeof(*pr_parm_names)*orig->num_parms); + strcpy(pr_parm_names[0], "this"); + orig = QCC_PR_FindType (&ftype); if (!orig) { @@ -5869,6 +5872,8 @@ QCC_type_t *QCC_PR_ParseType (int newtype, pbool silentfail) newt = QCC_PR_NewType(tname, ev_struct, true); newt->parentclass = parenttype; } + else if (!newt->size && !newt->parentclass) + newt->parentclass = parenttype; else if (parenttype && newt->parentclass != parenttype) QCC_PR_ParseError(ERR_NOTANAME, "Redeclaration of struct with different parent type", tname, parenttype->name); @@ -5992,7 +5997,12 @@ QCC_type_t *QCC_PR_ParseType (int newtype, pbool silentfail) QC_snprintfz(membername, sizeof(membername), "%s::%s", newt->name, parmname); d = QCC_PR_GetDef(type, membername, NULL, true, 0, (type->type==ev_function)?GDF_CONST:0); if (QCC_PR_CheckToken("=") || (type->type == ev_function && QCC_PR_PeekToken("{"))) + { +//FIXME: methods cannot be compiled yet, as none of the fields are not actually defined yet. + pr_classtype = newt; QCC_PR_ParseInitializerDef(d, 0); + pr_classtype = NULL; + } QCC_FreeDef(d); if (!QCC_PR_PeekToken(",")) newparm = NULL; diff --git a/engine/qclib/qccmain.c b/engine/qclib/qccmain.c index a1d03d5b7..218ac22b9 100644 --- a/engine/qclib/qccmain.c +++ b/engine/qclib/qccmain.c @@ -4175,13 +4175,19 @@ static void QCC_PR_CommandLinePrecompilerOptions (void) { flag_ifvector = flag_vectorlogic = true; flag_dblstarexp = flag_attributes = flag_assumevar = pr_subscopedlocals = flag_cpriority = flag_allowuninit = true; - flag_boundchecks = false; //gmqcc doesn't support these, so xonotic is buggy shite. + flag_boundchecks = false; //gmqcc doesn't support dynamic bound checks, so xonotic is buggy shite. we don't want to generate code that will crash. opt_logicops = true; - qccwarningaction[WARN_CONSTANTCOMPARISON] = WA_IGNORE; - qccwarningaction[WARN_POINTLESSSTATEMENT] = WA_IGNORE; - qccwarningaction[WARN_OVERFLOW] = WA_IGNORE; - qccwarningaction[WARN_STRICTTYPEMISMATCH] = WA_IGNORE; - qccwarningaction[WARN_PARAMWITHNONAME] = WA_IGNORE; + + //we have to disable some of these warnings, because xonotic insists on using -Werror. use -Wextra to override. + qccwarningaction[WARN_NOTREFERENCEDCONST] = WA_IGNORE; //gmqcc doesn't warn about function prototypes without any names + qccwarningaction[WARN_CONSTANTCOMPARISON] = WA_IGNORE; //xonotic abuses this, and gmqcc doesn't warn. + qccwarningaction[WARN_POINTLESSSTATEMENT] = WA_IGNORE; //so many macro expansions that we can't mute because of xonotic using an external preprocessor. + qccwarningaction[WARN_OVERFLOW] = WA_IGNORE; //xonotic has data loss from implicit conversions too. + qccwarningaction[WARN_STRICTTYPEMISMATCH] = WA_IGNORE; //gmqcc doesn't enforce checks on auxilliary types. + qccwarningaction[WARN_PARAMWITHNONAME] = WA_IGNORE; //nor does it care if a parameter isn't named. + qccwarningaction[WARN_IFSTRING_USED] = WA_IGNORE; //and many people would argue that this was a feature rather than a bug + qccwarningaction[WARN_UNINITIALIZED] = WA_IGNORE; //all locals get 0-initialised anyway, and our checks are not quite up to scratch. + qccwarningaction[WARN_GMQCC_SPECIFIC] = WA_IGNORE; //we shouldn't warn about gmqcc syntax when we're trying to be compatible with it. there's always -Wextra. keyword_asm = false; keyword_inout = keyword_optional = keyword_state = keyword_inline = keyword_nosave = keyword_extern = keyword_shared = keyword_unused = keyword_used = keyword_nonstatic = keyword_ignore = keyword_strip = false; @@ -4284,10 +4290,30 @@ static void QCC_PR_CommandLinePrecompilerOptions (void) for (j = 0; j < ERR_PARSEERRORS; j++) if (qccwarningaction[j] == WA_IGNORE) { - if (j != WARN_FTE_SPECIFIC && //kinda annoying when its actually valid code. - j != WARN_NOTREFERENCEDCONST && //warning about every single constant is annoying as heck. note that this includes both stuff like MOVETYPE_ and builtins. - j != WARN_EXTRAPRECACHE) //we can't guarentee that we can parse this correctly. this warning is thus a common false positive. its available with -Wextra, and there's intrinsics to reduce false positives. + switch(j) + { + //these warnings do not get switched on with -Wall when using -std=gmqcc, because mods that use -Werror would screw up too much + case WARN_CONSTANTCOMPARISON: + case WARN_POINTLESSSTATEMENT: + case WARN_OVERFLOW: + case WARN_STRICTTYPEMISMATCH: + case WARN_PARAMWITHNONAME: + case WARN_IFSTRING_USED: + case WARN_UNINITIALIZED: + case WARN_GMQCC_SPECIFIC: + qccwarningaction[j] = qccwarningaction[WARN_GMQCC_SPECIFIC]; + break; + + //these warnings require -Wextra to enable, as they're too annoying to have to fix + case WARN_NOTREFERENCEDCONST: //warning about every single constant is annoying as heck. note that this includes both stuff like MOVETYPE_ and builtins. + case WARN_EXTRAPRECACHE: //we can't guarentee that we can parse this correctly. this warning is thus a common false positive. its available with -Wextra, and there's intrinsics to reduce false positives. + case WARN_FTE_SPECIFIC: //kinda annoying when its actually valid code. + break; + + default: qccwarningaction[j] = WA_WARN; + break; + } } } else if (!stricmp(a, "extra")) diff --git a/engine/server/net_preparse.c b/engine/server/net_preparse.c index 5dd29b120..747afab21 100644 --- a/engine/server/net_preparse.c +++ b/engine/server/net_preparse.c @@ -828,16 +828,20 @@ void NPP_NQFlush(void) break; case svcfte_cgamepacket: - if (sv.csqcdebug) + if (writedest != &sv.multicast) { - /*shift the data up by two bytes*/ - memmove(buffer+3, buffer+1, bufferlen-1); + Con_Printf(CON_WARNING"Warning: svc_cgamepacket used outside of a multicast\n"); + if (sv.csqcdebug) + { + /*shift the data up by two bytes*/ + memmove(buffer+3, buffer+1, bufferlen-1); - /*add a length in the 2nd/3rd bytes*/ - buffer[1] = (bufferlen-1); - buffer[2] = (bufferlen-1) >> 8; + /*add a length in the 2nd/3rd bytes*/ + buffer[1] = (bufferlen-1); + buffer[2] = (bufferlen-1) >> 8; - bufferlen += 2; + bufferlen += 2; + } } break; case svc_temp_entity: @@ -846,16 +850,20 @@ void NPP_NQFlush(void) default: if (te_515sevilhackworkaround) { - if (sv.csqcdebug) + if (writedest != &sv.multicast) { - /*shift the data up by two bytes, but don't care about the first byte*/ - memmove(buffer+3, buffer+1, bufferlen-1); + Con_Printf(CON_WARNING"Warning: unknown svc_temp_entity used outside of a multicast\n"); + if (sv.csqcdebug) + { + /*shift the data up by two bytes, but don't care about the first byte*/ + memmove(buffer+3, buffer+1, bufferlen-1); - /*add a length in the 2nd/3rd bytes, if needed*/ - buffer[1] = (bufferlen-1) & 0xff; - buffer[2] = (bufferlen-1) >> 8; + /*add a length in the 2nd/3rd bytes, if needed*/ + buffer[1] = (bufferlen-1) & 0xff; + buffer[2] = (bufferlen-1) >> 8; - bufferlen += 2; + bufferlen += 2; + } } /*replace the svc itself*/ buffer[0] = svcfte_cgamepacket; @@ -1870,16 +1878,20 @@ void NPP_QWFlush(void) break; case svcfte_cgamepacket: - if (sv.csqcdebug) + if (writedest != &sv.nqmulticast) { - /*shift the data up by two bytes*/ - memmove(buffer+3, buffer+1, bufferlen-1); + Con_Printf(CON_WARNING"Warning: svc_cgamepacket used outside of a multicast\n"); + if (sv.csqcdebug) + { + /*shift the data up by two bytes*/ + memmove(buffer+3, buffer+1, bufferlen-1); - /*add a length in the 2nd/3rd bytes*/ - buffer[1] = (bufferlen-1); - buffer[2] = (bufferlen-1) >> 8; + /*add a length in the 2nd/3rd bytes*/ + buffer[1] = (bufferlen-1); + buffer[2] = (bufferlen-1) >> 8; - bufferlen += 2; + bufferlen += 2; + } } break; case svc_temp_entity: @@ -1888,16 +1900,20 @@ void NPP_QWFlush(void) default: if (te_515sevilhackworkaround) { - if (sv.csqcdebug) + if (writedest != &sv.nqmulticast) { - /*shift the data up by two bytes*/ - memmove(buffer+3, buffer+1, bufferlen-1); + Con_Printf(CON_WARNING"Warning: unknown svc_temp_entity used outside of a multicast\n"); + if (sv.csqcdebug) + { + /*shift the data up by two bytes*/ + memmove(buffer+3, buffer+1, bufferlen-1); - /*add a length in the 2nd/3rd bytes*/ - buffer[1] = (bufferlen-1); - buffer[2] = (bufferlen-1) >> 8; + /*add a length in the 2nd/3rd bytes*/ + buffer[1] = (bufferlen-1); + buffer[2] = (bufferlen-1) >> 8; - bufferlen += 2; + bufferlen += 2; + } } /*replace the svc itself*/ buffer[0] = svcfte_cgamepacket; diff --git a/engine/server/pr_cmds.c b/engine/server/pr_cmds.c index bb67a2c89..83bbe86fa 100644 --- a/engine/server/pr_cmds.c +++ b/engine/server/pr_cmds.c @@ -6255,6 +6255,44 @@ void QCBUILTIN PF_multicast (pubprogfuncs_t *prinst, struct globalvars_s *pr_glo NPP_Flush(); #endif + if (sv.csqcdebug) + { +#ifdef NQPROT + if (sv.nqmulticast.cursize && sv.nqmulticast.data[0] == svcfte_cgamepacket) + { + if (sv.nqmulticast.cursize + 2 > sv.nqmulticast.maxsize) + sv.nqmulticast.cursize = 0; + else + { + /*shift the data up by two bytes*/ + memmove(sv.nqmulticast.data+3, sv.nqmulticast.data+1, sv.nqmulticast.cursize-1); + + /*add a length in the 2nd/3rd bytes*/ + sv.nqmulticast.data[1] = (sv.nqmulticast.cursize-1); + sv.nqmulticast.data[2] = (sv.nqmulticast.cursize-1) >> 8; + + sv.nqmulticast.cursize += 2; + } + } +#endif + if (sv.multicast.cursize) + { + if (sv.multicast.cursize + 2 > sv.multicast.maxsize) + sv.multicast.cursize = 0; + else + { + /*shift the data up by two bytes*/ + memmove(sv.multicast.data+3, sv.multicast.data+1, sv.multicast.cursize-1); + + /*add a length in the 2nd/3rd bytes*/ + sv.multicast.data[1] = (sv.multicast.cursize-1); + sv.multicast.data[2] = (sv.multicast.cursize-1) >> 8; + + sv.multicast.cursize += 2; + } + } + } + SV_MulticastProtExt(o, to, pr_global_struct->dimension_send, 0, 0); } diff --git a/engine/server/server.h b/engine/server/server.h index 20fc2186a..b5d8c4f6c 100644 --- a/engine/server/server.h +++ b/engine/server/server.h @@ -130,7 +130,7 @@ typedef struct PAUSE_EXPLICIT = 1, //someone hit pause PAUSE_SERVICE = 2, //we're running as a service and someone paused us rather than killing us. PAUSE_AUTO = 4 //console is down in a singleplayer game. - } paused; + } paused, oldpaused; float pausedstart; //check player/eyes models for hacks diff --git a/engine/server/sv_ccmds.c b/engine/server/sv_ccmds.c index 9b87102b3..10f4c9586 100644 --- a/engine/server/sv_ccmds.c +++ b/engine/server/sv_ccmds.c @@ -1902,7 +1902,10 @@ static void SV_Status_f (void) int columns = 80; extern cvar_t sv_listen_qw; #if defined(TCPCONNECT) && !defined(CLIENTONLY) - extern cvar_t net_enable_tls, net_enable_http, net_enable_webrtcbroker, net_enable_websockets, net_enable_qizmo, net_enable_qtv; + #if defined(HAVE_SSL) + extern cvar_t net_enable_tls; + #endif + extern cvar_t net_enable_http, net_enable_webrtcbroker, net_enable_websockets, net_enable_qizmo, net_enable_qtv; #endif #ifdef NQPROT extern cvar_t sv_listen_nq, sv_listen_dp; @@ -1978,8 +1981,10 @@ static void SV_Status_f (void) Con_Printf(" DTLS"); #endif #if defined(TCPCONNECT) && !defined(CLIENTONLY) +#if defined(HAVE_SSL) if (net_enable_tls.ival) Con_Printf(" TLS"); +#endif if (net_enable_http.ival) Con_Printf(" HTTP"); if (net_enable_webrtcbroker.ival) diff --git a/engine/server/sv_ents.c b/engine/server/sv_ents.c index ddfd70ccc..944459719 100644 --- a/engine/server/sv_ents.c +++ b/engine/server/sv_ents.c @@ -3893,8 +3893,7 @@ void SV_WriteEntitiesToClient (client_t *client, sizebuf_t *msg, qboolean ignore // this is the frame we are creating frame = &client->frameunion.frames[client->netchan.incoming_sequence & UPDATE_MASK]; - if (!sv.paused) - memset(frame->playerpresent, 0, sizeof(frame->playerpresent)); + memset(frame->playerpresent, 0, sizeof(frame->playerpresent)); // find the client's PVS if (ignorepvs) diff --git a/engine/server/sv_main.c b/engine/server/sv_main.c index 456451b66..703846f48 100644 --- a/engine/server/sv_main.c +++ b/engine/server/sv_main.c @@ -58,8 +58,7 @@ cvar_t sv_nopvs = CVARD("sv_nopvs", "0", "Set to 1 to ignore pvs on the serv cvar_t fraglog_public = CVARD("fraglog_public", "1", "Enables support for connectionless fraglog requests"); cvar_t fraglog_details = CVARD("fraglog_details", "1", "Bitmask\n1: killer+killee names.\n2: killer+killee teams\n4:timestamp.\n8:killer weapon\n16:killer+killee guid.\nFor compatibility, use 1(vanilla) or 7(mvdsv)."); -cvar_t timeout = CVAR("timeout","65"); // seconds without any message -cvar_t zombietime = CVAR("zombietime", "2"); // seconds to sink messages +cvar_t zombietime = CVARD("zombietime", "2", "Client slots will not be reused for this number of seconds."); // seconds to sink messages 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"); @@ -4780,7 +4779,6 @@ float SV_Frame (void) static int oldpackets; float oldtime; qboolean isidle; - static int oldpaused; float timedelta; float delay; @@ -4820,10 +4818,10 @@ float SV_Frame (void) sv.paused ^= PAUSE_AUTO; #endif - if (oldpaused != sv.paused) + if (sv.oldpaused != sv.paused) { + sv.oldpaused = sv.paused; SV_PauseChanged(); - oldpaused = sv.paused; } @@ -5084,7 +5082,7 @@ static void SV_InfoChanged(void *context, const char *key) #endif for (i = 0; i < svs.allocated_client_slots; i++) { - if (svs.clients[i].state >= cs_connected) + if (svs.clients[i].state >= cs_connected && !svs.clients[i].controller) { InfoSync_Add(&svs.clients[i].infosync, context, key); } @@ -5155,7 +5153,6 @@ void SV_InitLocal (void) Cvar_Register (&sv_allow_splitscreen, cvargroup_serverinfo); Cvar_Register (&fbskins, cvargroup_serverinfo); - Cvar_Register (&timeout, cvargroup_servercontrol); Cvar_Register (&zombietime, cvargroup_servercontrol); Cvar_Register (&sv_pupglow, cvargroup_serverinfo); @@ -5615,8 +5612,10 @@ void SV_ExtractFromUserinfo (client_t *cl, qboolean verbose) cl->playercolor = top*16 + bottom; if (svs.gametype == GT_PROGS || svs.gametype == GT_Q1QVM) { +#ifndef NOLEGACY if (cl->edict) cl->edict->xv->clientcolors = cl->playercolor; +#endif MSG_WriteByte (&sv.nqreliable_datagram, svc_updatecolors); MSG_WriteByte (&sv.nqreliable_datagram, cl-svs.clients); MSG_WriteByte (&sv.nqreliable_datagram, cl->playercolor); diff --git a/engine/server/sv_phys.c b/engine/server/sv_phys.c index 01d82d166..0419e1fcf 100644 --- a/engine/server/sv_phys.c +++ b/engine/server/sv_phys.c @@ -53,6 +53,7 @@ cvar_t sv_airaccelerate = CVAR( "sv_airaccelerate", "0.7"); cvar_t sv_wateraccelerate = CVAR( "sv_wateraccelerate", "10"); cvar_t sv_friction = CVAR( "sv_friction", "4"); cvar_t sv_waterfriction = CVAR( "sv_waterfriction", "4"); +cvar_t sv_wallfriction = CVARD( "sv_wallfriction", "1", "Additional friction when running into walls"); cvar_t sv_gameplayfix_noairborncorpse = CVAR( "sv_gameplayfix_noairborncorpse", "0"); cvar_t sv_gameplayfix_multiplethinks = CVARD( "sv_gameplayfix_multiplethinks", "1", "Enables multiple thinks per entity per frame so small nextthink times are accurate. QuakeWorld mods expect a value of 1."); cvar_t sv_gameplayfix_stepdown = CVARD( "sv_gameplayfix_stepdown", "0", "Attempt to step down steps, instead of only up them. Affects non-predicted movetype_walk."); @@ -87,6 +88,7 @@ void WPhys_Init(void) Cvar_Register (&sv_wateraccelerate, cvargroup_serverphysics); Cvar_Register (&sv_friction, cvargroup_serverphysics); Cvar_Register (&sv_waterfriction, cvargroup_serverphysics); + Cvar_Register (&sv_wallfriction, cvargroup_serverphysics); Cvar_Register (&sv_sound_watersplash, cvargroup_serverphysics); Cvar_Register (&sv_sound_land, cvargroup_serverphysics); Cvar_Register (&sv_stepheight, cvargroup_serverphysics); @@ -1887,7 +1889,7 @@ static void SV_WalkMove (edict_t *ent) #else // 1/32 epsilon to keep floating point happy -#define DIST_EPSILON (0.03125) +/*#define DIST_EPSILON (0.03125) static int WPhys_SetOnGround (world_t *w, wedict_t *ent, const float *gravitydir) { vec3_t end; @@ -1896,6 +1898,8 @@ static int WPhys_SetOnGround (world_t *w, wedict_t *ent, const float *gravitydir return 1; VectorMA(ent->v->origin, 1, gravitydir, end); trace = World_Move(w, ent->v->origin, ent->v->mins, ent->v->maxs, end, MOVE_NORMAL, (wedict_t*)ent); + if (DotProduct(trace.plane.normal, ent->v->velocity) > 0) + return 0; //velocity is away from the plane normal, so this does not count as a contact. if (trace.fraction <= DIST_EPSILON && -DotProduct(gravitydir, trace.plane.normal) >= 0.7) { ent->v->flags = (int)ent->v->flags | FL_ONGROUND; @@ -1903,7 +1907,7 @@ static int WPhys_SetOnGround (world_t *w, wedict_t *ent, const float *gravitydir return 1; } return 0; -} +}*/ static void WPhys_WalkMove (world_t *w, wedict_t *ent, const float *gravitydir) { //int originalmove_clip; @@ -1922,7 +1926,7 @@ static void WPhys_WalkMove (world_t *w, wedict_t *ent, const float *gravitydir) clip = WPhys_FlyMove (w, ent, gravitydir, host_frametime, NULL); - WPhys_SetOnGround (w, ent, gravitydir); +// WPhys_SetOnGround (w, ent, gravitydir); WPhys_CheckVelocity(w, ent); VectorCopy(ent->v->origin, originalmove_origin); @@ -1951,7 +1955,7 @@ static void WPhys_WalkMove (world_t *w, wedict_t *ent, const float *gravitydir) return; // only step up while jumping if that is enabled - if (!pm_airstep.value) + if (!pm_airstep.value) if (!oldonground && ent->v->waterlevel == 0) return; } @@ -1967,9 +1971,9 @@ static void WPhys_WalkMove (world_t *w, wedict_t *ent, const float *gravitydir) WPhys_PushEntity(w, ent, upmove, MOVE_NORMAL); // move forward - ent->v->velocity[2] = 0; + VectorMA(ent->v->velocity, -DotProduct(gravitydir, ent->v->velocity), gravitydir, ent->v->velocity); //ent->v->velocity[2] = 0; clip = WPhys_FlyMove (w, ent, gravitydir, host_frametime, &steptrace); - ent->v->velocity[2] += start_velocity[2]; + VectorMA(ent->v->velocity, DotProduct(gravitydir, start_velocity), gravitydir, ent->v->velocity); //ent->v->velocity[2] += start_velocity[2]; WPhys_CheckVelocity(w, ent); @@ -1994,22 +1998,23 @@ static void WPhys_WalkMove (world_t *w, wedict_t *ent, const float *gravitydir) //Con_Printf("step - "); // extra friction based on view angle - if (clip & 2)// && sv_wallfriction.value) + if ((clip & 2) && sv_wallfriction.value) { // Con_Printf("wall\n"); WPhys_WallFriction (ent, &steptrace); } } - else if (!sv_gameplayfix_stepdown.ival || !oldonground || start_velocity[2] > 0 || ((int)ent->v->flags & FL_ONGROUND) || ent->v->waterlevel >= 2) + else if (!sv_gameplayfix_stepdown.ival || !oldonground || -DotProduct(gravitydir,start_velocity) > 0 || ((int)ent->v->flags & FL_ONGROUND) || ent->v->waterlevel >= 2) return; // move down - VectorScale(gravitydir, -(-movevars.stepheight + start_velocity[2]*host_frametime), downmove); + VectorScale(gravitydir, movevars.stepheight + (1/32.0) - DotProduct(gravitydir,start_velocity)*host_frametime, downmove); // FIXME: don't link? downtrace = WPhys_PushEntity (w, ent, downmove, MOVE_NORMAL); if (downtrace.fraction < 1 && -DotProduct(gravitydir, downtrace.plane.normal) > 0.7) { + if (DotProduct(downtrace.plane.normal, ent->v->velocity)<=0) //Spike: moving away from the surface should not count as onground. // LordHavoc: disabled this check so you can walk on monsters/players //if (ent->v->solid == SOLID_BSP) { @@ -2031,7 +2036,7 @@ static void WPhys_WalkMove (world_t *w, wedict_t *ent, const float *gravitydir) ent->v->groundentity = originalmove_groundentity; } - WPhys_SetOnGround (w, ent, gravitydir); +// WPhys_SetOnGround (w, ent, gravitydir); WPhys_CheckVelocity(w, ent); } #endif @@ -2142,9 +2147,9 @@ void WPhys_RunEntity (world_t *w, wedict_t *ent) if (ent->lastruntime == w->framenum) return; ent->lastruntime = w->framenum; - if (progstype == PROG_QW) //we don't use the field any more, but qw mods might. - ent->v->lastruntime = w->physicstime; #ifndef CLIENTONLY + if (progstype == PROG_QW && w == &sv.world) //we don't use the field any more, but qw mods might. + ent->v->lastruntime = w->physicstime; svent = NULL; #endif } @@ -2233,9 +2238,9 @@ void WPhys_RunEntity (world_t *w, wedict_t *ent) WPhys_WalkMove (w, ent, gravitydir); #ifndef CLIENTONLY - if (!(ent->entnum > 0 && ent->entnum <= sv.allocated_client_slots) && w == &sv.world) - World_LinkEdict (w, ent, true); + if (!svent) #endif + World_LinkEdict (w, ent, true); break; #ifdef USERBE case MOVETYPE_PHYSICS: @@ -2257,7 +2262,7 @@ void WPhys_RunEntity (world_t *w, wedict_t *ent) #ifndef CLIENTONLY if (svent) { - World_LinkEdict (w, (wedict_t*)svent, true); + World_LinkEdict (w, ent, true); if (!host_client->spectator) { @@ -2416,7 +2421,6 @@ void World_Physics_Frame(world_t *w) host_client = &svs.clients[i-1]; sv_player = svs.clients[i-1].edict; - host_client->lastruncmd = newt; SV_PreRunCmd(); #ifndef NEWSPEEDCHEATPROT svs.clients[i-1].last_check = 0; diff --git a/engine/server/sv_user.c b/engine/server/sv_user.c index 25797e6d7..321d3644d 100644 --- a/engine/server/sv_user.c +++ b/engine/server/sv_user.c @@ -1081,7 +1081,10 @@ void SV_SendClientPrespawnInfo(client_t *client) else if (client->prespawn_idx == 5) { ClientReliableWrite_Begin(client, svc_setpause, 2); - ClientReliableWrite_Byte (client, sv.paused!=0); + ClientReliableWrite_Byte (client, sv.oldpaused!=0); + + if (sv.oldpaused && sv.oldpaused&~PAUSE_AUTO) + SV_PrintToClient(client, PRINT_HIGH, "server is paused\n"); } else { @@ -1796,7 +1799,7 @@ void SVQW_Spawn_f (void) // send all current names, colors, and frag counts // FIXME: is this a good thing? - SZ_Clear (&host_client->netchan.message); +// SZ_Clear (&host_client->netchan.message); // send current status of all other players @@ -2138,6 +2141,8 @@ void SV_Begin_Core(client_t *split) SV_PostRunCmd(); host_client = oh; sv_player = oh?oh->edict:NULL; + + host_client->lastruncmd = sv.time*1000; } } } @@ -2217,18 +2222,6 @@ void SV_Begin_f (void) SV_BroadcastTPrintf (PRINT_HIGH, "warning: %s eyes or player model does not match\n", host_client->name); } - // if we are paused, tell the client - if (sv.paused) - { - if (!ISQ2CLIENT(host_client)) - { - ClientReliableWrite_Begin (host_client, svc_setpause, 2); - ClientReliableWrite_Byte (host_client, sv.paused!=0); - } - if (sv.paused&~PAUSE_AUTO) - SV_ClientTPrintf(host_client, PRINT_HIGH, "server is paused\n"); - } - if (sendangles) { // @@ -5518,7 +5511,7 @@ static void SVNQ_Spawn_f (void) // send all current names, colors, and frag counts // FIXME: is this a good thing? - SZ_Clear (&host_client->netchan.message); +// SZ_Clear (&host_client->netchan.message); // send current status of all other players @@ -5640,19 +5633,6 @@ static void SVNQ_Begin_f (void) SV_BroadcastTPrintf (PRINT_HIGH, "warning: %s eyes or player model not verified\n", host_client->name); } - - // if we are paused, tell the client - if (sv.paused) - { - if (!ISQ2CLIENT(host_client)) - { - ClientReliableWrite_Begin (host_client, svc_setpause, 2); - ClientReliableWrite_Byte (host_client, sv.paused!=0); - } - if (sv.paused&~PAUSE_AUTO) - SV_ClientTPrintf(host_client, PRINT_HIGH, "server is paused\n"); - } - if (sendangles) { // @@ -6830,6 +6810,7 @@ size_t playertouchmax; void SV_PreRunCmd(void) { size_t max = MAX_EDICTS;//(sv.world.num_edicts+7)&~7; + host_client->lastruncmd = sv.time*1000; if (max > playertouchmax) { playertouchmax = max; diff --git a/engine/server/world.c b/engine/server/world.c index 9ed97c3ee..744bd8416 100644 --- a/engine/server/world.c +++ b/engine/server/world.c @@ -2294,7 +2294,7 @@ static void World_ClipToNetwork (world_t *w, moveclip_t *clip) if (!((int)clip->passedict->xv->dimension_hit & 1)) continue; - if (!model || model->loadstate != MLS_LOADED) + if (!model || model->loadstate != MLS_LOADED || !model->funcs.NativeTrace) { model = NULL;