1
0
Fork 0
forked from fte/fteqw

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
This commit is contained in:
Spoike 2014-04-27 23:16:07 +00:00
parent eb3f5addb5
commit c0841c73ab
18 changed files with 126 additions and 34 deletions

View file

@ -1490,7 +1490,7 @@ void CL_ReRecord_f (void)
// //
// open the demo file // open the demo file
// //
COM_DefaultExtension (name, ".qwd", sizeof(name)); COM_RequireExtension (name, ".qwd", sizeof(name));
cls.demooutfile = FS_OpenVFS (name, "wb", FS_GAME); cls.demooutfile = FS_OpenVFS (name, "wb", FS_GAME);
if (!cls.demooutfile) if (!cls.demooutfile)

View file

@ -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 = 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 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"); 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)"."); 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; connectinfo.mtu = 0;
#ifdef HUFFNETWORK #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)); Q_strncatz(data, va("0x%x 0x%x\n", PROTOCOL_VERSION_HUFFMAN, LittleLong(compressioncrc)), sizeof(data));
connectinfo.compress = true; connectinfo.compress = true;

View file

@ -1662,7 +1662,7 @@ downloadlist_t *CL_DownloadFailed(const char *name, qboolean cancel)
if (!strncmp(cls.downloadtempname, "package/", 8)) if (!strncmp(cls.downloadtempname, "package/", 8))
FS_Remove(cls.downloadtempname, FS_ROOT); FS_Remove(cls.downloadtempname, FS_ROOT);
else if (!strncmp(cls.downloadtempname,"skins/",6)) else if (!strncmp(cls.downloadtempname,"skins/",6))
FS_Remove(va("qw/%s", cls.downloadtempname), FS_ROOT); FS_Remove(cls.downloadtempname, FS_PUBBASEGAMEONLY);
else else
FS_Remove(cls.downloadtempname, FS_GAME); FS_Remove(cls.downloadtempname, FS_GAME);
CL_SendClientCommand(true, "stopdownload"); CL_SendClientCommand(true, "stopdownload");
@ -1791,8 +1791,8 @@ void CL_ParseChunkedDownload(void)
} }
else if (!strncmp(cls.downloadtempname,"skins/",6)) else if (!strncmp(cls.downloadtempname,"skins/",6))
{ {
FS_CreatePath (va("qw/%s", cls.downloadtempname), FS_ROOT); FS_CreatePath (cls.downloadtempname, FS_PUBBASEGAMEONLY);
cls.downloadqw = FS_OpenVFS (va("qw/%s", cls.downloadtempname), "wb", FS_ROOT); cls.downloadqw = FS_OpenVFS (cls.downloadtempname, "wb", FS_PUBBASEGAMEONLY);
} }
else else
{ {
@ -2001,8 +2001,8 @@ void CL_ParseDownload (void)
else else
{ {
Q_snprintfz(name, sizeof(name), "%s", cls.downloadtempname); Q_snprintfz(name, sizeof(name), "%s", cls.downloadtempname);
FS_CreatePath (name, FS_GAME); FS_CreatePath (name, FS_GAMEONLY);
cls.downloadqw = FS_OpenVFS (name, "wb", FS_GAME); cls.downloadqw = FS_OpenVFS (name, "wb", FS_GAMEONLY);
} }
if (!cls.downloadqw) if (!cls.downloadqw)
{ {
@ -2136,8 +2136,8 @@ void CLDP_ParseDownloadBegin(char *s)
VFS_CLOSE(cls.downloadqw); VFS_CLOSE(cls.downloadqw);
} }
FS_CreatePath (cls.downloadtempname, FS_GAME); FS_CreatePath (cls.downloadtempname, FS_GAMEONLY);
cls.downloadqw = FS_OpenVFS (cls.downloadtempname, "wb", FS_GAME); cls.downloadqw = FS_OpenVFS (cls.downloadtempname, "wb", FS_GAMEONLY);
cls.downloadmethod = DL_DARKPLACES; cls.downloadmethod = DL_DARKPLACES;
Q_strncpyz(cls.downloadlocalname, fname, sizeof(cls.downloadlocalname)); Q_strncpyz(cls.downloadlocalname, fname, sizeof(cls.downloadlocalname));

View file

@ -1858,25 +1858,25 @@ qboolean SCR_ScreenShot (char *filename, void *rgb_buffer, int width, int height
return false; return false;
#ifdef AVAIL_PNGLIB #ifdef AVAIL_PNGLIB
if (!strcmp(ext, "png")) if (!Q_strcasecmp(ext, "png"))
{ {
return Image_WritePNG(filename, scr_sshot_compression.value, rgb_buffer, width, height); return Image_WritePNG(filename, scr_sshot_compression.value, rgb_buffer, width, height);
} }
else else
#endif #endif
#ifdef AVAIL_JPEGLIB #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); return screenshotJPEG(filename, scr_sshot_compression.value, rgb_buffer, width, height);
} }
else else
#endif #endif
/* if (!strcmp(ext, "bmp")) /* if (!Q_strcasecmp(ext, "bmp"))
{ {
WriteBMPFile(pcxname, rgb_buffer, width, height); WriteBMPFile(pcxname, rgb_buffer, width, height);
} }
else*/ else*/
if (!strcmp(ext, "pcx")) if (!Q_strcasecmp(ext, "pcx"))
{ {
int y, x; int y, x;
qbyte *src, *dest; 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); WritePCXfile (filename, newbuf, width, height, width, host_basepal, false);
} }
else //tga else if (!Q_strcasecmp(ext, "tga")) //tga
{ {
vfsfile_t *vfs; vfsfile_t *vfs;
FS_CreatePath(filename, FS_GAMEONLY); FS_CreatePath(filename, FS_GAMEONLY);
@ -1924,6 +1924,8 @@ qboolean SCR_ScreenShot (char *filename, void *rgb_buffer, int width, int height
VFS_CLOSE(vfs); VFS_CLOSE(vfs);
} }
} }
else //extension / type not recognised.
return false;
return true; return true;
} }

