From c0841c73ab69b0f3a5c1afd013cfa258bee85508 Mon Sep 17 00:00:00 2001 From: Spoike Date: Sun, 27 Apr 2014 23:16:07 +0000 Subject: [PATCH] add net_compress cvar to enable/disable the compression feature. off by default for now. auto-precache sounds if they were not already precached. also prints a warning (once, obviously). this is for consistency with models added cmd voicetarg specself, which will send voice only to the people spectating you (and not your team), including into demos. git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@4647 fc73d0e0-1445-4013-8a0c-d673dee63da5 --- engine/client/cl_demo.c | 2 +- engine/client/cl_main.c | 3 ++- engine/client/cl_parse.c | 14 +++++++------- engine/client/cl_screen.c | 12 +++++++----- engine/client/image.c | 2 +- engine/common/common.c | 30 ++++++++++++++++++++++++++++++ engine/common/common.h | 1 + engine/common/gl_q2bsp.c | 2 +- engine/common/huff.c | 19 +++++++++++++++++-- engine/common/net_chan.c | 2 ++ engine/gl/gl_draw.c | 6 +++--- engine/http/httpclient.c | 4 ++-- engine/server/pr_cmds.c | 2 +- engine/server/savegame.c | 3 +-- engine/server/server.h | 1 + engine/server/sv_main.c | 10 ++++++++-- engine/server/sv_send.c | 33 +++++++++++++++++++++++++++------ engine/server/sv_user.c | 14 ++++++++++++++ 18 files changed, 126 insertions(+), 34 deletions(-) diff --git a/engine/client/cl_demo.c b/engine/client/cl_demo.c index fd5f1f997..527c26719 100644 --- a/engine/client/cl_demo.c +++ b/engine/client/cl_demo.c @@ -1490,7 +1490,7 @@ void CL_ReRecord_f (void) // // open the demo file // - COM_DefaultExtension (name, ".qwd", sizeof(name)); + COM_RequireExtension (name, ".qwd", sizeof(name)); cls.demooutfile = FS_OpenVFS (name, "wb", FS_GAME); if (!cls.demooutfile) diff --git a/engine/client/cl_main.c b/engine/client/cl_main.c index 31107eece..a9355785b 100644 --- a/engine/client/cl_main.c +++ b/engine/client/cl_main.c @@ -58,6 +58,7 @@ cvar_t cl_pext_mask = CVAR("cl_pext_mask", "0xffffffff"); cvar_t cl_nolerp = CVARD("cl_nolerp", "0", "Disables interpolation. If set, missiles/monsters will be smoother, but they may be more laggy. Does not affect players. A value of 2 means 'interpolate only in single-player/coop'."); cvar_t cl_nolerp_netquake = CVARD("cl_nolerp_netquake", "0", "Disables interpolation when connected to an NQ server. Does affect players, even the local player. You probably don't want to set this."); cvar_t hud_tracking_show = CVAR("hud_tracking_show", "1"); +extern cvar_t net_compress; cvar_t cl_defaultport = CVARAFD("cl_defaultport", STRINGIFY(PORT_QWSERVER), "port", 0, "The default port to connect to servers.\nQW: "STRINGIFY(PORT_QWSERVER)", NQ: "STRINGIFY(PORT_NQSERVER)", Q2: "STRINGIFY(PORT_Q2SERVER)"."); @@ -602,7 +603,7 @@ void CL_SendConnectPacket (netadr_t *to, int mtu, connectinfo.mtu = 0; #ifdef HUFFNETWORK - if (compressioncrc && Huff_CompressionCRC(compressioncrc)) + if (compressioncrc && net_compress.ival && Huff_CompressionCRC(compressioncrc)) { Q_strncatz(data, va("0x%x 0x%x\n", PROTOCOL_VERSION_HUFFMAN, LittleLong(compressioncrc)), sizeof(data)); connectinfo.compress = true; diff --git a/engine/client/cl_parse.c b/engine/client/cl_parse.c index bd475d8c1..ced00e495 100644 --- a/engine/client/cl_parse.c +++ b/engine/client/cl_parse.c @@ -1662,7 +1662,7 @@ downloadlist_t *CL_DownloadFailed(const char *name, qboolean cancel) if (!strncmp(cls.downloadtempname, "package/", 8)) FS_Remove(cls.downloadtempname, FS_ROOT); else if (!strncmp(cls.downloadtempname,"skins/",6)) - FS_Remove(va("qw/%s", cls.downloadtempname), FS_ROOT); + FS_Remove(cls.downloadtempname, FS_PUBBASEGAMEONLY); else FS_Remove(cls.downloadtempname, FS_GAME); CL_SendClientCommand(true, "stopdownload"); @@ -1791,8 +1791,8 @@ void CL_ParseChunkedDownload(void) } else if (!strncmp(cls.downloadtempname,"skins/",6)) { - FS_CreatePath (va("qw/%s", cls.downloadtempname), FS_ROOT); - cls.downloadqw = FS_OpenVFS (va("qw/%s", cls.downloadtempname), "wb", FS_ROOT); + FS_CreatePath (cls.downloadtempname, FS_PUBBASEGAMEONLY); + cls.downloadqw = FS_OpenVFS (cls.downloadtempname, "wb", FS_PUBBASEGAMEONLY); } else { @@ -2001,8 +2001,8 @@ void CL_ParseDownload (void) else { Q_snprintfz(name, sizeof(name), "%s", cls.downloadtempname); - FS_CreatePath (name, FS_GAME); - cls.downloadqw = FS_OpenVFS (name, "wb", FS_GAME); + FS_CreatePath (name, FS_GAMEONLY); + cls.downloadqw = FS_OpenVFS (name, "wb", FS_GAMEONLY); } if (!cls.downloadqw) { @@ -2136,8 +2136,8 @@ void CLDP_ParseDownloadBegin(char *s) VFS_CLOSE(cls.downloadqw); } - FS_CreatePath (cls.downloadtempname, FS_GAME); - cls.downloadqw = FS_OpenVFS (cls.downloadtempname, "wb", FS_GAME); + FS_CreatePath (cls.downloadtempname, FS_GAMEONLY); + cls.downloadqw = FS_OpenVFS (cls.downloadtempname, "wb", FS_GAMEONLY); cls.downloadmethod = DL_DARKPLACES; Q_strncpyz(cls.downloadlocalname, fname, sizeof(cls.downloadlocalname)); diff --git a/engine/client/cl_screen.c b/engine/client/cl_screen.c index d31327488..af0cc21a5 100644 --- a/engine/client/cl_screen.c +++ b/engine/client/cl_screen.c @@ -1858,25 +1858,25 @@ qboolean SCR_ScreenShot (char *filename, void *rgb_buffer, int width, int height return false; #ifdef AVAIL_PNGLIB - if (!strcmp(ext, "png")) + if (!Q_strcasecmp(ext, "png")) { return Image_WritePNG(filename, scr_sshot_compression.value, rgb_buffer, width, height); } else #endif #ifdef AVAIL_JPEGLIB - if (!strcmp(ext, "jpeg") || !strcmp(ext, "jpg")) + if (!Q_strcasecmp(ext, "jpeg") || !Q_strcasecmp(ext, "jpg")) { return screenshotJPEG(filename, scr_sshot_compression.value, rgb_buffer, width, height); } else #endif - /* if (!strcmp(ext, "bmp")) + /* if (!Q_strcasecmp(ext, "bmp")) { WriteBMPFile(pcxname, rgb_buffer, width, height); } else*/ - if (!strcmp(ext, "pcx")) + if (!Q_strcasecmp(ext, "pcx")) { int y, x; qbyte *src, *dest; @@ -1895,7 +1895,7 @@ qboolean SCR_ScreenShot (char *filename, void *rgb_buffer, int width, int height WritePCXfile (filename, newbuf, width, height, width, host_basepal, false); } - else //tga + else if (!Q_strcasecmp(ext, "tga")) //tga { vfsfile_t *vfs; FS_CreatePath(filename, FS_GAMEONLY); @@ -1924,6 +1924,8 @@ qboolean SCR_ScreenShot (char *filename, void *rgb_buffer, int width, int height VFS_CLOSE(vfs); } } + else //extension / type not recognised. + return false; return true; } diff --git a/engine/client/image.c b/engine/client/image.c index 94f16cc7e..cc8c05ba4 100644 --- a/engine/client/image.c +++ b/engine/client/image.c @@ -1540,7 +1540,7 @@ qboolean screenshotJPEG(char *filename, int compression, qbyte *screendata, int if (!(outfile = FS_OpenVFS(filename, "wb", FS_GAMEONLY))) { - FS_CreatePath (filename, FS_GAME); + FS_CreatePath (filename, FS_GAMEONLY); if (!(outfile = FS_OpenVFS(filename, "wb", FS_GAMEONLY))) { Con_Printf("Error opening %s\n", filename); diff --git a/engine/common/common.c b/engine/common/common.c index 0640bb8be..8e83e1277 100644 --- a/engine/common/common.c +++ b/engine/common/common.c @@ -1942,7 +1942,37 @@ void COM_DefaultExtension (char *path, char *extension, int maxlen) Q_strncatz (path, extension, maxlen); } +//adds .ext only if it isn't already present (either case). +//extension *must* contain a leading . as this is really a requiresuffix rather than an actual extension +//returns false if truncated. will otherwise still succeed. +qboolean COM_RequireExtension(char *path, char *extension, int maxlen) +{ + qboolean okay = true; + int plen = strlen(path); + int elen = strlen(extension); + //check if its aready suffixed + if (plen >= elen) + { + if (!Q_strcasecmp(path+plen-elen, extension)) + return okay; + } + + //truncate if required + if (plen+1+elen > maxlen) + { + if (elen+1 > maxlen) + Sys_Error("extension longer than path buffer"); + okay = false; + plen = maxlen - 1+elen; + } + + //do the copy + while(*extension) + path[plen++] = *extension++; + path[plen] = 0; + return okay; +} //errors: //1 sequence error diff --git a/engine/common/common.h b/engine/common/common.h index 53a339c4c..7a6ad8ad0 100644 --- a/engine/common/common.h +++ b/engine/common/common.h @@ -322,6 +322,7 @@ void COM_StripAllExtensions (char *in, char *out, int outlen); void COM_FileBase (const char *in, char *out, int outlen); int QDECL COM_FileSize(const char *path); void COM_DefaultExtension (char *path, char *extension, int maxlen); +qboolean COM_RequireExtension(char *path, char *extension, int maxlen); char *COM_FileExtension (const char *in); void COM_CleanUpPath(char *str); diff --git a/engine/common/gl_q2bsp.c b/engine/common/gl_q2bsp.c index 8a6b59074..db9f97e72 100644 --- a/engine/common/gl_q2bsp.c +++ b/engine/common/gl_q2bsp.c @@ -289,7 +289,7 @@ static int numtexinfo; static q2mapsurface_t *map_surfaces; static int numleafs = 1; // allow leaf funcs to be called without a map -static mleaf_t map_leafs[(MAX_MAP_LEAFS+7)/8]; +static mleaf_t map_leafs[MAX_MAP_LEAFS]; static int emptyleaf; static int numleafbrushes; diff --git a/engine/common/huff.c b/engine/common/huff.c index 85c7db6ee..5de6f307e 100644 --- a/engine/common/huff.c +++ b/engine/common/huff.c @@ -24,6 +24,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. // #include "quakedef.h" #ifdef HUFFNETWORK +extern cvar_t net_compress; #define ID_INLINE #define VALUE(a) (*(size_t *)&(a)) @@ -755,6 +756,9 @@ void Huff_LoadTable(char *filename) int Huff_PreferedCompressionCRC (void) { + if (!net_compress.ival) + return 0; + if (!madetable) Huff_Init(NULL); return madetable; @@ -797,17 +801,28 @@ void Huff_CompressPacket( sizebuf_t *msg, int offset ) inLen = msg->cursize - offset; if (inLen <= 0 || inLen >= MAX_OVERALLMSGLEN) { + //panic! return; } outLen = 0; for (i=0; i < inLen; i++) { - if (i == MAX_OVERALLMSGLEN) - Sys_Error("Compression became too large\n"); Huff_EmitByte(data[i], buffer, &outLen); countinghuffCounts[data[i]]++; + + outLen = (huffBitPos >> 3) + 1; + if (outLen > inLen) + break; + if (outLen > MAX_OVERALLMSGLEN-64) + { + Con_Printf("Huffman overflow\n"); + //panic + data[0] = 0x80; + msg->cursize = offset+1; + return; + } } outLen = (huffBitPos >> 3) + 1; diff --git a/engine/common/net_chan.c b/engine/common/net_chan.c index 8bd7dd9f7..c637710eb 100644 --- a/engine/common/net_chan.c +++ b/engine/common/net_chan.c @@ -85,6 +85,7 @@ cvar_t showpackets = SCVAR("showpackets", "0"); cvar_t showdrop = SCVAR("showdrop", "0"); cvar_t qport = SCVAR("qport", "0"); cvar_t net_mtu = CVARD("net_mtu", "1440", "Specifies a maximum udp payload size, above which packets will be fragmented. If routers all worked properly this could be some massive value, and some massive value may work really nicely for lans. Use smaller values than the default if you're connecting through nested tunnels through routers that fail with IP fragmentation."); +cvar_t net_compress = CVARD("net_compress", "0", "Enables huffman compression of network packets."); cvar_t pext_replacementdeltas = CVAR("pext_replacementdeltas", "1"); cvar_t pext_nqpredinfo = CVAR("debug_pext_nqpredinfo", "0"); @@ -235,6 +236,7 @@ void Netchan_Init (void) Cvar_Register (&showdrop, "Networking"); Cvar_Register (&qport, "Networking"); Cvar_Register (&net_mtu, "Networking"); + Cvar_Register (&net_compress, "Networking"); // pick a port value that should be nice and random #ifdef _WIN32 diff --git a/engine/gl/gl_draw.c b/engine/gl/gl_draw.c index e2a20c6cc..4456224a1 100644 --- a/engine/gl/gl_draw.c +++ b/engine/gl/gl_draw.c @@ -1035,7 +1035,7 @@ static void GL_MipMap8Bit (qbyte *in, int width, int height) #endif #endif -qboolean GL_UploadCompressed (qbyte *file, int *out_width, int *out_height, unsigned int *out_flags) +static qboolean GL_UploadCompressed (qbyte *file, int *out_width, int *out_height, unsigned int *out_flags) { int miplevel; int width; @@ -1405,8 +1405,8 @@ static void GL_Upload32_Int (const char *name, unsigned *data, int width, int he if (compressed == GL_TRUE && !strstr(name, "..")) //is there any point in bothering with the whole endian thing? { Q_snprintfz(outname, sizeof(outname), "tex/%s.tex", name); - FS_CreatePath(outname, FS_GAME); - out = FS_OpenVFS(outname, "wb", FS_GAME); + FS_CreatePath(outname, FS_GAMEONLY); + out = FS_OpenVFS(outname, "wb", FS_GAMEONLY); if (out) { i = LittleLong(miplevels); diff --git a/engine/http/httpclient.c b/engine/http/httpclient.c index 40a8b72ef..fbe947f4e 100644 --- a/engine/http/httpclient.c +++ b/engine/http/httpclient.c @@ -30,8 +30,8 @@ static void DL_OnLoad(void *c, void *data, int datasize) { if (*dl->localname) { - FS_CreatePath(dl->localname, FS_GAME); - dl->file = FS_OpenVFS(dl->localname, "w+b", FS_GAME); + FS_CreatePath(dl->localname, FS_GAMEONLY); + dl->file = FS_OpenVFS(dl->localname, "w+b", FS_GAMEONLY); } else { diff --git a/engine/server/pr_cmds.c b/engine/server/pr_cmds.c index fc8ea6e8c..882def7aa 100644 --- a/engine/server/pr_cmds.c +++ b/engine/server/pr_cmds.c @@ -3772,7 +3772,7 @@ void PF_precache_sound_Internal (pubprogfuncs_t *prinst, const char *s) { if (!*sv.strings.sound_precache[i]) { - strcpy(sv.strings.sound_precache[i], s); + Q_strncpyz(sv.strings.sound_precache[i], s, sizeof(sv.strings.sound_precache[i])); /*touch the file, so any packs will be referenced*/ FS_FLocateFile(s, FSLFRT_IFFOUND, NULL); diff --git a/engine/server/savegame.c b/engine/server/savegame.c index 349b7a4e6..f315c3e95 100644 --- a/engine/server/savegame.c +++ b/engine/server/savegame.c @@ -374,8 +374,7 @@ void SV_LegacySavegame_f (void) } sprintf (name, "%s", Cmd_Argv(1)); - COM_DefaultExtension (name, ".sav", sizeof(name)); - + COM_RequireExtension (name, ".sav", sizeof(name)); if (!FS_NativePath(name, FS_GAMEONLY, native, sizeof(native))) return; Con_TPrintf (U8("Saving game to %s...\n"), native); diff --git a/engine/server/server.h b/engine/server/server.h index 0664c6d54..27022719e 100644 --- a/engine/server/server.h +++ b/engine/server/server.h @@ -522,6 +522,7 @@ typedef struct client_s VT_TEAM, VT_ALL, VT_NONMUTED, /*cheap, but allows custom private channels with no external pesters*/ + VT_SPECSELF, /*sends to self, audiable to people spectating self*/ VT_PLAYERSLOT0 /*player0+...*/ } voice_target; diff --git a/engine/server/sv_main.c b/engine/server/sv_main.c index 708fd9762..f39acfc32 100644 --- a/engine/server/sv_main.c +++ b/engine/server/sv_main.c @@ -1489,7 +1489,7 @@ void SVC_GetChallenge (void) compressioncrc = Huff_PreferedCompressionCRC(); if (compressioncrc) { - lng = LittleLong((('H'<<0) + ('U'<<8) + ('F'<<16) + ('F' << 24))); + lng = LittleLong(PROTOCOL_VERSION_HUFFMAN); memcpy(over, &lng, sizeof(lng)); over+=sizeof(lng); @@ -2710,7 +2710,7 @@ client_t *SVC_DirectConnect(void) unsigned int protextsupported=0; unsigned int protextsupported2=0; - extern cvar_t sv_protocol_nq; + extern cvar_t sv_protocol_nq, net_compress; char *name; @@ -2905,6 +2905,12 @@ client_t *SVC_DirectConnect(void) case PROTOCOL_VERSION_HUFFMAN: huffcrc = Q_atoi(Cmd_Argv(1)); Con_DPrintf("Client supports huffman compression. crc 0x%x\n", huffcrc); + if (!net_compress.ival || !Huff_CompressionCRC(huffcrc)) + { + SV_RejectMessage (protocol, "Compression should not have been enabled.\n"); //buggy/exploiting client. can also happen from timing when changing the setting, but whatever + Con_TPrintf ("* rejected - bad compression state\n"); + return NULL; + } break; case PROTOCOL_VERSION_FRAGMENT: mtu = Q_atoi(Cmd_Argv(1)) & ~7; diff --git a/engine/server/sv_send.c b/engine/server/sv_send.c index 70a0224eb..cbc56bb59 100644 --- a/engine/server/sv_send.c +++ b/engine/server/sv_send.c @@ -980,16 +980,37 @@ void SV_StartSound (int ent, vec3_t origin, int seenmask, int channel, const cha else { for (sound_num=1 ; sound_numvoice_mute[j>>3] & (1<<(j&3))) continue; } + else if (vt == VT_SPECSELF) + { + //spectators spectating self hear it. + //self hears it (for demos, voip_echo stops it from actually being echoed) + if (!host_client->spectator || host_client->spec_track != host_client-svs.clients) + if (j != host_client-svs.clients) + continue; + } else if (vt >= VT_PLAYERSLOT0) { if (j != vt - VT_PLAYERSLOT0) @@ -2519,6 +2527,12 @@ void SV_Voice_Target_f(void) if (verbose) SV_ClientTPrintf(host_client, PRINT_HIGH, "Now sending voice to all\n"); } + else if (!strcmp(t, "specself")) + { + host_client->voice_target = VT_SPECSELF; + if (verbose) + SV_ClientTPrintf(host_client, PRINT_HIGH, "Now sending voice to your personal admirers\n"); + } else if (!strcmp(t, "nonmuted")) { host_client->voice_target = VT_NONMUTED;