View file

@ -1540,7 +1540,7 @@ qboolean screenshotJPEG(char *filename, int compression, qbyte *screendata, int
if (!(outfile = FS_OpenVFS(filename, "wb", FS_GAMEONLY))) 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))) if (!(outfile = FS_OpenVFS(filename, "wb", FS_GAMEONLY)))
{ {
Con_Printf("Error opening %s\n", filename); Con_Printf("Error opening %s\n", filename);

View file

@ -1942,7 +1942,37 @@ void COM_DefaultExtension (char *path, char *extension, int maxlen)
Q_strncatz (path, extension, 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: //errors:
//1 sequence error //1 sequence error

View file

@ -322,6 +322,7 @@ void COM_StripAllExtensions (char *in, char *out, int outlen);
void COM_FileBase (const char *in, char *out, int outlen); void COM_FileBase (const char *in, char *out, int outlen);
int QDECL COM_FileSize(const char *path); int QDECL COM_FileSize(const char *path);
void COM_DefaultExtension (char *path, char *extension, int maxlen); void COM_DefaultExtension (char *path, char *extension, int maxlen);
qboolean COM_RequireExtension(char *path, char *extension, int maxlen);
char *COM_FileExtension (const char *in); char *COM_FileExtension (const char *in);
void COM_CleanUpPath(char *str); void COM_CleanUpPath(char *str);

View file

@ -289,7 +289,7 @@ static int numtexinfo;
static q2mapsurface_t *map_surfaces; static q2mapsurface_t *map_surfaces;
static int numleafs = 1; // allow leaf funcs to be called without a map 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 emptyleaf;
static int numleafbrushes; static int numleafbrushes;

View file

@ -24,6 +24,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
// //
#include "quakedef.h" #include "quakedef.h"
#ifdef HUFFNETWORK #ifdef HUFFNETWORK
extern cvar_t net_compress;
#define ID_INLINE #define ID_INLINE
#define VALUE(a) (*(size_t *)&(a)) #define VALUE(a) (*(size_t *)&(a))
@ -755,6 +756,9 @@ void Huff_LoadTable(char *filename)
int Huff_PreferedCompressionCRC (void) int Huff_PreferedCompressionCRC (void)
{ {
if (!net_compress.ival)
return 0;
if (!madetable) if (!madetable)
Huff_Init(NULL); Huff_Init(NULL);
return madetable; return madetable;
@ -797,17 +801,28 @@ void Huff_CompressPacket( sizebuf_t *msg, int offset )
inLen = msg->cursize - offset; inLen = msg->cursize - offset;
if (inLen <= 0 || inLen >= MAX_OVERALLMSGLEN) if (inLen <= 0 || inLen >= MAX_OVERALLMSGLEN)
{ {
//panic!
return; return;
} }
outLen = 0; outLen = 0;
for (i=0; i < inLen; i++) for (i=0; i < inLen; i++)
{ {
if (i == MAX_OVERALLMSGLEN)
Sys_Error("Compression became too large\n");
Huff_EmitByte(data[i], buffer, &outLen); Huff_EmitByte(data[i], buffer, &outLen);
countinghuffCounts[data[i]]++; 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; outLen = (huffBitPos >> 3) + 1;

View file

@ -85,6 +85,7 @@ cvar_t showpackets = SCVAR("showpackets", "0");
cvar_t showdrop = SCVAR("showdrop", "0"); cvar_t showdrop = SCVAR("showdrop", "0");
cvar_t qport = SCVAR("qport", "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_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_replacementdeltas = CVAR("pext_replacementdeltas", "1");
cvar_t pext_nqpredinfo = CVAR("debug_pext_nqpredinfo", "0"); cvar_t pext_nqpredinfo = CVAR("debug_pext_nqpredinfo", "0");
@ -235,6 +236,7 @@ void Netchan_Init (void)
Cvar_Register (&showdrop, "Networking"); Cvar_Register (&showdrop, "Networking");
Cvar_Register (&qport, "Networking"); Cvar_Register (&qport, "Networking");
Cvar_Register (&net_mtu, "Networking"); Cvar_Register (&net_mtu, "Networking");
Cvar_Register (&net_compress, "Networking");
// pick a port value that should be nice and random // pick a port value that should be nice and random
#ifdef _WIN32 #ifdef _WIN32

View file

@ -1035,7 +1035,7 @@ static void GL_MipMap8Bit (qbyte *in, int width, int height)
#endif #endif
#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 miplevel;
int width; 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? 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); Q_snprintfz(outname, sizeof(outname), "tex/%s.tex", name);
FS_CreatePath(outname, FS_GAME); FS_CreatePath(outname, FS_GAMEONLY);
out = FS_OpenVFS(outname, "wb", FS_GAME); out = FS_OpenVFS(outname, "wb", FS_GAMEONLY);
if (out) if (out)
{ {
i = LittleLong(miplevels); i = LittleLong(miplevels);

View file

@ -30,8 +30,8 @@ static void DL_OnLoad(void *c, void *data, int datasize)
{ {
if (*dl->localname) if (*dl->localname)
{ {
FS_CreatePath(dl->localname, FS_GAME); FS_CreatePath(dl->localname, FS_GAMEONLY);
dl->file = FS_OpenVFS(dl->localname, "w+b", FS_GAME); dl->file = FS_OpenVFS(dl->localname, "w+b", FS_GAMEONLY);
} }
else else
{ {

View file

@ -3772,7 +3772,7 @@ void PF_precache_sound_Internal (pubprogfuncs_t *prinst, const char *s)
{ {
if (!*sv.strings.sound_precache[i]) 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*/ /*touch the file, so any packs will be referenced*/
FS_FLocateFile(s, FSLFRT_IFFOUND, NULL); FS_FLocateFile(s, FSLFRT_IFFOUND, NULL);

View file

@ -374,8 +374,7 @@ void SV_LegacySavegame_f (void)
} }
sprintf (name, "%s", Cmd_Argv(1)); 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))) if (!FS_NativePath(name, FS_GAMEONLY, native, sizeof(native)))
return; return;
Con_TPrintf (U8("Saving game to %s...\n"), native); Con_TPrintf (U8("Saving game to %s...\n"), native);

View file

@ -522,6 +522,7 @@ typedef struct client_s
VT_TEAM, VT_TEAM,
VT_ALL, VT_ALL,
VT_NONMUTED, /*cheap, but allows custom private channels with no external pesters*/ VT_NONMUTED, /*cheap, but allows custom private channels with no external pesters*/
VT_SPECSELF, /*sends to self, audiable to people spectating self*/
VT_PLAYERSLOT0 VT_PLAYERSLOT0
/*player0+...*/ /*player0+...*/
} voice_target; } voice_target;

View file

@ -1489,7 +1489,7 @@ void SVC_GetChallenge (void)
compressioncrc = Huff_PreferedCompressionCRC(); compressioncrc = Huff_PreferedCompressionCRC();
if (compressioncrc) if (compressioncrc)
{ {
lng = LittleLong((('H'<<0) + ('U'<<8) + ('F'<<16) + ('F' << 24))); lng = LittleLong(PROTOCOL_VERSION_HUFFMAN);
memcpy(over, &lng, sizeof(lng)); memcpy(over, &lng, sizeof(lng));
over+=sizeof(lng); over+=sizeof(lng);
@ -2710,7 +2710,7 @@ client_t *SVC_DirectConnect(void)
unsigned int protextsupported=0; unsigned int protextsupported=0;
unsigned int protextsupported2=0; unsigned int protextsupported2=0;
extern cvar_t sv_protocol_nq; extern cvar_t sv_protocol_nq, net_compress;
char *name; char *name;
@ -2905,6 +2905,12 @@ client_t *SVC_DirectConnect(void)
case PROTOCOL_VERSION_HUFFMAN: case PROTOCOL_VERSION_HUFFMAN:
huffcrc = Q_atoi(Cmd_Argv(1)); huffcrc = Q_atoi(Cmd_Argv(1));
Con_DPrintf("Client supports huffman compression. crc 0x%x\n", huffcrc); 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; break;
case PROTOCOL_VERSION_FRAGMENT: case PROTOCOL_VERSION_FRAGMENT:
mtu = Q_atoi(Cmd_Argv(1)) & ~7; mtu = Q_atoi(Cmd_Argv(1)) & ~7;

View file

@ -980,16 +980,37 @@ void SV_StartSound (int ent, vec3_t origin, int seenmask, int channel, const cha
else else
{ {
for (sound_num=1 ; sound_num<MAX_SOUNDS for (sound_num=1 ; sound_num<MAX_SOUNDS
&& sv.strings.sound_precache[sound_num] ; sound_num++) && *sv.strings.sound_precache[sound_num] ; sound_num++)
if (!strcmp(sample, sv.strings.sound_precache[sound_num])) if (!strcmp(sample, sv.strings.sound_precache[sound_num]))
break; break;
} }
if ( sound_num == MAX_SOUNDS || !sv.strings.sound_precache[sound_num] ) if ( sound_num == MAX_SOUNDS || !*sv.strings.sound_precache[sound_num] )
{ {
Con_DPrintf ("SV_StartSound: %s not precacheed\n", sample); if (sound_num < MAX_SOUNDS)
return; {
} Con_Printf("WARNING: SV_StartSound: sound %s not precached\n", sample);
//late precache it. use multicast to ensure that its sent NOW (and to all). normal reliables would mean it would arrive after the svc_sound
Q_strncpyz(sv.strings.sound_precache[sound_num], sample, sizeof(sv.strings.sound_precache[sound_num]));
Con_DPrintf("Delayed sound precache: %s\n", sample);
MSG_WriteByte(&sv.multicast, svcfte_precache);
MSG_WriteShort(&sv.multicast, sound_num+PC_SOUND);
MSG_WriteString(&sv.multicast, sample);
#ifdef NQPROT
MSG_WriteByte(&sv.nqmulticast, svcdp_precache);
MSG_WriteShort(&sv.nqmulticast, sound_num+PC_SOUND);
MSG_WriteString(&sv.nqmulticast, sample);
#endif
SV_MulticastProtExt(NULL, MULTICAST_ALL_R, FULLDIMENSIONMASK, PEXT_CSQC, 0);
reliable = true; //try to make sure it doesn't arrive before the precache!
}
else
{
Con_DPrintf ("SV_StartSound: %s not precached\n", sample);
return;
}
}
if (reliable || !sv_phs.value) // no PHS flag if (reliable || !sv_phs.value) // no PHS flag
use_phs = false; use_phs = false;

View file

@ -2358,6 +2358,14 @@ void SV_VoiceReadPacket(void)
if (host_client->voice_mute[j>>3] & (1<<(j&3))) if (host_client->voice_mute[j>>3] & (1<<(j&3)))
continue; 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) else if (vt >= VT_PLAYERSLOT0)
{ {
if (j != vt - VT_PLAYERSLOT0) if (j != vt - VT_PLAYERSLOT0)
@ -2519,6 +2527,12 @@ void SV_Voice_Target_f(void)
if (verbose) if (verbose)
SV_ClientTPrintf(host_client, PRINT_HIGH, "Now sending voice to all\n"); 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")) else if (!strcmp(t, "nonmuted"))
{ {
host_client->voice_target = VT_NONMUTED; host_client->voice_target = VT_NONMUTED;