From 2bf193001bdab867420b34f1d476199a2a243d6f Mon Sep 17 00:00:00 2001 From: Spoike Date: Wed, 21 Jun 2017 01:24:25 +0000 Subject: [PATCH] implement pcma+pcmu codecs for voip for xmpp compat, because they're fairly simple and I can. remove MAX_MAP_LEAFS limit, although its still checked for sanity (just MUCH higher). You may need 64bit processes on account of the pvs+phs memory required. integrated my fork of frikdec into fteqccgui. Just associate .dat with fteqccgui and it'll decompile the progs (compiling will then embed the decompiled source into the resulting .dat to avoid repeated decompilation). Be sure to back up first... not tested as a 64bit process. git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@5114 fc73d0e0-1445-4013-8a0c-d673dee63da5 --- engine/Makefile | 6 +- engine/client/cl_cg.c | 2 +- engine/client/cl_demo.c | 36 ++-- engine/client/cl_ents.c | 84 ++++++-- engine/client/cl_input.c | 6 +- engine/client/cl_main.c | 17 +- engine/client/cl_parse.c | 7 +- engine/client/cl_ui.c | 9 +- engine/client/clq2_ents.c | 2 +- engine/client/in_win.c | 92 +++++++- engine/client/keys.c | 10 +- engine/client/keys.h | 12 +- engine/client/m_mp3.c | 2 +- engine/client/m_options.c | 16 +- engine/client/net_master.c | 2 +- engine/client/pr_csqc.c | 6 +- engine/client/quakedef.h | 16 +- engine/client/r_d3.c | 8 +- engine/client/r_surf.c | 62 +++--- engine/client/render.h | 4 + engine/client/renderer.c | 41 ++-- engine/client/snd_directx.c | 8 +- engine/client/snd_dma.c | 207 ++++++++++++++++-- engine/client/sys_linux.c | 2 - engine/client/sys_win.c | 44 ++++ engine/client/winquake.h | 11 +- engine/common/bothdefs.h | 2 +- engine/common/bspfile.h | 17 +- engine/common/com_mesh.c | 41 ++-- engine/common/common.c | 84 ++++---- engine/common/common.h | 3 +- engine/common/gl_q2bsp.c | 128 ++++++----- engine/common/net.h | 4 +- engine/common/net_ice.c | 84 +++++--- engine/common/net_ssl_gnutls.c | 54 +++-- engine/common/net_ssl_winsspi.c | 71 +++++-- engine/common/net_wins.c | 120 +++++++---- engine/common/netinc.h | 27 ++- engine/common/pr_bgcmd.c | 13 +- engine/common/q1bsp.c | 150 ++++++++----- engine/common/world.h | 2 +- engine/d3d/vid_d3d.c | 4 + engine/d3d/vid_d3d11.c | 4 + engine/d3d/vid_d3d8.c | 4 + engine/dotnet2005/emscripten.vcproj | 4 +- engine/dotnet2005/ftequake.sln | 316 ++++++++++++++-------------- engine/gl/gl_alias.c | 6 - engine/gl/gl_backend.c | 5 - engine/gl/gl_heightmap.c | 18 +- engine/gl/gl_model.c | 15 +- engine/gl/gl_model.h | 34 ++- engine/gl/gl_rmain.c | 108 +++++++--- engine/gl/gl_shader.c | 18 +- engine/gl/gl_shadow.c | 14 +- engine/gl/gl_vidnt.c | 54 +++-- engine/http/iwebiface.c | 33 +-- engine/qclib/qcc.h | 14 ++ engine/qclib/qcc_pr_comp.c | 58 +++-- engine/qclib/qcc_pr_lex.c | 8 +- engine/qclib/qccgui.c | 167 ++++++++++----- engine/qclib/qccguistuff.c | 26 +++ engine/qclib/qcd.h | 3 +- engine/qclib/qcd_main.c | 14 +- engine/server/pr_cmds.c | 4 +- engine/server/sv_ents.c | 67 +++--- engine/server/sv_init.c | 37 ++-- engine/server/sv_main.c | 16 +- engine/server/sv_mvd.c | 109 +++++++--- engine/server/sv_send.c | 12 +- engine/server/sv_user.c | 23 +- engine/server/svq2_ents.c | 13 +- engine/server/svq2_game.c | 4 +- engine/server/svq3_game.c | 26 +-- engine/sw/sw_vidwin.c | 4 + engine/vk/vk_backend.c | 22 +- fteqtv/source.c | 24 ++- plugins/ezhud/ezquakeisms.c | 8 +- plugins/irc/ircclient.c | 74 ++++--- plugins/jabber/jabberclient.c | 130 +++++++----- plugins/jabber/jingle.c | 117 ++++++---- plugins/jabber/xmpp.h | 6 +- 81 files changed, 2034 insertions(+), 1101 deletions(-) diff --git a/engine/Makefile b/engine/Makefile index 2e6dfcfb..8d909a8a 100644 --- a/engine/Makefile +++ b/engine/Makefile @@ -1762,11 +1762,11 @@ _qcc-tmp: $(REQDIR) qcc-rel: @$(MAKE) _qcc-tmp TYPE=_out-rel REQDIR=reldir EXE_NAME="../fteqcc$(BITS)" OUT_DIR="$(RELEASE_DIR)/$(NCDIRPREFIX)$(QCC_DIR)" SOBJS="qcctui.o $(if $(findstring win,$(FTE_TARGET)),fteqcc.o)" qccgui-rel: - @$(MAKE) _qcc-tmp TYPE=_out-rel REQDIR=reldir EXE_NAME="../fteqccgui$(BITS)" OUT_DIR="$(RELEASE_DIR)/$(NCDIRPREFIX)$(QCC_DIR)gui" SOBJS="qccgui.o qccguistuff.o fteqcc.o" LDFLAGS="$(LDFLAGS) -lole32 -lcomdlg32 -lcomctl32 -lshlwapi -mwindows" + @$(MAKE) _qcc-tmp TYPE=_out-rel REQDIR=reldir EXE_NAME="../fteqccgui$(BITS)" OUT_DIR="$(RELEASE_DIR)/$(NCDIRPREFIX)$(QCC_DIR)gui" SOBJS="qccgui.o qccguistuff.o decomp.o fteqcc.o" LDFLAGS="$(LDFLAGS) -lole32 -lcomdlg32 -lcomctl32 -lshlwapi -mwindows" qcc-dbg: @$(MAKE) _qcc-tmp TYPE=_out-dbg REQDIR=debugdir EXE_NAME="../fteqcc$(BITS)" OUT_DIR="$(DEBUG_DIR)/$(NCDIRPREFIX)$(QCC_DIR)" SOBJS="qcctui.o $(if $(findstring win,$(FTE_TARGET)),fteqcc.o)" qccgui-dbg: - @$(MAKE) _qcc-tmp TYPE=_out-dbg REQDIR=debugdir EXE_NAME="../fteqccgui$(BITS)" OUT_DIR="$(DEBUG_DIR)/$(NCDIRPREFIX)$(QCC_DIR)gui" SOBJS="qccgui.o qccguistuff.o fteqcc.o" LDFLAGS="$(LDFLAGS) -lole32 -lcomdlg32 -lcomctl32 -lshlwapi -mwindows" + @$(MAKE) _qcc-tmp TYPE=_out-dbg REQDIR=debugdir EXE_NAME="../fteqccgui$(BITS)" OUT_DIR="$(DEBUG_DIR)/$(NCDIRPREFIX)$(QCC_DIR)gui" SOBJS="qccgui.o qccguistuff.o decomp.o fteqcc.o" LDFLAGS="$(LDFLAGS) -lole32 -lcomdlg32 -lcomctl32 -lshlwapi -mwindows" #scintilla is messy as fuck when building statically. but at least we can strip out the lexers we don't use this way. @@ -1784,7 +1784,7 @@ scintilla$(BITS)_static: @$(MAKE) reldir OUT_DIR=$(RELEASE_DIR)/$(QCC_DIR)scin @$(MAKE) $(RELEASE_DIR)/scintilla$(BITS).a VPATH="$(SCINTILLA_DIRS)" CFLAGS="$(SCINTILLA_INC) -DDISABLE_D2D -DSTATIC_BUILD -DSCI_LEXER -std=c++11" OUT_DIR=$(RELEASE_DIR)/$(QCC_DIR)scin WCFLAGS="$(WCFLAGS) -Os" WARNINGFLAGS= qccgui-scintilla: scintilla$(BITS)_static - @$(MAKE) _qcc-tmp TYPE=_out-rel REQDIR=reldir EXE_NAME="../fteqccgui$(BITS)" OUT_DIR="$(RELEASE_DIR)/$(QCC_DIR)scin" SOBJS="qccgui.o qccguistuff.o fteqcc.o" WCFLAGS="$(WCFLAGS) -DSCISTATIC" LDFLAGS="$(LDFLAGS) $(RELEASE_DIR)/scintilla$(BITS).a -static -luuid -lole32 -limm32 -lstdc++ -loleaut32 -lcomdlg32 -lcomctl32 -lshlwapi -mwindows" + @$(MAKE) _qcc-tmp TYPE=_out-rel REQDIR=reldir EXE_NAME="../fteqccgui$(BITS)" OUT_DIR="$(RELEASE_DIR)/$(QCC_DIR)scin" SOBJS="qccgui.o qccguistuff.o decomp.o fteqcc.o" WCFLAGS="$(WCFLAGS) -DSCISTATIC" LDFLAGS="$(LDFLAGS) $(RELEASE_DIR)/scintilla$(BITS).a -static -luuid -lole32 -limm32 -lstdc++ -loleaut32 -lcomdlg32 -lcomctl32 -lshlwapi -mwindows" ifdef windir debugdir: diff --git a/engine/client/cl_cg.c b/engine/client/cl_cg.c index 0a76763b..2ed90e8f 100644 --- a/engine/client/cl_cg.c +++ b/engine/client/cl_cg.c @@ -968,7 +968,7 @@ static qintptr_t CG_SystemCalls(void *offset, quintptr_t mask, qintptr_t fn, con case CG_KEY_ISDOWN: { - extern qboolean keydown[256]; + extern qboolean keydown[K_MAX]; if (keydown[VM_LONG(arg[0])]) VM_LONG(ret) = 1; else diff --git a/engine/client/cl_demo.c b/engine/client/cl_demo.c index 4c151739..75784028 100644 --- a/engine/client/cl_demo.c +++ b/engine/client/cl_demo.c @@ -2626,7 +2626,7 @@ char *strchrrev(char *str, char chr) return NULL; } -void CL_ParseQTVFile(vfsfile_t *f, const char *fname, qtvfile_t *result) +/*void CL_ParseQTVFile(vfsfile_t *f, const char *fname, qtvfile_t *result) { char buffer[2048]; char *s; @@ -2713,10 +2713,12 @@ void CL_ParseQTVFile(vfsfile_t *f, const char *fname, qtvfile_t *result) } } VFS_CLOSE(f); -} +}*/ void CL_ParseQTVDescriptor(vfsfile_t *f, const char *name) -{ +{ //.qtv files are some sneaky way to deal with download links using file extension associations instead of special protocols. + //they basically contain some directive:hostname line that tells us what to do and where from. + //they should have mime type text/x-quaketvident with extension .qtv char buffer[1024]; char *s; @@ -2799,6 +2801,7 @@ void CL_QTVPlay_f (void) char *host; char msg[4096]; int msglen=0; + char *password; if (Cmd_Argc() < 2) { @@ -2808,12 +2811,12 @@ void CL_QTVPlay_f (void) connrequest = Cmd_Argv(1); - if (*connrequest == '#') + /*if (*connrequest == '#') { //#FILENAME is a local system path CL_ParseQTVDescriptor(VFSOS_Open(connrequest+1, "rt"), connrequest+1); return; - } + }*/ strcpy(cls.servername, "qtv:"); Q_strncpyz(cls.servername+4, connrequest, sizeof(cls.servername)-4); @@ -2840,6 +2843,8 @@ void CL_QTVPlay_f (void) else host = NULL; + password = Cmd_Argv(2); + if (qtvcl_forceversion1.ival) { Q_snprintfz(msg+msglen, sizeof(msg)-msglen, @@ -2854,23 +2859,22 @@ void CL_QTVPlay_f (void) } msglen += strlen(msg+msglen); - if (qtvcl_eztvextensions.ival) - { - raw = 0; - - Q_snprintfz(msg+msglen, sizeof(msg)-msglen, - "QTV_EZQUAKE_EXT: 3\n" - "USERINFO: %s\n", cls.userinfo[0]); - msglen += strlen(msg+msglen); - } - else if (raw) + if (raw) { Q_snprintfz(msg+msglen, sizeof(msg)-msglen, "RAW: 1\n"); msglen += strlen(msg+msglen); } - if (host) + else if (host) { + if (qtvcl_eztvextensions.ival) + { + Q_snprintfz(msg+msglen, sizeof(msg)-msglen, + "QTV_EZQUAKE_EXT: 3\n" + "USERINFO: %s\n", cls.userinfo[0]); + msglen += strlen(msg+msglen); + } + Q_snprintfz(msg+msglen, sizeof(msg)-msglen, "SOURCE: %s\n", host); msglen += strlen(msg+msglen); diff --git a/engine/client/cl_ents.c b/engine/client/cl_ents.c index b0f7ec1c..e9759b68 100644 --- a/engine/client/cl_ents.c +++ b/engine/client/cl_ents.c @@ -777,6 +777,8 @@ void CLFTE_ReadDelta(unsigned int entnum, entity_state_t *news, entity_state_t * { news->tagentity = MSGCL_ReadEntity(); news->tagindex = MSG_ReadByte(); + if (news->tagindex == 0xff) + news->tagindex = ~0; } if (bits & UF_LIGHT) { @@ -3916,25 +3918,46 @@ void CL_LinkPacketEntities (void) // if set to invisible, skip if (state->modelindex<1) - continue; - - if (CL_FilterModelindex(state->modelindex, state->frame)) - continue; - - model = cl.model_precache[state->modelindex]; - if (!model) { - Con_DPrintf("Bad modelindex (%i)\n", state->modelindex); - continue; - } - - //DP extension. .modelflags (which is sent in the high parts of effects) allows to specify exactly the q1-compatible flags. - //the extra bit allows for setting to 0. - //note that hexen2 has additional flags which cannot be expressed. - if (state->effects & 0xff800000) + if (state->tagindex == 0xffff) + { + if (state->tagentity) + { + ent->rtype = RT_PORTALCAMERA; + ent->keynum = state->tagentity; + } + else + { + ent->rtype = RT_PORTALSURFACE; + VectorCopy(ent->origin, ent->oldorigin); + } + } + else + continue; + model = NULL; + modelflags = state->effects>>24; + } else - modelflags = model->flags; + { + if (CL_FilterModelindex(state->modelindex, state->frame)) + continue; + + model = cl.model_precache[state->modelindex]; + if (!model) + { + Con_DPrintf("Bad modelindex (%i)\n", state->modelindex); + continue; + } + + //DP extension. .modelflags (which is sent in the high parts of effects) allows to specify exactly the q1-compatible flags. + //the extra bit allows for setting to 0. + //note that hexen2 has additional flags which cannot be expressed. + if (state->effects & 0xff800000) + modelflags = state->effects>>24; + else + modelflags = model->flags; + } if (cl.model_precache_vwep[0] && state->modelindex2 < MAX_VWEP_MODELS) { @@ -4109,7 +4132,20 @@ void CL_LinkPacketEntities (void) ent->keynum += MAX_EDICTS; } - if (state->tagentity) + if (state->tagindex == 0xffff) + { + if (state->tagentity) + { + ent->rtype = RT_PORTALCAMERA; + ent->keynum = state->tagentity; + } + else + { + ent->rtype = RT_PORTALSURFACE; + VectorCopy(ent->origin, ent->oldorigin); + } + } + else if (state->tagentity) { //ent is attached to a tag, rotate this ent accordingly. CL_RotateAroundTag(ent, state->number, state->tagentity, state->tagindex); } @@ -4142,8 +4178,16 @@ void CL_LinkPacketEntities (void) CL_AddVWeapModel (ent, model2); //figure out which trail this entity is using - trailef = model->particletrail; - trailidx = model->traildefaultindex; + if (model) + { + trailef = model->particletrail; + trailidx = model->traildefaultindex; + } + else + { + trailef = P_INVALID; + trailidx = P_INVALID; + } if (state->effects & EF_HASPARTICLETRAIL) P_DefaultTrail (state->effects, modelflags, &trailef, &trailidx); if (state->u.q1.traileffectnum) @@ -4151,7 +4195,7 @@ void CL_LinkPacketEntities (void) if (state->u.q1.emiteffectnum) P_EmitEffect (ent->origin, ent->axis, MDLF_EMITFORWARDS, CL_TranslateParticleFromServer(state->u.q1.emiteffectnum), &(le->emitstate)); - else if (model->particleeffect != P_INVALID && cls.allow_anyparticles && gl_part_flame.ival) + else if (model && model->particleeffect != P_INVALID && cls.allow_anyparticles && gl_part_flame.ival) P_EmitEffect (ent->origin, ent->axis, model->engineflags, model->particleeffect, &(le->emitstate)); // add automatic particle trails diff --git a/engine/client/cl_input.c b/engine/client/cl_input.c index 35a70b19..11cf59b0 100644 --- a/engine/client/cl_input.c +++ b/engine/client/cl_input.c @@ -168,7 +168,7 @@ void KeyDown (kbutton_t *b) c = Cmd_Argv(1); if (c[0]) - k = atoi(c)&255; + k = atoi(c); else k = -1; // typed manually at the console for continuous down @@ -199,7 +199,7 @@ void KeyUp (kbutton_t *b) c = Cmd_Argv(1); if (c[0]) - k = atoi(c)&255; + k = atoi(c); else { // typed manually at the console, assume for unsticking, so clear all b->down[pnum][0] = b->down[pnum][1] = 0; @@ -1430,7 +1430,7 @@ void CL_UpdateSeats(void) else #endif ver = va("%s v%i.%02i", DISTRIBUTION, FTE_VER_MAJOR, FTE_VER_MINOR); - Info_SetValueForKey(newinfo, "*ver", ver, sizeof(newinfo)); + Info_SetValueForStarKey(newinfo, "*ver", ver, sizeof(newinfo)); CL_SendClientCommand(true, "addseat %i %s", cl.splitclients, COM_QuotedString(newinfo, buffer, sizeof(buffer), false)); } diff --git a/engine/client/cl_main.c b/engine/client/cl_main.c index 5604e869..99b4ed52 100644 --- a/engine/client/cl_main.c +++ b/engine/client/cl_main.c @@ -1039,7 +1039,7 @@ void CL_CheckForResend (void) Con_TPrintf ("Connecting to %s...\n", cls.servername); if (connectinfo.tries == 0) - if (!NET_EnsureRoute(cls.sockets, "conn", cls.servername, false)) + if (!NET_EnsureRoute(cls.sockets, "conn", cls.servername)) { Con_Printf ("Unable to establish connection to %s\n", cls.servername); connectinfo.trying = false; @@ -1773,7 +1773,7 @@ void CL_Disconnect (void) #ifdef TCPCONNECT //disconnects it, without disconnecting the others. - FTENET_AddToCollection(cls.sockets, "conn", NULL, NA_INVALID, NP_DGRAM, false); + FTENET_AddToCollection(cls.sockets, "conn", NULL, NA_INVALID, NP_DGRAM); #endif Cvar_ForceSet(&cl_servername, "none"); @@ -3165,10 +3165,17 @@ void CL_ConnectionlessPacket (void) if (!NET_CompareAdr(&connectinfo.adr, &net_from)) return; - connectinfo.dtlsupgrade = DTLS_ACTIVE; - connectinfo.adr.prot = NP_DTLS; - if (!NET_DTLS_Create(cls.sockets, &net_from)) + if (NET_DTLS_Create(cls.sockets, &net_from)) + { + connectinfo.dtlsupgrade = DTLS_ACTIVE; + connectinfo.adr.prot = NP_DTLS; + } + else + { + if (connectinfo.dtlsupgrade == DTLS_TRY) + connectinfo.dtlsupgrade = DTLS_DISABLE; Con_Printf ("unable to establish dtls route\n"); + } #else Con_Printf ("dtlsopened (unsupported)\n"); #endif diff --git a/engine/client/cl_parse.c b/engine/client/cl_parse.c index 8070fa65..14343e9b 100644 --- a/engine/client/cl_parse.c +++ b/engine/client/cl_parse.c @@ -1327,6 +1327,9 @@ static int CL_LoadModels(int stage, qboolean dontactuallyload) // return stage; // Host_EndGame("Worldmodel wasn't loaded\n"); } + //the worldmodel can take a while to load, so be sure to wait. + if (cl.worldmodel && cl.worldmodel->loadstate == MLS_LOADING) + return -1; SCR_SetLoadingFile("csprogs world"); @@ -1672,7 +1675,7 @@ void CL_RequestNextDownload (void) { if (CL_RemoveClientCommands("qtvspawn")) Con_DPrintf("Multiple prespawns\n"); - CL_SendClientCommand(true, "qtvspawn %i 0 %i", cl.servercount, COM_RemapMapChecksum(LittleLong(cl.worldmodel->checksum2))); + CL_SendClientCommand(true, "qtvspawn %i 0 %i", cl.servercount, COM_RemapMapChecksum(cl.worldmodel, LittleLong(cl.worldmodel->checksum2))); SCR_SetLoadingStage(LS_NONE); } else @@ -1685,7 +1688,7 @@ void CL_RequestNextDownload (void) else { // CL_SendClientCommand("prespawn %i 0 %i", cl.servercount, cl.worldmodel->checksum2); - CL_SendClientCommand(true, prespawn_name, cl.servercount, COM_RemapMapChecksum(LittleLong(cl.worldmodel->checksum2))); + CL_SendClientCommand(true, prespawn_name, cl.servercount, COM_RemapMapChecksum(cl.worldmodel, LittleLong(cl.worldmodel->checksum2))); } } } diff --git a/engine/client/cl_ui.c b/engine/client/cl_ui.c index 8409ec44..0662d4ac 100644 --- a/engine/client/cl_ui.c +++ b/engine/client/cl_ui.c @@ -976,8 +976,9 @@ static qintptr_t UI_SystemCalls(void *offset, quintptr_t mask, qintptr_t fn, con case UI_KEY_ISDOWN: { - extern qboolean keydown[256]; - if (keydown[VM_LONG(arg[0])]) + extern qboolean keydown[K_MAX]; + unsigned int k = VM_LONG(arg[0]); + if (k < K_MAX && keydown[k]) VM_LONG(ret) = 1; else VM_LONG(ret) = 0; @@ -1528,8 +1529,8 @@ int UI_MenuState(void) qboolean UI_KeyPress(int key, int unicode, qboolean down) { - extern qboolean keydown[256]; - extern int keyshift[256]; // key to map to if shift held down in console + extern qboolean keydown[K_MAX]; + extern int keyshift[K_MAX]; // key to map to if shift held down in console // qboolean result; if (!uivm) return false; diff --git a/engine/client/clq2_ents.c b/engine/client/clq2_ents.c index 9ca2cba7..b712f364 100644 --- a/engine/client/clq2_ents.c +++ b/engine/client/clq2_ents.c @@ -2151,7 +2151,7 @@ static void CLQ2_AddViewWeapon (int seat, q2player_state_t *ps, q2player_state_t if (!r_drawviewmodel.value) return; - if (!Cam_DrawViewModel(0)) + if (!Cam_DrawViewModel(pv)) return; // don't draw gun if in wide angle view diff --git a/engine/client/in_win.c b/engine/client/in_win.c index bf96ec4b..bc2c687a 100644 --- a/engine/client/in_win.c +++ b/engine/client/in_win.c @@ -2153,7 +2153,7 @@ void INS_EnumerateDevices(void *ctx, void(*callback)(void *ctx, const char *type } } -static qbyte scantokey[] = +static unsigned short scantokey[] = { // 0 1 2 3 4 5 6 7 // 8 9 A B C D E F @@ -2263,7 +2263,7 @@ void INS_TranslateKeyEvent(WPARAM wParam, LPARAM lParam, qboolean down, int qdev int qcode; int unicode; int chars; - extern int keyshift[256]; + extern int keyshift[K_MAX]; extern int shift_down; qcode = MapKey(lParam); @@ -2316,4 +2316,92 @@ void INS_TranslateKeyEvent(WPARAM wParam, LPARAM lParam, qboolean down, int qdev } IN_KeyEvent(qdeviceid, down, qcode, unicode); } + + +#ifndef APPCOMMAND_BROWSER_BACKWARD //added in win2k (but was probably used before that too) +#define APPCOMMAND_BROWSER_BACKWARD 1 +#define APPCOMMAND_BROWSER_FORWARD 2 +#define APPCOMMAND_BROWSER_REFRESH 3 +#define APPCOMMAND_BROWSER_STOP 4 +#define APPCOMMAND_BROWSER_SEARCH 5 +#define APPCOMMAND_BROWSER_FAVORITES 6 +#define APPCOMMAND_BROWSER_HOME 7 +#define APPCOMMAND_VOLUME_MUTE 8 +#define APPCOMMAND_VOLUME_DOWN 9 +#define APPCOMMAND_VOLUME_UP 10 +#define APPCOMMAND_MEDIA_NEXTTRACK 11 +#define APPCOMMAND_MEDIA_PREVIOUSTRACK 12 +#define APPCOMMAND_MEDIA_STOP 13 +#define APPCOMMAND_MEDIA_PLAY_PAUSE 14 +#define APPCOMMAND_LAUNCH_MAIL 15 +#define APPCOMMAND_LAUNCH_MEDIA_SELECT 16 +#define APPCOMMAND_LAUNCH_APP1 17 +#define APPCOMMAND_LAUNCH_APP2 18 +#define APPCOMMAND_BASS_DOWN 19 +#define APPCOMMAND_BASS_BOOST 20 +#define APPCOMMAND_BASS_UP 21 +#define APPCOMMAND_TREBLE_DOWN 22 +#define APPCOMMAND_TREBLE_UP 23 +#endif +#ifndef APPCOMMAND_MICROPHONE_VOLUME_MUTE //added in winxp +#define APPCOMMAND_MICROPHONE_VOLUME_MUTE 24 +#define APPCOMMAND_MICROPHONE_VOLUME_DOWN 25 +#define APPCOMMAND_MICROPHONE_VOLUME_UP 26 +#define APPCOMMAND_HELP 27 +#define APPCOMMAND_FIND 28 +#define APPCOMMAND_NEW 29 +#define APPCOMMAND_OPEN 30 +#define APPCOMMAND_CLOSE 31 +#define APPCOMMAND_SAVE 32 +#define APPCOMMAND_PRINT 33 +#define APPCOMMAND_UNDO 34 +#define APPCOMMAND_REDO 35 +#define APPCOMMAND_COPY 36 +#define APPCOMMAND_CUT 37 +#define APPCOMMAND_PASTE 38 +#define APPCOMMAND_REPLY_TO_MAIL 39 +#define APPCOMMAND_FORWARD_MAIL 40 +#define APPCOMMAND_SEND_MAIL 41 +#define APPCOMMAND_SPELL_CHECK 42 +#define APPCOMMAND_DICTATE_OR_COMMAND_CONTROL_TOGGLE 43 +#define APPCOMMAND_MIC_ON_OFF_TOGGLE 44 +#define APPCOMMAND_CORRECTION_LIST 45 +#define APPCOMMAND_MEDIA_PLAY 46 +#define APPCOMMAND_MEDIA_PAUSE 47 +#define APPCOMMAND_MEDIA_RECORD 48 +#define APPCOMMAND_MEDIA_FAST_FORWARD 49 +#define APPCOMMAND_MEDIA_REWIND 50 +#define APPCOMMAND_MEDIA_CHANNEL_UP 51 +#define APPCOMMAND_MEDIA_CHANNEL_DOWN 52 +#endif + +int INS_AppCommand(LPARAM lParam) +{ + int qkey = 0; + switch(HIWORD(lParam)&0xfff) + { + case APPCOMMAND_BROWSER_BACKWARD: qkey = K_MM_BACK; break; + case APPCOMMAND_BROWSER_FAVORITES: qkey = K_MM_FAVORITES; break; + case APPCOMMAND_BROWSER_FORWARD: qkey = K_MM_FORWARD; break; + case APPCOMMAND_BROWSER_HOME: qkey = K_MM_HOME; break; + case APPCOMMAND_BROWSER_REFRESH: qkey = K_MM_REFRESH; break; + case APPCOMMAND_BROWSER_SEARCH: qkey = K_SEARCH; break; + case APPCOMMAND_BROWSER_STOP: qkey = K_MM_STOP; break; +// case APPCOMMAND_VOLUME_MUTE: qkey = K_MM_MUTE; break; + case APPCOMMAND_VOLUME_UP: qkey = K_VOLUP; break; + case APPCOMMAND_VOLUME_DOWN: qkey = K_VOLDOWN; break; + +// I want to use these, but that would fuck up external music players. +// case APPCOMMAND_MEDIA_NEXTTRACK: +// case APPCOMMAND_MEDIA_PREVIOUSTRACK: +// case APPCOMMAND_MEDIA_STOP: +// case APPCOMMAND_MEDIA_PLAY_PAUSE: + default: + return false; + } + IN_KeyEvent(0, true, qkey, 0); + IN_KeyEvent(0, false, qkey, 0); + return true; + return false; +} #endif diff --git a/engine/client/keys.c b/engine/client/keys.c index 63a7a2ff..7b76b134 100644 --- a/engine/client/keys.c +++ b/engine/client/keys.c @@ -837,13 +837,13 @@ void Key_DefaultLinkClicked(console_t *con, char *text, char *info) c = Info_ValueForKey(info, "connect"); if (*c && !strchr(c, ';') && !strchr(c, '\n')) { - Cbuf_AddText(va("\nconnect %s\n", c), RESTRICT_LOCAL); + Cbuf_AddText(va("\nconnect \"%s\"\n", c), RESTRICT_LOCAL); return; } c = Info_ValueForKey(info, "join"); if (*c && !strchr(c, ';') && !strchr(c, '\n')) { - Cbuf_AddText(va("\njoin %s\n", c), RESTRICT_LOCAL); + Cbuf_AddText(va("\njoin \"%s\"\n", c), RESTRICT_LOCAL); return; } /*c = Info_ValueForKey(info, "url"); @@ -855,19 +855,19 @@ void Key_DefaultLinkClicked(console_t *con, char *text, char *info) c = Info_ValueForKey(info, "observe"); if (*c && !strchr(c, ';') && !strchr(c, '\n')) { - Cbuf_AddText(va("\nobserve %s\n", c), RESTRICT_LOCAL); + Cbuf_AddText(va("\nobserve \"%s\"\n", c), RESTRICT_LOCAL); return; } c = Info_ValueForKey(info, "qtv"); if (*c && !strchr(c, ';') && !strchr(c, '\n')) { - Cbuf_AddText(va("\nqtvplay %s\n", c), RESTRICT_LOCAL); + Cbuf_AddText(va("\nqtvplay \"%s\"\n", c), RESTRICT_LOCAL); return; } c = Info_ValueForKey(info, "demo"); if (*c && !strchr(c, ';') && !strchr(c, '\n')) { - Cbuf_AddText(va("\nplaydemo %s\n", c), RESTRICT_LOCAL); + Cbuf_AddText(va("\nplaydemo \"%s\"\n", c), RESTRICT_LOCAL); return; } c = Info_ValueForKey(info, "map"); diff --git a/engine/client/keys.h b/engine/client/keys.h index cb90104c..a5f84643 100644 --- a/engine/client/keys.h +++ b/engine/client/keys.h @@ -205,6 +205,7 @@ K_AUX29 = 235, K_AUX30 = 236, K_AUX31 = 237, K_AUX32 = 238, + K_LWIN = 239, K_RWIN = 240, K_APP = 241, @@ -227,7 +228,14 @@ K_GP_DPAD_RIGHT = 254, K_GP_UNKNOWN = 255, #endif -K_MAX = 256 +K_MM_BACK, +K_MM_FAVORITES, +K_MM_FORWARD, +K_MM_HOME, +K_MM_REFRESH, +K_MM_STOP, + +K_MAX }; #define KEY_MODIFIER_SHIFT (1<<0) @@ -260,7 +268,7 @@ typedef enum //highest has priority extern unsigned int key_dest_absolutemouse; //if the active key dest bit is set, the mouse is absolute. extern unsigned int key_dest_mask; -extern char *keybindings[K_MAX][16]; +extern char *keybindings[K_MAX][KEY_MODIFIERSTATES]; extern int key_repeats[K_MAX]; extern int key_count; // incremented every key event extern int key_lastpress; diff --git a/engine/client/m_mp3.c b/engine/client/m_mp3.c index 25d44eeb..44ce997b 100644 --- a/engine/client/m_mp3.c +++ b/engine/client/m_mp3.c @@ -4749,7 +4749,7 @@ void STT_Init_f(void) if (SUCCEEDED(CoCreateInstance(&CLSID_SpSharedRecoContext, NULL, CLSCTX_SERVER, &IID_SpRecoContext, (void*)&stt_recctx))) { ULONGLONG ev = (((ULONGLONG)1) << 38) | (((ULONGLONG)1) << 30) | (((ULONGLONG)1) << 33); - if (SUCCEEDED(stt_recctx->lpVtbl->SetNotifyWindowMessage(stt_recctx, mainwindow, WM_USER, 0, 0))) + if (SUCCEEDED(stt_recctx->lpVtbl->SetNotifyWindowMessage(stt_recctx, mainwindow, WM_USER_SPEECHTOTEXT, 0, 0))) if (SUCCEEDED(stt_recctx->lpVtbl->SetInterest(stt_recctx, ev, ev))) if (SUCCEEDED(stt_recctx->lpVtbl->CreateGrammar(stt_recctx, 0, &stt_gram))) { diff --git a/engine/client/m_options.c b/engine/client/m_options.c index 38acc2a5..7f8e66c6 100644 --- a/engine/client/m_options.c +++ b/engine/client/m_options.c @@ -532,16 +532,20 @@ void M_Menu_Audio_f (void) "Speex (Narrow)", "Speex (Wide)", // "Speex (UltraWide)", +// "PCM A-Law", +// "PCM U-Law", NULL }; static const char *voipcodecvalue[] = { "", - "0", -// "1", - "2", - "3", - "4", -// "5", + "0", //speex non-standard +// "1", //pcm16 sucks + "2", //opus + "3", //speex narrow + "4", //speex wide +// "5", //speex UW +// "6", //pcma +// "7", //pcmu NULL }; diff --git a/engine/client/net_master.c b/engine/client/net_master.c index 7b411ea4..3a380d3d 100644 --- a/engine/client/net_master.c +++ b/engine/client/net_master.c @@ -310,7 +310,7 @@ void SV_Master_Worker_Resolved(void *ctx, void *data, size_t a, size_t b) { //tcp masters require a route if (NET_AddrIsReliable(na)) - NET_EnsureRoute(svs.sockets, master->cv.name, master->cv.string, false); + NET_EnsureRoute(svs.sockets, master->cv.name, master->cv.string); //q2+qw masters are given a ping to verify that they're still up switch (master->protocol) diff --git a/engine/client/pr_csqc.c b/engine/client/pr_csqc.c index accddbe7..a6ccf3cc 100644 --- a/engine/client/pr_csqc.c +++ b/engine/client/pr_csqc.c @@ -3281,8 +3281,12 @@ static void QCBUILTIN PF_cs_getentitytoken (pubprogfuncs_t *prinst, struct globa if (prinst->callargc) { const char *s = PR_GetStringOfs(prinst, OFS_PARM0); - if (*s == 0) + if (*s == 0 && cl.worldmodel) + { + if (cl.worldmodel->loadstate == MLS_LOADING) + COM_WorkerPartialSync(cl.worldmodel, &cl.worldmodel->loadstate, MLS_LOADING); s = Mod_GetEntitiesString(cl.worldmodel); + } csqcmapentitydata = s; G_INT(OFS_RETURN) = 0; return; diff --git a/engine/client/quakedef.h b/engine/client/quakedef.h index 7bc2f684..9a393082 100644 --- a/engine/client/quakedef.h +++ b/engine/client/quakedef.h @@ -139,6 +139,17 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #endif #endif #include + +#ifdef USE_MSVCRT_DEBUG +#define _CRTDBG_MAP_ALLOC +#include +#endif +#if defined(_WIN32) || defined(__DJGPP__) +#include +#else +#include +#endif + #ifdef __cplusplus extern "C" { #endif @@ -192,11 +203,6 @@ extern "C" { #define min(a,b) ((a) < (b) ? (a) : (b)) #endif -#ifdef USE_MSVCRT_DEBUG -#define _CRTDBG_MAP_ALLOC -#include -#endif - //msvcrt lacks any and all c99 support. #if defined(_WIN32) #ifdef __GNUC__ diff --git a/engine/client/r_d3.c b/engine/client/r_d3.c index 85775a5d..5e3b21f4 100644 --- a/engine/client/r_d3.c +++ b/engine/client/r_d3.c @@ -597,10 +597,10 @@ unsigned char *D3_CalcVis(model_t *mod, vec3_t org) static void D3_FindTouchedLeafs (struct model_s *model, struct pvscache_s *ent, vec3_t cullmins, vec3_t cullmaxs) { } -static qbyte *D3_ClusterPVS (struct model_s *model, int num, qbyte *buffer, unsigned int buffersize) +static qbyte *D3_ClusterPVS (struct model_s *model, int num, pvsbuffer_t *buffer, pvsmerge_t merge) { - memset(buffer, 0xff, buffersize); - return buffer; + memset(buffer->buffer, 0xff, buffer->buffersize); + return buffer->buffer; } static int D3_ClusterForPoint (struct model_s *model, vec3_t point) { @@ -618,7 +618,7 @@ static int D3_ClusterForPoint (struct model_s *model, vec3_t point) } return 0; } -static unsigned int D3_FatPVS (struct model_s *model, vec3_t org, qbyte *pvsbuffer, unsigned int buffersize, qboolean merge) +static unsigned int D3_FatPVS (struct model_s *model, vec3_t org, pvsbuffer_t *pvsbuffer, qboolean merge) { return 0; } diff --git a/engine/client/r_surf.c b/engine/client/r_surf.c index 19a582f7..0ae3de24 100644 --- a/engine/client/r_surf.c +++ b/engine/client/r_surf.c @@ -2614,7 +2614,7 @@ struct webostate_s model_t *wmodel; mleaf_t *leaf[2]; int cluster[2]; - qbyte pvs[MAX_MAP_LEAFS/8]; + pvsbuffer_t pvs; vboarray_t ebo; void *ebomem; size_t idxcount; @@ -2857,20 +2857,13 @@ void R_GenWorldEBO(void *ctx, void *data, size_t a, size_t b) #if defined(Q2BSPS) || defined(Q3BSPS) if (es->wmodel->fromgame == fg_quake2 || es->wmodel->fromgame == fg_quake3) { - if (es->cluster[1] != -1 && es->cluster[0] != es->cluster[1]) - { //view is near to a water boundary. this implies the water crosses the near clip plane. - qbyte tmppvs[MAX_MAP_LEAFS/8], *pvs2; - int c; - pvs = es->wmodel->funcs.ClusterPVS(es->wmodel, es->cluster[0], es->pvs, sizeof(es->pvs)); - pvs2 = es->wmodel->funcs.ClusterPVS(es->wmodel, es->cluster[1], tmppvs, sizeof(tmppvs)); - c = (es->wmodel->numclusters+31)/32; - for (i=0 ; ipvs)[i] = ((int *)pvs)[i] | ((int *)pvs2)[i]; - pvs = es->pvs; + if (es->cluster[1] != -1 && es->cluster[0] != es->cluster[1]) //view is near to a water boundary. this implies the water crosses the near clip plane. + { + pvs = es->wmodel->funcs.ClusterPVS(es->wmodel, es->cluster[0], &es->pvs, PVM_REPLACE); + pvs = es->wmodel->funcs.ClusterPVS(es->wmodel, es->cluster[1], &es->pvs, PVM_MERGE); } else - pvs = es->wmodel->funcs.ClusterPVS(es->wmodel, es->cluster[0], es->pvs, sizeof(es->pvs)); - + pvs = es->wmodel->funcs.ClusterPVS(es->wmodel, es->cluster[0], &es->pvs, PVM_FAST); Surf_SimpleWorld_Q3BSP(es, pvs); } else @@ -2879,21 +2872,10 @@ void R_GenWorldEBO(void *ctx, void *data, size_t a, size_t b) if (es->wmodel->fromgame == fg_quake || es->wmodel->fromgame == fg_halflife) { //maybe we should just use fatpvs instead, and wait for completion when outside? - if (es->leaf[1]) - { //view is near to a water boundary. this implies the water crosses the near clip plane. - qbyte tmppvs[MAX_MAP_LEAFS/8]; - int c; - Q1BSP_LeafPVS (es->wmodel, es->leaf[0], es->pvs, sizeof(es->pvs)); - Q1BSP_LeafPVS (es->wmodel, es->leaf[1], tmppvs, sizeof(tmppvs)); - c = (es->wmodel->numclusters+31)/32; - for (i=0 ; ipvs)[i] |= ((int *)tmppvs)[i]; - pvs = es->pvs; - } - else - { - pvs = Q1BSP_LeafPVS (es->wmodel, es->leaf[0], es->pvs, sizeof(es->pvs)); - } + pvs = Q1BSP_LeafPVS (es->wmodel, es->leaf[0], &es->pvs, false); + if (es->leaf[1]) //view is near to a water boundary. this implies the water crosses the near clip plane. + pvs = Q1BSP_LeafPVS (es->wmodel, es->leaf[1], &es->pvs, true); + Surf_SimpleWorld_Q1BSP(es, pvs); } else @@ -2916,7 +2898,7 @@ void Surf_DrawWorld (void) { //surfvis vs entvis - the key difference is that surfvis is surfaces while entvis is volume. though surfvis should be frustum culled also for lighting. entvis doesn't care. qbyte *surfvis, *entvis; - qbyte frustumvis_[MAX_MAP_LEAFS/8]; + static pvsbuffer_t frustumvis_; RSpeedLocals(); if (r_refdef.flags & RDF_NOWORLDMODEL) @@ -2982,10 +2964,12 @@ void Surf_DrawWorld (void) } } webogeneratingstate = true; - webogenerating = BZ_Malloc(sizeof(*webogenerating) + sizeof(webogenerating->batches[0]) * (currentmodel->numbatches-1)); + webogenerating = BZ_Malloc(sizeof(*webogenerating) + sizeof(webogenerating->batches[0]) * (currentmodel->numbatches-1) + currentmodel->pvsbytes); webogenerating->wmodel = currentmodel; webogenerating->leaf[0] = r_viewleaf; webogenerating->leaf[1] = r_viewleaf2; + webogenerating->pvs.buffer = (qbyte*)(webogenerating+1) + sizeof(webogenerating->batches[0])*(currentmodel->numbatches-1); + webogenerating->pvs.buffersize = currentmodel->pvsbytes; for (i = 0; i < MAX_LIGHTSTYLES; i++) webogenerating->lightstylevalues[i] = d_lightstylevalue[i]; Q_strncpyz(webogenerating->dbgid, "webostate", sizeof(webogenerating->dbgid)); @@ -3017,10 +3001,12 @@ void Surf_DrawWorld (void) } } webogeneratingstate = true; - webogenerating = BZ_Malloc(sizeof(*webogenerating) + sizeof(webogenerating->batches[0]) * (currentmodel->numbatches-1)); + webogenerating = BZ_Malloc(sizeof(*webogenerating) + sizeof(webogenerating->batches[0]) * (currentmodel->numbatches-1) + currentmodel->pvsbytes); webogenerating->wmodel = currentmodel; webogenerating->cluster[0] = r_viewcluster; webogenerating->cluster[1] = r_viewcluster2; + webogenerating->pvs.buffer = (qbyte*)(webogenerating+1) + sizeof(webogenerating->batches[0])*(currentmodel->numbatches-1); + webogenerating->pvs.buffersize = currentmodel->pvsbytes; Q_strncpyz(webogenerating->dbgid, "webostate", sizeof(webogenerating->dbgid)); COM_AddWork(WG_LOADER, R_GenWorldEBO, webogenerating, NULL, 0, 0); } @@ -3030,7 +3016,7 @@ void Surf_DrawWorld (void) if (webostate) { - entvis = surfvis = webostate->pvs; + entvis = surfvis = webostate->pvs.buffer; RSpeedEnd(RSPEED_WORLDNODE); @@ -3065,8 +3051,10 @@ void Surf_DrawWorld (void) #if defined(Q2BSPS) || defined(Q3BSPS) if (currentmodel->fromgame == fg_quake2 || currentmodel->fromgame == fg_quake3) { - frustumvis = frustumvis_; - memset(frustumvis, 0, (currentmodel->numclusters + 7)>>3); + if (frustumvis_.buffersize < currentmodel->pvsbytes) + frustumvis_.buffer = BZ_Realloc(frustumvis_.buffer, frustumvis_.buffersize=currentmodel->pvsbytes); + frustumvis = frustumvis_.buffer; + memset(frustumvis, 0, currentmodel->pvsbytes); if (!r_refdef.areabitsknown) { //generate the info each frame, as the gamecode didn't tell us what to use. @@ -3128,8 +3116,10 @@ void Surf_DrawWorld (void) if (!(r_novis.ival & 2)) VectorCopy (r_origin, modelorg); - frustumvis = frustumvis_; - memset(frustumvis, 0, (currentmodel->numclusters + 7)>>3); + if (frustumvis_.buffersize < currentmodel->pvsbytes) + frustumvis_.buffer = BZ_Realloc(frustumvis_.buffer, frustumvis_.buffersize=currentmodel->pvsbytes); + frustumvis = frustumvis_.buffer; + memset(frustumvis, 0, currentmodel->pvsbytes); if (r_refdef.useperspective) Surf_RecursiveWorldNode (currentmodel->nodes, 0x1f); diff --git a/engine/client/render.h b/engine/client/render.h index 0158cea5..3f90352f 100644 --- a/engine/client/render.h +++ b/engine/client/render.h @@ -80,6 +80,10 @@ typedef enum { RT_RAIL_RINGS, RT_LIGHTNING, RT_PORTALSURFACE, // doesn't draw anything, just info for portals + //q3 ones stop here. + + //fte ones start here + RT_PORTALCAMERA, // an alternative to RT_PORTALSURFACE. RT_MAX_REF_ENTITY_TYPE } refEntityType_t; diff --git a/engine/client/renderer.c b/engine/client/renderer.c index b2d54b08..7a3881e8 100644 --- a/engine/client/renderer.c +++ b/engine/client/renderer.c @@ -303,6 +303,7 @@ cvar_t vid_gl_context_debug = CVARD ("vid_gl_context_debug", "0", "Requests cvar_t vid_gl_context_es = CVARD ("vid_gl_context_es", "0", "Requests an OpenGLES context. Be sure to set vid_gl_context_version to 2 or so."); //requires version set correctly, no debug, no compat cvar_t vid_gl_context_robustness = CVARD ("vid_gl_context_robustness", "1", "Attempt to enforce extra buffer protection in the gl driver, but can be slower with pre-gl3 hardware."); cvar_t vid_gl_context_selfreset = CVARD ("vid_gl_context_selfreset", "1", "Upon hardware failure, have the engine create a new context instead of depending on the drivers to restore everything. This can help to avoid graphics drivers randomly killing your game, and can help reduce memory requirements."); +cvar_t vid_gl_context_noerror = CVARD ("vid_gl_context_noerror", "", "Disables OpenGL's error checks for a small performance speedup. May cause segfaults if stuff wasn't properly implemented/tested."); #endif #if 1 @@ -450,6 +451,7 @@ void GLRenderer_Init(void) Cvar_Register (&vid_gl_context_es, GLRENDEREROPTIONS); Cvar_Register (&vid_gl_context_robustness, GLRENDEREROPTIONS); Cvar_Register (&vid_gl_context_selfreset, GLRENDEREROPTIONS); + Cvar_Register (&vid_gl_context_noerror, GLRENDEREROPTIONS); //renderer @@ -1623,6 +1625,8 @@ TRACE(("dbg: R_ApplyRenderer: efrags\n")); void R_ReloadRenderer_f (void) { float time = Sys_DoubleTime(); + if (qrenderer == QR_NONE || qrenderer == QR_HEADLESS) + return; //don't bother reloading the renderer if its not actually rendering anything anyway. R_ShutdownRenderer(false); Con_DPrintf("teardown = %f\n", Sys_DoubleTime() - time); //reloads textures without destroying video context. @@ -2122,7 +2126,7 @@ mleaf_t *r_viewleaf2, *r_oldviewleaf2; int r_viewcluster, r_viewcluster2, r_oldviewcluster, r_oldviewcluster2; int r_visframecount; mleaf_t *r_vischain; // linked list of visible leafs -static FTE_ALIGN(4) qbyte curframevis[R_MAX_RECURSE][MAX_MAP_LEAFS/8]; +static pvsbuffer_t curframevis[R_MAX_RECURSE]; /* =============== @@ -2183,7 +2187,7 @@ qbyte *R_MarkLeaves_Q3 (void) } else { - vis = CM_ClusterPVS (cl.worldmodel, r_viewcluster, curframevis[portal], sizeof(curframevis)); + vis = CM_ClusterPVS (cl.worldmodel, r_viewcluster, &curframevis[portal], PVM_FAST); for (i=0,leaf=cl.worldmodel->leafs ; inumleafs ; i++, leaf++) { cluster = leaf->cluster; @@ -2224,7 +2228,6 @@ qbyte *R_MarkLeaves_Q2 (void) mleaf_t *leaf; qbyte *vis; - int c; int portal = r_refdef.recurse; if (r_refdef.forcevis) @@ -2264,16 +2267,13 @@ qbyte *R_MarkLeaves_Q2 (void) return vis; } - vis = CM_ClusterPVS (cl.worldmodel, r_viewcluster, curframevis[portal], sizeof(curframevis)); - // may have to combine two clusters because of solid water boundaries - if (r_viewcluster2 != r_viewcluster) + if (r_viewcluster2 != r_viewcluster) // may have to combine two clusters because of solid water boundaries { - vis = CM_ClusterPVS (cl.worldmodel, r_viewcluster2, NULL, sizeof(curframevis)); - c = (cl.worldmodel->numclusters+31)/32; - for (i=0 ; inumclusters+7)>>3); + vis = cvis[portal] = curframevis[portal].buffer; + memset (curframevis[portal].buffer, 0xff, curframevis[portal].buffersize); r_oldviewleaf = NULL; r_oldviewleaf2 = NULL; } - else if (r_viewleaf2 && r_viewleaf2 != r_viewleaf) - { - int c; - Q1BSP_LeafPVS (cl.worldmodel, r_viewleaf2, curframevis[portal], sizeof(curframevis[portal])); - vis = cvis[portal] = Q1BSP_LeafPVS (cl.worldmodel, r_viewleaf, NULL, 0); - c = (cl.worldmodel->numclusters+31)/32; - for (i=0 ; i>4; + if (e) + m = (((m)<<1)|0x21) << (e-1); + else + m = (((m)<<1)|1); + if (inv & 0x80) + out[i] = -m; + else + out[i] = m; + } + return i; +} +size_t PCMA_Encode(unsigned char *out, size_t outsize, short *in, size_t samples) +{ + size_t i = 0; + for (i = 0; i < samples; i++) + { + int o = in[i]; + unsigned char b; + if (o < 0) + { + o = -o; + b = 0x80; + } + else + b = 0; + + if (o >= 0x0800) + b |= ((o>>7)&0xf) | 0x70; + else if (o >= 0x0400) + b |= ((o>>6)&0xf) | 0x60; + else if (o >= 0x0200) + b |= ((o>>5)&0xf) | 0x50; + else if (o >= 0x0100) + b |= ((o>>4)&0xf) | 0x40; + else if (o >= 0x0080) + b |= ((o>>3)&0xf) | 0x30; + else if (o >= 0x0040) + b |= ((o>>2)&0xf) | 0x20; + else if (o >= 0x0020) + b |= ((o>>1)&0xf) | 0x10; + else + b |= ((o>>1)&0xf) | 0x00; + out[i] = b^0x55; //invert every-other bit. + } + + return samples; +} +size_t PCMU_Decode(short *out, unsigned char *in, size_t samples) +{ + size_t i = 0; + for (i = 0; i < samples; i++) + { + unsigned char inv = in[i]^0xff; + int m = (((inv&0xf)<<1)|0x21) << ((inv&0x70)>>4); + m -= 33; + if (inv & 0x80) + out[i] = -m; + else + out[i] = m; + } + return i; +} +size_t PCMU_Encode(unsigned char *out, size_t outsize, short *in, size_t samples) +{ + size_t i = 0; + for (i = 0; i < samples; i++) + { + int o = in[i]; + unsigned char b; + if (o < 0) + { + o = ~o; + b = 0x80; + } + else + b = 0; + o+=33; + + if (o >= 0x1000) + b |= ((o>>8)&0xf) | 0x70; + else if (o >= 0x0800) + b |= ((o>>7)&0xf) | 0x60; + else if (o >= 0x0400) + b |= ((o>>6)&0xf) | 0x50; + else if (o >= 0x0200) + b |= ((o>>5)&0xf) | 0x40; + else if (o >= 0x0100) + b |= ((o>>4)&0xf) | 0x30; + else if (o >= 0x0080) + b |= ((o>>3)&0xf) | 0x20; + else if (o >= 0x0040) + b |= ((o>>2)&0xf) | 0x10; + else + b |= ((o>>1)&0xf) | 0x00; + out[i] = b^0xff; + } + + return samples; +} + void S_Voip_Decode(unsigned int sender, unsigned int codec, unsigned int gen, unsigned char seq, unsigned int bytes, unsigned char *data) { unsigned char *start; @@ -577,6 +687,11 @@ void S_Voip_Decode(unsigned int sender, unsigned int codec, unsigned int gen, un case VOIP_RAW16: s_voip.decsamplerate[sender] = 11025; break; + case VOIP_PCMA: + case VOIP_PCMU: + s_voip.decsamplerate[sender] = 8000; + s_voip.decframesize[sender] = 8000/20; + break; case VOIP_SPEEX_OLD: case VOIP_SPEEX_NARROW: case VOIP_SPEEX_WIDE: @@ -732,6 +847,19 @@ void S_Voip_Decode(unsigned int sender, unsigned int codec, unsigned int gen, un bytes -= len; start += len; break; + case VOIP_PCMA: + case VOIP_PCMU: + len = min(bytes, sizeof(decodebuf)-(sizeof(decodebuf[0])*decodesamps)); + if (len > s_voip.decframesize[sender]*2) + len = s_voip.decframesize[sender]*2; + if (codec == VOIP_PCMA) + decodesamps += PCMA_Decode(decodebuf+decodesamps, start, len); + else + decodesamps += PCMU_Decode(decodebuf+decodesamps, start, len); + s_voip.decseq[sender]++; + bytes -= len; + start += len; + break; case VOIP_OPUS: len = bytes; if (decodesamps > 0) @@ -765,32 +893,46 @@ void S_Voip_Decode(unsigned int sender, unsigned int codec, unsigned int gen, un } #ifdef SUPPORT_ICE +static int S_Voip_NameToId(const char *codec) +{ + if (!Q_strcasecmp(codec, "speex@8000")) + return VOIP_SPEEX_NARROW; + else if (!Q_strcasecmp(codec, "speex@11025")) + return VOIP_SPEEX_OLD; + else if (!Q_strcasecmp(codec, "speex@16000")) + return VOIP_SPEEX_WIDE; + else if (!Q_strcasecmp(codec, "speex@32000")) + return VOIP_SPEEX_ULTRAWIDE; + else if (!Q_strcasecmp(codec, "opus") || !strcmp(codec, "opus@48000")) + return VOIP_OPUS; + else if (!Q_strcasecmp(codec, "pcma@8000")) + return VOIP_PCMA; + else if (!Q_strcasecmp(codec, "pcmu@8000")) + return VOIP_PCMU; + else + return VOIP_INVALID; +} qboolean S_Voip_RTP_CodecOkay(const char *codec) { - if (!strcmp(codec, "speex@8000") || !strcmp(codec, "speex@11025") || !strcmp(codec, "speex@16000") || !strcmp(codec, "speex@32000")) + switch(S_Voip_NameToId(codec)) { - if (S_Speex_Init()) - return true; + case VOIP_SPEEX_NARROW: + case VOIP_SPEEX_OLD: + case VOIP_SPEEX_WIDE: + case VOIP_SPEEX_ULTRAWIDE: + return S_Speex_Init(); + case VOIP_PCMA: + case VOIP_PCMU: + return true; + case VOIP_OPUS: + return S_Opus_Init(); + default: + return false; } - else if (!strcmp(codec, "opus") || !strcmp(codec, "opus@48000")) - { - if (S_Opus_Init()) - return true; - } - return false; } void S_Voip_RTP_Parse(unsigned short sequence, char *codec, unsigned char *data, unsigned int datalen) { - if (!strcmp(codec, "speex@8000")) - S_Voip_Decode(MAX_CLIENTS-1, VOIP_SPEEX_NARROW, 0, sequence&0xff, datalen, data); - if (!strcmp(codec, "speex@11025")) - S_Voip_Decode(MAX_CLIENTS-1, VOIP_SPEEX_OLD, 0, sequence&0xff, datalen, data); //very much non-standard rtp - if (!strcmp(codec, "speex@16000")) - S_Voip_Decode(MAX_CLIENTS-1, VOIP_SPEEX_WIDE, 0, sequence&0xff, datalen, data); - if (!strcmp(codec, "speex@32000")) - S_Voip_Decode(MAX_CLIENTS-1, VOIP_SPEEX_ULTRAWIDE, 0, sequence&0xff, datalen, data); - if (!strcmp(codec, "opus") || !strcmp(codec, "opus@48000")) - S_Voip_Decode(MAX_CLIENTS-1, VOIP_OPUS, 0, sequence&0xff, datalen, data); + S_Voip_Decode(MAX_CLIENTS-1, S_Voip_NameToId(codec), 0, sequence&0xff, datalen, data); } qboolean NET_RTP_Transmit(unsigned int sequence, unsigned int timestamp, const char *codec, char *cdata, int clength); qboolean NET_RTP_Active(void); @@ -1035,6 +1177,11 @@ void S_Voip_Transmit(unsigned char clc, sizebuf_t *buf) qspeex_encoder_ctl(s_voip.encoder, SPEEX_SET_SAMPLING_RATE, &s_voip.encsamplerate); } break; + case VOIP_PCMA: + case VOIP_PCMU: + s_voip.encsamplerate = 8000; + s_voip.encframesize = 8000/20; + break; case VOIP_RAW16: s_voip.encsamplerate = 11025; s_voip.encframesize = 256; @@ -1218,6 +1365,20 @@ void S_Voip_Transmit(unsigned char clc, sizebuf_t *buf) outpos += len; //bytes written to output encpos += len; //number of bytes consumed + s_voip.encsequence++; //increment number of packets, for packetloss detection. + samps+=len / 2; //number of samplepairs eaten in this packet. for stats. + break; + case VOIP_PCMA: + case VOIP_PCMU: + len = s_voip.capturepos-encpos; //amount of data to be eaten in this frame + len = min(len, sizeof(outbuf)-outpos); + len = min(len, s_voip.encframesize*2); + level += S_Voip_Preprocess(start, len/2, micamp); + if (s_voip.enccodec == VOIP_PCMA) + outpos += PCMA_Encode(outbuf+outpos, sizeof(outbuf)-outpos, start, len/2); + else + outpos += PCMU_Encode(outbuf+outpos, sizeof(outbuf)-outpos, start, len/2); + encpos += len; //number of bytes consumed s_voip.encsequence++; //increment number of packets, for packetloss detection. samps+=len / 2; //number of samplepairs eaten in this packet. for stats. break; @@ -1339,8 +1500,14 @@ void S_Voip_Transmit(unsigned char clc, sizebuf_t *buf) case VOIP_SPEEX_OLD: NET_RTP_Transmit(initseq, inittimestamp, va("speex@%i", s_voip.encsamplerate), outbuf, outpos); break; + case VOIP_PCMA: + NET_RTP_Transmit(initseq, inittimestamp, "pcma@8000", outbuf, outpos); + break; + case VOIP_PCMU: + NET_RTP_Transmit(initseq, inittimestamp, "pcmu@8000", outbuf, outpos); + break; case VOIP_OPUS: - NET_RTP_Transmit(initseq, inittimestamp, "opus", outbuf, outpos); + NET_RTP_Transmit(initseq, inittimestamp, "opus@48000", outbuf, outpos); break; } } diff --git a/engine/client/sys_linux.c b/engine/client/sys_linux.c index 996dad91..cb9c6021 100644 --- a/engine/client/sys_linux.c +++ b/engine/client/sys_linux.c @@ -850,9 +850,7 @@ char *Sys_ConsoleInput(void) // if (!qrenderer) { -Con_Printf("ConsoleInput\n"); len = read (0, text, sizeof(text)); -Con_Printf("ConsoleInput read %i\n", len); if (len < 1) return NULL; diff --git a/engine/client/sys_win.c b/engine/client/sys_win.c index 379e44f9..4ea377e0 100644 --- a/engine/client/sys_win.c +++ b/engine/client/sys_win.c @@ -365,6 +365,50 @@ qboolean Sys_RandomBytes(qbyte *string, int len) CryptReleaseContext(prov, 0); return true; } +//returns 0 on failure, otherwise returns the actual digest size and the digest (overallocate if lazy) +size_t HashCalculate(const char *hashtype, const void *data, size_t data_size, void *digest_out, size_t digest_size) +{ + HCRYPTPROV prov; + HCRYPTHASH hash; + ALG_ID alg; + + if (!Q_strcasecmp(hashtype, "MD4")) + alg = CALG_MD4; + else if (!Q_strcasecmp(hashtype, "MD5")) + alg = CALG_MD5; + else if (!Q_strcasecmp(hashtype, "SHA1")) + alg = CALG_SHA1; + else if (!Q_strcasecmp(hashtype, "SHA256")) + alg = CALG_SHA_256; //only on xp sp3+ + else if (!Q_strcasecmp(hashtype, "SHA384")) + alg = CALG_SHA_384; //only on xp sp3+ + else if (!Q_strcasecmp(hashtype, "SHA512")) + alg = CALG_SHA_512; //only on xp sp3+ + else + return 0; + + memset(digest_out, 0, digest_size); + + if(CryptAcquireContext(&prov, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) + { + if (CryptCreateHash(prov, alg, 0, 0, &hash)) + { + if (CryptHashData(hash, data, (DWORD)data_size, 0)) + { + DWORD grr = digest_size; + if (CryptGetHashParam(hash, HP_HASHVAL, digest_out, &grr, 0)) + { + CryptDestroyHash(hash); + CryptReleaseContext(prov, 0); + return grr; + } + } + CryptDestroyHash(hash); + } + CryptReleaseContext(prov, 0); + } + return 0; +} /* ================= diff --git a/engine/client/winquake.h b/engine/client/winquake.h index 4c40f38a..9affd09a 100644 --- a/engine/client/winquake.h +++ b/engine/client/winquake.h @@ -58,8 +58,16 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #ifndef WM_MOUSEWHEEL -#define WM_MOUSEWHEEL 0x020A +#define WM_MOUSEWHEEL 0x020A #endif +#ifndef WM_APPCOMMAND +#define WM_APPCOMMAND 0x0319 +#endif + +#define WM_USER_SPEECHTOTEXT (WM_USER+0) //used by stt +#define WM_USER_VIDSHUTDOWN (WM_USER+4) //used by multithreading +#define WM_USER_VKPRESENT (WM_USER+7) //used by vulkan +#define WM_USER_NVVKPRESENT (WM_USER+8) //used by vulkan-over-opengl #undef byte @@ -127,6 +135,7 @@ void WIN_WindowCreated(HWND window); void INS_UpdateClipCursor (void); void CenterWindow(HWND hWndCenter, int width, int height, BOOL lefttopjustify); void INS_TranslateKeyEvent(WPARAM wParam, LPARAM lParam, qboolean down, int pnum, qboolean genkeystate); +int INS_AppCommand(LPARAM lParam); void S_BlockSound (void); void S_UnblockSound (void); diff --git a/engine/common/bothdefs.h b/engine/common/bothdefs.h index a2263732..67ae7098 100644 --- a/engine/common/bothdefs.h +++ b/engine/common/bothdefs.h @@ -264,7 +264,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #define HUFFNETWORK //huffman network compression #define DOOMWADS //doom wad/sprite support // #define MAP_DOOM //doom map support - #define MAP_PROC //doom3/quake4 map support +// #define MAP_PROC //doom3/quake4 map support //#define WOLF3DSUPPORT //wolfenstein3d map support (not started yet) #define Q1BSPS //quake 1 bsp support, because we're still a quake engine #define Q2BSPS //quake 2 bsp support diff --git a/engine/common/bspfile.h b/engine/common/bspfile.h index b934a2ba..15e25968 100644 --- a/engine/common/bspfile.h +++ b/engine/common/bspfile.h @@ -30,15 +30,18 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. //#define MAX_MAP_ENTITIES 1024 //#define MAX_MAP_ENTSTRING 65536 -#define SANITY_MAX_MAP_PLANES 65536*8 //sanity -#define SANITY_MAX_MAP_NODES 65536 //sanity -#define SANITY_MAX_MAP_CLIPNODES 65536 //sanity -#define MAX_MAP_LEAFS 65536 //pvs buffer size. not sanity. -#define SANITY_MAX_MAP_VERTS 65536 //sanity -#define SANITY_MAX_MAP_FACES 65536 //sanity +//FIXME: make sure that any 16bit indexes are bounded properly +//FIXME: ensure that we don't get any count*size overflows +#define SANITY_MAX_MAP_PLANES 65536*64 //sanity +#define SANITY_MAX_MAP_NODES 65536*64 //sanity +//#define SANITY_MAX_MAP_CLIPNODES 65536*64 //sanity +//#define MAX_MAP_LEAFS 1 //pvs buffer size. not sanity. +#define SANITY_MAX_MAP_LEAFS 65536*64 //too many leafs results in massive amounts of ram used for pvs/phs caches. +//#define SANITY_MAX_MAP_VERTS 65536 //sanity +#define SANITY_MAX_MAP_FACES 65536*64 //sanity //#define MAX_MAP_MARKSURFACES 65536 //sanity //#define MAX_MAP_TEXINFO 4096 //sanity -#define MAX_MAP_EDGES 256000 +//#define MAX_MAP_EDGES 256000 //#define MAX_MAP_SURFEDGES 512000 //#define MAX_MAP_MIPTEX 0x200000 //#define MAX_MAP_LIGHTING 0x100000 diff --git a/engine/common/com_mesh.c b/engine/common/com_mesh.c index 221befc3..4eb0499f 100644 --- a/engine/common/com_mesh.c +++ b/engine/common/com_mesh.c @@ -68,15 +68,6 @@ void Mod_DoCRC(model_t *mod, char *buffer, int buffersize) #endif } - - - -#if defined(_WIN32) || defined(__DJGPP__) -#include -#else -#include -#endif - extern cvar_t gl_part_flame, r_fullbrightSkins, r_fb_models; extern cvar_t r_noaliasshadows; extern cvar_t r_skin_overlays; @@ -1099,26 +1090,26 @@ static int Alias_FindRawSkelData(galiasinfo_t *inf, framestate_t *fstate, skelle for (bonegroup = 0; bonegroup < FS_COUNT; bonegroup++) { endbone = fstate->g[bonegroup].endbone; - if (bonegroup == FS_COUNT-1 || endbone > lastbone) - endbone = lastbone; + if (bonegroup == FS_COUNT-1) + endbone = MAX_BONES; - if (endbone == cbone) - continue; - - if (!inf->numanimations || !Alias_BuildSkelLerps(lerps, &fstate->g[bonegroup], inf->numbones, inf)) //if there's no animations in this model, use the base pose instead. + if (cbone <= firstbone || endbone > lastbone) { - if (!inf->baseframeofs) - continue; //nope, not happening. - lerps->skeltype = SKEL_ABSOLUTE; - lerps->frac[0] = 1; - lerps->pose[0] = inf->baseframeofs; - lerps->lerpcount = 1; + if (!inf->numanimations || !Alias_BuildSkelLerps(lerps, &fstate->g[bonegroup], inf->numbones, inf)) //if there's no animations in this model, use the base pose instead. + { + if (!inf->baseframeofs) + continue; //nope, not happening. + lerps->skeltype = SKEL_ABSOLUTE; + lerps->frac[0] = 1; + lerps->pose[0] = inf->baseframeofs; + lerps->lerpcount = 1; + } + lerps->firstbone = max(cbone, firstbone); + lerps->endbone = min(endbone, lastbone); + numbonegroups++; + lerps++; } - lerps->firstbone = cbone; - lerps->endbone = endbone; cbone = endbone; - numbonegroups++; - lerps++; } return numbonegroups; } diff --git a/engine/common/common.c b/engine/common/common.c index 6fcb4267..baf8079c 100644 --- a/engine/common/common.c +++ b/engine/common/common.c @@ -5725,8 +5725,8 @@ void COM_Effectinfo_Enumerate(int (*cb)(const char *pname)) /*************************************************************************/ -/*remaps map checksums from known non-cheat GPL maps to authentic id1 maps*/ -unsigned int COM_RemapMapChecksum(unsigned int checksum) +/*remaps map checksums from known non-cheat GPL maps to authentic id1 maps.*/ +unsigned int COM_RemapMapChecksum(model_t *model, unsigned int checksum) { #ifndef NOLEGACY static const struct { @@ -5736,56 +5736,58 @@ unsigned int COM_RemapMapChecksum(unsigned int checksum) unsigned int id12; } sums[] = { - {"maps/start.bsp", -603735309, 714749795, 493454459}, + {"maps/start.bsp", 0xDC03BAF3, 0x2A9A3763, 0x1D69847B}, - {"maps/e1m1.bsp", -1213097692, 523840258, -1391994750}, - {"maps/e1m2.bsp", -2134038629, 1561595172, 1729102119}, - {"maps/e1m3.bsp", 526593427, 1008794158, 893792842}, - {"maps/e1m4.bsp", -1218723400, -442162482, -304478603}, - {"maps/e1m5.bsp", 1709090059, 1856217547, -1473504118}, - {"maps/e1m6.bsp", 1014375998, 1304756164, 738207971}, - {"maps/e1m7.bsp", 1375393448, -1396746908, -1747518694}, - {"maps/e1m8.bsp", 1470379688, -163803419, 79095617}, + {"maps/e1m1.bsp", 0xB7B19924, 0x1F392B02, 0xAD07D882}, + {"maps/e1m2.bsp", 0x80CD279B, 0x5D140D24, 0x67100127}, + {"maps/e1m3.bsp", 0x1F632D93, 0x3C20FA2E, 0x3546324A}, + {"maps/e1m4.bsp", 0xB75BC1B8, 0xE5A522CE, 0xEDDA0675}, + {"maps/e1m5.bsp", 0x65DEA50B, 0x6EA3A1CB, 0xA82C1C8A}, + {"maps/e1m6.bsp", 0x3C76263E, 0x4DC4FFC4, 0x2C0028E3}, + {"maps/e1m7.bsp", 0x51FAD6A8, 0xACBF5564, 0x97D6FB1A}, + {"maps/e1m8.bsp", 0x57A436A8, 0xF63C8EE5, 0x04B6E741}, - {"maps/e2m1.bsp", -1725230579, -797758554, -587894734}, - {"maps/e2m2.bsp", -1573837115, -355822557, -1349116595}, - {"maps/e2m3.bsp", 156655662, 1203005272, -57072303}, - {"maps/e2m4.bsp", -1530012474, -1629664024, -1021928503}, - {"maps/e3m5.bsp", -594001393, -1405673977, -1854273999}, - {"maps/e2m6.bsp", 1041933133, 583875451, -1851573375}, - {"maps/e2m7.bsp", -1583122652, 1814005234, 2051006488}, + {"maps/e2m1.bsp", 0x992B120D, 0xD0732BA6, 0xDCF57032}, + {"maps/e2m2.bsp", 0xA23126C5, 0xEACA9423, 0xAF961D4D}, + {"maps/e2m3.bsp", 0x0956602E, 0x47B46758, 0xFC992551}, + {"maps/e2m4.bsp", 0xA4CDDCC6, 0x9EDD4CE8, 0xC3169BC9}, + {"maps/e3m5.bsp", 0xDC98420F, 0xAC371E07, 0x917A0631}, + {"maps/e2m6.bsp", 0x3E1AA34D, 0x22CD3B7B, 0x91A33B81}, + {"maps/e2m7.bsp", 0xA1A37724, 0x6C1F85F2, 0x7A3FE018}, - {"maps/e3m1.bsp", -1118143869, -457270773, -1867379423}, - {"maps/e3m2.bsp", -469484146, 723435606, -1670613704}, - {"maps/e3m3.bsp", -300762423, -540030088, -1009754856}, - {"maps/e3m4.bsp", -214067894, 1107310161, -1317466952}, - {"maps/e3m5.bsp", -594001393, -1405673977, -1854273999}, - {"maps/e3m6.bsp", -1664550468, 1631142730, 767655416}, - {"maps/e3m7.bsp", 781051658, -1513131760, 272220593}, + {"maps/e3m1.bsp", 0xBD5A7A83, 0xE4BE9A0B, 0x90B20D21}, + {"maps/e3m2.bsp", 0xE4043D8E, 0x2B1EC056, 0x9C6C7538}, + {"maps/e3m3.bsp", 0xEE12BAC9, 0xDFCFCB78, 0xC3D05D18}, + {"maps/e3m4.bsp", 0xF33D954A, 0x42003651, 0xB1790CB8}, + {"maps/e3m5.bsp", 0xDC98420F, 0xAC371E07, 0x917A0631}, + {"maps/e3m6.bsp", 0x9CC8F9BC, 0x6139434A, 0x2DC17DF8}, + {"maps/e3m7.bsp", 0x2E8DE70A, 0xA5CF7110, 0x1039C1B1}, - {"maps/e4m1.bsp", 1548541253, 1254243660, -1141873840}, - {"maps/e4m2.bsp", -1400585206, 92253388, -472296}, - {"maps/e4m3.bsp", -1230693918, 1961442781, 1505685644}, - {"maps/e4m4.bsp", 842253404, -374904516, 758847551}, - {"maps/e4m5.bsp", -439098147, 389110272, 1771890676}, - {"maps/e4m6.bsp", 1518024640, 1714857656, 102825880}, - {"maps/e4m7.bsp", -381063035, -585362206, -1645477460}, - {"maps/e4m8.bsp", 844770132, 1063417045, 1018457175}, + {"maps/e4m1.bsp", 0x5C4CDD45, 0x4AC23D4C, 0xBBF06350}, + {"maps/e4m2.bsp", 0xAC84C40A, 0x057FACCC, 0xFFF8CB18}, + {"maps/e4m3.bsp", 0xB6A519E2, 0x74E93DDD, 0x59BEF08C}, + {"maps/e4m4.bsp", 0x3233C45C, 0xE9A7693C, 0x2D3B183F}, + {"maps/e4m5.bsp", 0xE5D3E4DD, 0x17315A00, 0x699CE7F4}, + {"maps/e4m6.bsp", 0x5A7B37C0, 0x6636A6B8, 0x0620FF98}, + {"maps/e4m7.bsp", 0xE9497085, 0xDD1C14E2, 0x9DEC01AC}, + {"maps/e4m8.bsp", 0x325A2B54, 0x3F6274D5, 0x3CB46C57}, - {"maps/gpl_dm1.bsp", 2100781454, -1548219590, -976758093}, - {"maps/gpl_dm2.bsp", 2066969664, 392410074, 1710634548}, - {"maps/gpl_dm3.bsp", -1859681874, 2060033246, 367136248}, - {"maps/gpl_dm4.bsp", -1015750775, 326737183, -1670388545}, - {"maps/gpl_dm5.bsp", 2009758949, 766929852, -1339209475}, - {"maps/gpl_dm6.bsp", 537693021, 247150701, 1376311851}, + {"maps/dm1.bsp", 0x7D37618E, 0xA3B80B3A, 0xC5C7DAB3}, //you should be able to use aquashark's untextured maps. + {"maps/dm2.bsp", 0x7B337440, 0x1763B3DA, 0x65F63634}, + {"maps/dm3.bsp", 0x912781AE, 0x7AC99CDE, 0x15E20DF8}, + {"maps/dm4.bsp", 0xC374DF89, 0x13799D1F, 0x9C6FE4BF}, + {"maps/dm5.bsp", 0x77CA7CE5, 0x2DB66BBC, 0xB02D48FD}, + {"maps/dm6.bsp", 0x200C8B5D, 0x0EBB386D, 0x5208DA2B}, - {"maps/end.bsp", -124054866, -1503553320, -1143688027} + {"maps/end.bsp", 0xF89B12AE, 0xA66198D8, 0xBBD4B4A5}, //unmodified gpl version (with the extra room) + {"maps/end.bsp", 0x924F4D33, 0xA66198D8, 0xBBD4B4A5} //aquashark's gpl version (with the extra room removed) }; unsigned int i; for (i = 0; i < sizeof(sums)/sizeof(sums[0]); i++) { if (checksum == sums[i].gpl2) - return sums[i].id12; + if (!Q_strcasecmp(model->name, sums[i].name)) + return sums[i].id12; } #endif return checksum; diff --git a/engine/common/common.h b/engine/common/common.h index 6d0e99de..72e19f3d 100644 --- a/engine/common/common.h +++ b/engine/common/common.h @@ -703,7 +703,8 @@ extern qboolean standard_quake; //fixme: remove void COM_Effectinfo_Enumerate(int (*cb)(const char *pname)); #endif -unsigned int COM_RemapMapChecksum(unsigned int checksum); +struct model_s; +unsigned int COM_RemapMapChecksum(struct model_s *model, unsigned int checksum); #define MAX_INFO_KEY 256 char *Info_ValueForKey (const char *s, const char *key); diff --git a/engine/common/gl_q2bsp.c b/engine/common/gl_q2bsp.c index 6ea6c8f8..d7720cf8 100644 --- a/engine/common/gl_q2bsp.c +++ b/engine/common/gl_q2bsp.c @@ -4,12 +4,6 @@ #endif #include "com_mesh.h" -#if defined(_WIN32) || defined(__DJGPP__) -#include -#else -#include -#endif - #define MAX_Q3MAP_INDICES 0x8000000 //just a sanity limit #define MAX_Q3MAP_VERTEXES 0x800000 //just a sanity limit //#define MAX_CM_PATCH_VERTS (4096) @@ -1733,7 +1727,7 @@ static qboolean CModQ2_LoadLeafs (model_t *mod, qbyte *mod_base, lump_t *l) return false; } // need to save space for box planes - if (count > MAX_MAP_LEAFS) + if (count > SANITY_MAX_MAP_LEAFS) { Con_Printf (CON_ERROR "Map has too many leafs\n"); return false; @@ -1772,6 +1766,7 @@ static qboolean CModQ2_LoadLeafs (model_t *mod, qbyte *mod_base, lump_t *l) mod->numclusters = out->cluster + 1; } out = mod->leafs; + mod->pvsbytes = ((mod->numclusters + 31)>>3)&~3; if (out[0].contents != Q2CONTENTS_SOLID) { @@ -2033,6 +2028,7 @@ static qboolean CModQ2_LoadVisibility (model_t *mod, qbyte *mod_base, lump_t *l) prv->q2vis->bitofs[i][1] = LittleLong (prv->q2vis->bitofs[i][1]); } mod->numclusters = prv->q2vis->numclusters; + mod->pvsbytes = ((mod->numclusters + 31)>>3)&~3; return true; } @@ -3208,7 +3204,7 @@ static qboolean CModQ3_LoadLeafs (model_t *mod, qbyte *mod_base, lump_t *l) } // need to save space for box planes - if (count > MAX_MAP_LEAFS) + if (count > SANITY_MAX_MAP_LEAFS) { Con_Printf (CON_ERROR "Too many leaves on map"); return false; @@ -3453,6 +3449,7 @@ static qboolean CModQ3_LoadVisibility (model_t *mod, qbyte *mod_base, lump_t *l) prv->q3pvs->rowsize = LittleLong (prv->q3pvs->rowsize); } mod->numclusters = numclusters; + mod->pvsbytes = ((mod->numclusters + 31)>>3)&~3; return true; } @@ -3724,7 +3721,7 @@ static void CMQ3_CalcPHS (model_t *mod) vcount = 0; for (i=0 ; i>3] & (1<<(j&7)) ) @@ -4430,11 +4427,11 @@ int CM_ClusterBytes (model_t *model) if (model->fromgame == fg_quake3) { cminfo_t *prv = (cminfo_t*)model->meshinfo; - return prv->q3pvs->rowsize ? prv->q3pvs->rowsize : MAX_MAP_LEAFS / 8; + return prv->q3pvs->rowsize ? prv->q3pvs->rowsize : model->pvsbytes; } else #endif - return (model->numclusters+7)/8; + return model->pvsbytes; } static int CM_NumInlineModels (model_t *model) @@ -6089,7 +6086,7 @@ qbyte *Mod_ClusterPVS (int cluster, model_t *model) model); } */ -static void CM_DecompressVis (model_t *mod, qbyte *in, qbyte *out) +static void CM_DecompressVis (model_t *mod, qbyte *in, qbyte *out, qboolean merge) { cminfo_t *prv = (cminfo_t*)mod->meshinfo; int c; @@ -6109,70 +6106,101 @@ static void CM_DecompressVis (model_t *mod, qbyte *in, qbyte *out) return; } - do + if (merge) { - if (*in) + do { - *out_p++ = *in++; - continue; - } + if (*in) + { + *out_p++ |= *in++; + continue; + } - c = in[1]; - in += 2; - if ((out_p - out) + c > row) + out_p += in[1]; + in += 2; + } while (out_p - out < row); + } + else + { + do { - c = row - (out_p - out); - Con_DPrintf ("warning: Vis decompression overrun\n"); - } - while (c) - { - *out_p++ = 0; - c--; - } - } while (out_p - out < row); + if (*in) + { + *out_p++ = *in++; + continue; + } + + c = in[1]; + in += 2; + if ((out_p - out) + c > row) + { + c = row - (out_p - out); + Con_DPrintf ("warning: Vis decompression overrun\n"); + } + while (c) + { + *out_p++ = 0; + c--; + } + } while (out_p - out < row); + } } -static FTE_ALIGN(4) qbyte pvsrow[MAX_MAP_LEAFS/8]; -static FTE_ALIGN(4) qbyte phsrow[MAX_MAP_LEAFS/8]; +static pvsbuffer_t pvsrow; +static pvsbuffer_t phsrow; -qbyte *CM_ClusterPVS (model_t *mod, int cluster, qbyte *buffer, unsigned int buffersize) +qbyte *CM_ClusterPVS (model_t *mod, int cluster, pvsbuffer_t *buffer, pvsmerge_t merge) { cminfo_t *prv = (cminfo_t*)mod->meshinfo; if (!buffer) - { - buffer = pvsrow; - buffersize = sizeof(pvsrow); - } - if (buffersize < (mod->numclusters+7)>>3) - Sys_Error("CM_ClusterPVS with too small a buffer\n"); + buffer = &pvsrow; + if (buffer->buffersize < mod->pvsbytes) + buffer->buffer = BZ_Realloc(buffer->buffer, buffer->buffersize=mod->pvsbytes); if (mod->fromgame == fg_quake2) { if (cluster == -1) - memset (buffer, 0, (mod->numclusters+7)>>3); + memset (buffer->buffer, 0, (mod->numclusters+7)>>3); else - CM_DecompressVis (mod, ((qbyte*)prv->q2vis) + prv->q2vis->bitofs[cluster][DVIS_PVS], buffer); - return buffer; + CM_DecompressVis (mod, ((qbyte*)prv->q2vis) + prv->q2vis->bitofs[cluster][DVIS_PVS], buffer->buffer, merge==PVM_MERGE); + return buffer->buffer; } else { if (cluster != -1 && prv->q3pvs->numclusters) { - return (qbyte *)prv->q3pvs->data + cluster * prv->q3pvs->rowsize; + if (merge == PVM_FAST) + return (qbyte *)prv->q3pvs->data + cluster * prv->q3pvs->rowsize; + else if (merge == PVM_REPLACE) + memcpy(buffer->buffer, prv->q3pvs->data + cluster * prv->q3pvs->rowsize, mod->pvsbytes); + else + { + int c; + char *in = prv->q3pvs->data + cluster * prv->q3pvs->rowsize; + for (c = 0; c < mod->pvsbytes; c++) + *(int*)&buffer->buffer[c] |= *(int*)&in[c]; + } } else { - memset (buffer, 0, (mod->numclusters+7)>>3); - return buffer; + if (merge != PVM_REPLACE) + memset (buffer->buffer, 0, (mod->numclusters+7)>>3); } + return buffer->buffer; } } -qbyte *CM_ClusterPHS (model_t *mod, int cluster) +qbyte *CM_ClusterPHS (model_t *mod, int cluster, pvsbuffer_t *buffer) { cminfo_t *prv = (cminfo_t*)mod->meshinfo; + + if (!buffer) + buffer = &phsrow; + if (buffer->buffersize < mod->pvsbytes) + buffer->buffer = BZ_Realloc(buffer->buffer, buffer->buffersize=mod->pvsbytes); + if (mod->fromgame != fg_quake2) { if (cluster != -1 && prv->q3phs->numclusters) @@ -6181,16 +6209,16 @@ qbyte *CM_ClusterPHS (model_t *mod, int cluster) } else { - memset (phsrow, 0, (mod->numclusters+7)>>3); - return phsrow; + memset (buffer->buffer, 0, (mod->numclusters+7)>>3); + return buffer->buffer; } } if (cluster == -1) - memset (phsrow, 0, (mod->numclusters+7)>>3); + memset (buffer->buffer, 0, (mod->numclusters+7)>>3); else - CM_DecompressVis (mod, ((qbyte*)prv->q2vis) + prv->q2vis->bitofs[cluster][DVIS_PHS], phsrow); - return phsrow; + CM_DecompressVis (mod, ((qbyte*)prv->q2vis) + prv->q2vis->bitofs[cluster][DVIS_PHS], buffer->buffer, false); + return buffer->buffer; } diff --git a/engine/common/net.h b/engine/common/net.h index 2e3865d7..77c5507d 100644 --- a/engine/common/net.h +++ b/engine/common/net.h @@ -126,7 +126,7 @@ neterr_t NET_SendPacket (netsrc_t socket, int length, const void *data, netadr_t int NET_LocalAddressForRemote(struct ftenet_connections_s *collection, netadr_t *remote, netadr_t *local, int idx); void NET_PrintAddresses(struct ftenet_connections_s *collection); qboolean NET_AddressSmellsFunny(netadr_t *a); -qboolean NET_EnsureRoute(struct ftenet_connections_s *collection, char *routename, char *host, qboolean islisten); +qboolean NET_EnsureRoute(struct ftenet_connections_s *collection, char *routename, char *host); void NET_PrintConnectionsStatus(struct ftenet_connections_s *collection); enum addressscope_e @@ -159,7 +159,7 @@ char *NET_AdrToStringMasked (char *s, int len, netadr_t *a, netadr_t *amask); void NET_IntegerToMask (netadr_t *a, netadr_t *amask, int bits); qboolean NET_CompareAdrMasked(netadr_t *a, netadr_t *b, netadr_t *mask); -qboolean FTENET_AddToCollection(struct ftenet_connections_s *col, const char *name, const char *address, netadrtype_t addrtype, netproto_t addrprot, qboolean islisten); +qboolean FTENET_AddToCollection(struct ftenet_connections_s *col, const char *name, const char *address, netadrtype_t addrtype, netproto_t addrprot); #ifdef HAVE_DTLS qboolean NET_DTLS_Create(struct ftenet_connections_s *col, netadr_t *to); diff --git a/engine/common/net_ice.c b/engine/common/net_ice.c index 867d2b98..648fb2ac 100644 --- a/engine/common/net_ice.c +++ b/engine/common/net_ice.c @@ -94,11 +94,26 @@ struct icestate_s ftenet_connections_t *connections; - //FIXME: we should probably include decode state in here somehow so multiple connections don't clobber each other. - char *codec[32]; //96-127. don't really need to care about other ones. + struct icecodecslot_s + { + //FIXME: we should probably include decode state in here somehow so multiple connections don't clobber each other. + int id; + char *name; + } codecslot[34]; //96-127. don't really need to care about other ones. }; static struct icestate_s *icelist; +static struct icecodecslot_s *ICE_GetCodecSlot(struct icestate_s *ice, int slot) +{ + if (slot >= 96 && slot < 96+32) + return &ice->codecslot[slot-96]; + else if (slot == 0) + return &ice->codecslot[32]; + else if (slot == 8) + return &ice->codecslot[33]; + return NULL; +} + #if !defined(SERVERONLY) && defined(VOICECHAT) extern cvar_t snd_voip_send; @@ -121,7 +136,6 @@ qboolean NET_RTP_Parse(void) int hlen; int padding = 0; struct icestate_s *con; - int proto; //make sure this really came from an accepted rtp stream //note that an rtp connection equal to the game connection will likely mess up when sequences start to get big //(especially problematic in sane clients that start with a random sequence) @@ -129,11 +143,11 @@ qboolean NET_RTP_Parse(void) { if (con->state != ICE_INACTIVE && (con->proto == ICEP_VIDEO || con->proto == ICEP_VOICE) && NET_CompareAdr(&net_from, &con->chosenpeer)) { - proto = rtpheader->m1_pt7 & 0x7f; - if (proto >= 96 && proto <= 127) //rtp dynamic assignments + struct icecodecslot_s *codec = ICE_GetCodecSlot(con, rtpheader->m1_pt7 & 0x7f); + if (codec) //untracked slot { - char *codecname = con->codec[proto-96]; - if (!codecname) + char *codecname = codec->name; + if (!codecname) //inactive slot continue; if (rtpheader->v2_p1_x1_cc4 & 0x20) @@ -179,16 +193,16 @@ qboolean NET_RTP_Transmit(unsigned int sequence, unsigned int timestamp, const c { if (con->state == ICE_CONNECTED && con->proto == ICEP_VOICE) { - for (i = 0; i < sizeof(con->codec)/sizeof(con->codec[0]); i++) + for (i = 0; i < countof(con->codecslot); i++) { - if (con->codec[i] && !strcmp(con->codec[i], codec)) + if (con->codecslot[i].name && !strcmp(con->codecslot[i].name, codec)) { if (!built) { built = true; MSG_WriteByte(&buf, (2u<<6) | (0u<<5) | (0u<<4) | (0<<0)); //v2_p1_x1_cc4 - MSG_WriteByte(&buf, (0u<<7) | ((i+96)<<0)); //m1_pt7 - MSG_WriteShort(&buf, BigShort(sequence)&0xffff); //seq + MSG_WriteByte(&buf, (0u<<7) | (con->codecslot[i].id<<0)); //m1_pt7 + MSG_WriteShort(&buf, BigShort(sequence&0xffff)); //seq MSG_WriteLong(&buf, BigLong(timestamp)); //timestamp MSG_WriteLong(&buf, BigLong(0)); //ssrc SZ_Write(&buf, cdata, clength); @@ -259,13 +273,15 @@ struct icestate_s *QDECL ICE_Create(void *module, const char *conname, const cha case ICEP_VOICE: case ICEP_VIDEO: collection = cls.sockets; - NET_InitClient(false); + if (!collection) + NET_InitClient(false); break; #endif #ifndef SERVERONLY case ICEP_QWCLIENT: collection = cls.sockets; - NET_InitClient(false); + if (!collection) + NET_InitClient(false); break; #endif #ifndef CLIENTONLY @@ -297,8 +313,8 @@ struct icestate_s *QDECL ICE_Create(void *module, const char *conname, const cha if (!collection) { con->connections = collection = FTENET_CreateCollection(true); - FTENET_AddToCollection(collection, "UDP", "0", NA_IP, NP_DGRAM, true); - FTENET_AddToCollection(collection, "natpmp", "natpmp://5351", NA_IP, NP_NATPMP, true); + FTENET_AddToCollection(collection, "UDP", "0", NA_IP, NP_DGRAM); + FTENET_AddToCollection(collection, "natpmp", "natpmp://5351", NA_IP, NP_NATPMP); } con->next = icelist; @@ -633,20 +649,20 @@ qboolean QDECL ICE_Set(struct icestate_s *con, const char *prop, const char *val con->controlled = !atoi(value); else if (!strncmp(prop, "codec", 5)) { - int codec = atoi(prop+5); - if (codec < 96 || codec > 127) + struct icecodecslot_s *codec = ICE_GetCodecSlot(con, atoi(prop+5)); + if (!codec) return false; - codec -= 96; + codec->id = atoi(prop+5); #if !defined(SERVERONLY) && defined(VOICECHAT) if (!S_Voip_RTP_CodecOkay(value)) #endif { - Z_Free(con->codec[codec]); - con->codec[codec] = NULL; + Z_Free(codec->name); + codec->name = NULL; return false; } - Z_Free(con->codec[codec]); - con->codec[codec] = Z_StrDup(value); + Z_Free(codec->name); + codec->name = Z_StrDup(value); } else if (!strcmp(prop, "rufrag")) { @@ -822,12 +838,12 @@ qboolean QDECL ICE_Get(struct icestate_s *con, const char *prop, char *value, si Q_strncpyz(value, con->lpwd, valuelen); else if (!strncmp(prop, "codec", 5)) { - int codec = atoi(prop+5); - if (codec < 96 || codec > 127) + int codecid = atoi(prop+5); + struct icecodecslot_s *codec = ICE_GetCodecSlot(con, atoi(prop+5)); + if (!codec || codec->id != codecid) return false; - codec -= 96; - if (con->codec[codec]) - Q_strncpyz(value, con->codec[codec], valuelen); + if (codec->name) + Q_strncpyz(value, codec->name, valuelen); else Q_strncpyz(value, "", valuelen); } @@ -877,23 +893,25 @@ qboolean QDECL ICE_Get(struct icestate_s *con, const char *prop, char *value, si #endif } - for (i = 0; i < countof(con->codec); i++) + /*fixme: merge the codecs into a single media line*/ + for (i = 0; i < countof(con->codecslot); i++) { - if (!con->codec[i]) + int id = con->codecslot[i].id; + if (!con->codecslot[i].name) continue; - Q_strncatz(value, va("m=audio %i RTP/AVP %i\n", sender.port, i+96), valuelen); + Q_strncatz(value, va("m=audio %i RTP/AVP %i\n", sender.port, id), valuelen); Q_strncatz(value, va("b=RS:0\n"), valuelen); Q_strncatz(value, va("b=RR:0\n"), valuelen); - Q_strncpyz(tmpstr, con->codec[i], sizeof(tmpstr)); + Q_strncpyz(tmpstr, con->codecslot[i].name, sizeof(tmpstr)); at = strchr(tmpstr, '@'); if (at) { *at = '/'; - Q_strncatz(value, va("a=rtpmap:%i %s\n", i+96, tmpstr), valuelen); + Q_strncatz(value, va("a=rtpmap:%i %s\n", id, tmpstr), valuelen); } else - Q_strncatz(value, va("a=rtpmap:%i %s/%i\n", i+96, tmpstr, 8000), valuelen); + Q_strncatz(value, va("a=rtpmap:%i %s/%i\n", id, tmpstr, 8000), valuelen); for (can = con->lc; can; can = can->next) { diff --git a/engine/common/net_ssl_gnutls.c b/engine/common/net_ssl_gnutls.c index 15ba27de..b22ba89c 100644 --- a/engine/common/net_ssl_gnutls.c +++ b/engine/common/net_ssl_gnutls.c @@ -3,6 +3,7 @@ //named functions, this makes it *really* easy to port plugins from one engine to annother. #include "quakedef.h" +#include "netinc.h" #ifndef GNUTLS_STATIC #define GNUTLS_DYNAMIC //statically linking is bad, because that just dynamically links to a .so that probably won't exist. @@ -710,6 +711,7 @@ static gnutls_datum_t cookie_key; qboolean SSL_InitGlobal(qboolean isserver) { static int initstatus[2]; + isserver = !!isserver; if (!initstatus[isserver]) { if (!Init_GNUTLS()) @@ -744,12 +746,12 @@ qboolean SSL_InitGlobal(qboolean isserver) char keyfile[MAX_OSPATH]; char certfile[MAX_OSPATH]; *keyfile = *certfile = 0; - if (FS_NativePath("key.pem", FS_ROOT, keyfile, sizeof(keyfile))) - if (FS_NativePath("cert.pem", FS_ROOT, certfile, sizeof(certfile))) - ret = qgnutls_certificate_set_x509_key_file(xcred[isserver], certfile, keyfile, GNUTLS_X509_FMT_PEM); + if (FS_NativePath("key.pem", FS_ROOT, keyfile, sizeof(keyfile))) + if (FS_NativePath("cert.pem", FS_ROOT, certfile, sizeof(certfile))) + ret = qgnutls_certificate_set_x509_key_file(xcred[isserver], certfile, keyfile, GNUTLS_X509_FMT_PEM); if (ret < 0) { - Con_Printf("No certificate or key were found in %s and %s\n", certfile, keyfile); + Con_Printf("No certificate or key was found in %s and %s\n", certfile, keyfile); initstatus[isserver] = -1; } } @@ -848,17 +850,11 @@ vfsfile_t *FS_OpenSSL(const char *hostname, vfsfile_t *source, qboolean isserver #ifdef HAVE_DTLS -void DTLS_DestroyContext(void *ctx) +void GNUDTLS_DestroyContext(void *ctx) { SSL_Close(ctx); } -qboolean DTLS_HasServerCertificate(void) -{ - if (!SSL_InitGlobal(true)) - return false; - return true; -} -void *DTLS_CreateContext(void *cbctx, neterr_t(*push)(void *cbctx, const qbyte *data, size_t datasize), qboolean isserver) +void *GNUDTLS_CreateContext(const char *remotehost, void *cbctx, neterr_t(*push)(void *cbctx, const qbyte *data, size_t datasize), qboolean isserver) { gnutlsfile_t *newf; @@ -875,7 +871,7 @@ void *DTLS_CreateContext(void *cbctx, neterr_t(*push)(void *cbctx, const qbyte * // Sys_Printf("DTLS_CreateContext: server=%i\n", isserver); - Q_strncpyz(newf->certname, "", sizeof(newf->certname)); + Q_strncpyz(newf->certname, remotehost?remotehost:"", sizeof(newf->certname)); if (!SSL_InitConnection(newf, isserver, true)) { @@ -886,7 +882,7 @@ void *DTLS_CreateContext(void *cbctx, neterr_t(*push)(void *cbctx, const qbyte * return newf; } -neterr_t DTLS_Transmit(void *ctx, const qbyte *data, size_t datasize) +neterr_t GNUDTLS_Transmit(void *ctx, const qbyte *data, size_t datasize) { int ret; gnutlsfile_t *f = (gnutlsfile_t *)ctx; @@ -918,7 +914,7 @@ neterr_t DTLS_Transmit(void *ctx, const qbyte *data, size_t datasize) return NETERR_SENT; } -neterr_t DTLS_Received(void *ctx, qbyte *data, size_t datasize) +neterr_t GNUDTLS_Received(void *ctx, qbyte *data, size_t datasize) { int cli_addr = 0xdeadbeef; int ret; @@ -992,7 +988,7 @@ neterr_t DTLS_Received(void *ctx, qbyte *data, size_t datasize) return NETERR_SENT; } -neterr_t DTLS_Timeouts(void *ctx) +neterr_t GNUDTLS_Timeouts(void *ctx) { gnutlsfile_t *f = (gnutlsfile_t *)ctx; int ret; @@ -1012,13 +1008,25 @@ neterr_t DTLS_Timeouts(void *ctx) } return NETERR_SENT; } -#else -void DTLS_DestroyContext(void *ctx){} -qboolean DTLS_HasServerCertificate(void){return false;} -void *DTLS_CreateContext(void *cbctx, neterr_t(*push)(void *cbctx, const qbyte *data, size_t datasize), qboolean isserver){return NULL;} -neterr_t DTLS_Transmit(void *ctx, const qbyte *data, size_t datasize){return NETERR_DISCONNECTED;} -neterr_t DTLS_Received(void *ctx, qbyte *data, size_t datasize){return NETERR_DISCONNECTED;} -neterr_t DTLS_Timeouts(void *ctx) {return NETERR_SENT;} + +static const dtlsfuncs_t dtlsfuncs_gnutls = +{ + GNUDTLS_CreateContext, + GNUDTLS_DestroyContext, + GNUDTLS_Transmit, + GNUDTLS_Received, + GNUDTLS_Timeouts, +}; +const dtlsfuncs_t *DTLS_InitServer(void) +{ + if (!SSL_InitGlobal(true)) + return NULL; //unable to init a server certificate. don't allow dtls to init. + return &dtlsfuncs_gnutls; +} +const dtlsfuncs_t *DTLS_InitClient(void) +{ + return &dtlsfuncs_gnutls; +} #endif #endif diff --git a/engine/common/net_ssl_winsspi.c b/engine/common/net_ssl_winsspi.c index d4353422..7e1e645b 100644 --- a/engine/common/net_ssl_winsspi.c +++ b/engine/common/net_ssl_winsspi.c @@ -1072,42 +1072,61 @@ vfsfile_t *FS_OpenSSL(const char *servername, vfsfile_t *source, qboolean server } +#include "netinc.h" #if 0 -struct nulldtls_s +struct fakedtls_s { void *cbctx; neterr_t(*push)(void *cbctx, const qbyte *data, size_t datasize); }; -void *DTLS_CreateContext(void *cbctx, neterr_t(*push)(void *cbctx, const qbyte *data, size_t datasize), qboolean isserver) +static void *FAKEDTLS_CreateContext(const char *remotehost, void *cbctx, neterr_t(*push)(void *cbctx, const qbyte *data, size_t datasize), qboolean isserver) { - struct nulldtls_s *ctx = Z_Malloc(sizeof(*ctx)); + struct fakedtls_s *ctx = Z_Malloc(sizeof(*ctx)); ctx->cbctx = cbctx; ctx->push = push; return ctx; } -qboolean DTLS_HasServerCertificate(void) +static void FAKEDTLS_DestroyContext(void *vctx) { - //FIXME: at this point, schannel is still returning errors when I try acting as a server. - //so just block any attempt to use this as a server. - //clients don't need certs! - return false; + Z_Free(vctx); } -neterr_t DTLS_Transmit(void *vctx, const qbyte *data, size_t datasize) +static neterr_t FAKEDTLS_Transmit(void *vctx, const qbyte *data, size_t datasize) { - struct nulldtls_s *ctx = vctx; + struct fakedtls_s *ctx = vctx; neterr_t r; *(int*)data ^= 0xdeadbeef; r = ctx->push(ctx->cbctx, data, datasize); *(int*)data ^= 0xdeadbeef; return r; } -neterr_t DTLS_Received(void *ctx, qbyte *data, size_t datasize) +static neterr_t FAKEDTLS_Received(void *ctx, qbyte *data, size_t datasize) { *(int*)data ^= 0xdeadbeef; return NETERR_SENT; } +static neterr_t FAKEDTLS_Timeouts(void *ctx) +{ +// fakedtls_s *f = (fakedtls_s *)ctx; + return NETERR_SENT; +} +static const dtlsfuncs_t dtlsfuncs_fakedtls = +{ + FAKEDTLS_CreateContext, + FAKEDTLS_DestroyContext, + FAKEDTLS_Transmit, + FAKEDTLS_Received, + FAKEDTLS_Timeouts, +}; +const dtlsfuncs_t *FAKEDTLS_InitServer(void) +{ + return &dtlsfuncs_fakedtls; +} +const dtlsfuncs_t *FAKEDTLS_InitClient(void) +{ + return &dtlsfuncs_fakedtls; +} #elif defined(HAVE_DTLS) -void *DTLS_CreateContext(char *remotehost, void *cbctx, neterr_t(*push)(void *cbctx, const qbyte *data, size_t datasize), qboolean isserver) +static void *SSPI_DTLS_CreateContext(const char *remotehost, void *cbctx, neterr_t(*push)(void *cbctx, const qbyte *data, size_t datasize), qboolean isserver) { int i = 0; sslfile_t *ctx; @@ -1150,13 +1169,13 @@ void *DTLS_CreateContext(char *remotehost, void *cbctx, neterr_t(*push)(void *cb return ctx; } -void DTLS_DestroyContext(void *vctx) +static void SSPI_DTLS_DestroyContext(void *vctx) { SSPI_Close(vctx); } -neterr_t DTLS_Transmit(void *ctx, const qbyte *data, size_t datasize) +static neterr_t SSPI_DTLS_Transmit(void *ctx, const qbyte *data, size_t datasize) { int ret; sslfile_t *f = (sslfile_t *)ctx; @@ -1184,7 +1203,7 @@ neterr_t DTLS_Transmit(void *ctx, const qbyte *data, size_t datasize) return ret; } -neterr_t DTLS_Received(void *ctx, qbyte *data, size_t datasize) +static neterr_t SSPI_DTLS_Received(void *ctx, qbyte *data, size_t datasize) { int ret; sslfile_t *f = (sslfile_t *)ctx; @@ -1217,7 +1236,7 @@ neterr_t DTLS_Received(void *ctx, qbyte *data, size_t datasize) f->incrypt.data = NULL; return ret; } -neterr_t DTLS_Timeouts(void *ctx) +static neterr_t SSPI_DTLS_Timeouts(void *ctx) { sslfile_t *f = (sslfile_t *)ctx; if (f->handshaking) @@ -1227,6 +1246,26 @@ neterr_t DTLS_Timeouts(void *ctx) } return NETERR_SENT; } + +static const dtlsfuncs_t dtlsfuncs_schannel = +{ + SSPI_DTLS_CreateContext, + SSPI_DTLS_DestroyContext, + SSPI_DTLS_Transmit, + SSPI_DTLS_Received, + SSPI_DTLS_Timeouts, +}; +const dtlsfuncs_t *SSPI_DTLS_InitServer(void) +{ + //FIXME: at this point, schannel is still returning errors when I try acting as a server. + //so just block any attempt to use this as a server. + //clients don't need/get certs. + return NULL; +} +const dtlsfuncs_t *SSPI_DTLS_InitClient(void) +{ + return &dtlsfuncs_schannel; +} #endif #endif diff --git a/engine/common/net_wins.c b/engine/common/net_wins.c index abe36ff7..45cc35c0 100644 --- a/engine/common/net_wins.c +++ b/engine/common/net_wins.c @@ -1899,7 +1899,7 @@ void FTENET_Loop_Close(ftenet_generic_connection_t *con) int sock = con->thesocket; sock &= 1; loopbacks[sock].inited = false; - loopbacks[sock].get = loopbacks[sock^1].send = 0; + loopbacks[sock].get = loopbacks[sock].send = 0; for (i = 0; i < MAX_LOOPBACK; i++) { BZ_Free(loopbacks[sock].msgs[i].data); @@ -1923,7 +1923,7 @@ static ftenet_generic_connection_t *FTENET_Loop_EstablishConnection(qboolean iss if (newcon) { loopbacks[sock].inited = true; - loopbacks[sock].get = loopbacks[sock^1].send = 0; + loopbacks[sock].get = loopbacks[sock].send = 0; newcon->GetLocalAddresses = FTENET_Loop_GetLocalAddresses; newcon->GetPacket = FTENET_Loop_GetPacket; @@ -2234,6 +2234,8 @@ ftenet_generic_connection_t *FTENET_NATPMP_EstablishConnection(qboolean isserver #ifdef HAVE_DTLS struct dtlspeer_s { + const dtlsfuncs_t *funcs; + ftenet_connections_t *col; void *dtlsstate; netadr_t addr; @@ -2250,10 +2252,31 @@ void NET_DTLS_Timeouts(ftenet_connections_t *col) return; for (peer = col->dtls; peer; peer = peer->next) { - DTLS_Timeouts(peer->dtlsstate); + peer->funcs->Timeouts(peer->dtlsstate); } } +const dtlsfuncs_t *DTLS_InitServer(void) +{ +#if defined(HAVE_GNUTLS) + return GNUDTLS_InitServer(); +#elif defined(HAVE_WINSSPI) + return SSPI_DTLS_InitServer(); +#else + return NULL; +#endif +} +const dtlsfuncs_t *DTLS_InitClient(void) +{ +#ifdef HAVE_WINSSPI + return SSPI_DTLS_InitClient(); +#elif defined(HAVE_GNUTLS) + return GNUDTLS_InitClient(); +#else + return NULL; +#endif +} + static neterr_t NET_SendPacketCol (ftenet_connections_t *collection, int length, const void *data, netadr_t *to); static neterr_t FTENET_DTLS_DoSendPacket(void *cbctx, const qbyte *data, size_t length) { //callback that does the actual sending @@ -2277,16 +2300,27 @@ qboolean NET_DTLS_Create(ftenet_connections_t *col, netadr_t *to) peer->addr = *to; peer->col = col; - peer->dtlsstate = DTLS_CreateContext(NET_BaseAdrToString(hostname, sizeof(hostname), to), peer, FTENET_DTLS_DoSendPacket, col->islisten); - Sys_Printf("Created %p\n", peer->dtlsstate); - - if (peer->next) - peer->next->link = &peer->next; - peer->link = &col->dtls; - peer->next = col->dtls; - col->dtls = peer; + if (col->islisten) + peer->funcs = DTLS_InitServer(); + else + peer->funcs = DTLS_InitClient(); + if (peer->funcs) + peer->dtlsstate = peer->funcs->CreateContext(NET_BaseAdrToString(hostname, sizeof(hostname), to), peer, FTENET_DTLS_DoSendPacket, col->islisten); + if (peer->dtlsstate) + { + if (peer->next) + peer->next->link = &peer->next; + peer->link = &col->dtls; + peer->next = col->dtls; + col->dtls = peer; + } + else + { + Z_Free(peer); + peer = NULL; + } } - return true; + return peer!=NULL; } static void NET_DTLS_DisconnectPeer(ftenet_connections_t *col, struct dtlspeer_s *peer) { @@ -2296,7 +2330,7 @@ static void NET_DTLS_DisconnectPeer(ftenet_connections_t *col, struct dtlspeer_s peer->next->link = peer->link; *peer->link = peer->next; - DTLS_DestroyContext(peer->dtlsstate); + peer->funcs->DestroyContext(peer->dtlsstate); Z_Free(peer); } qboolean NET_DTLS_Disconnect(ftenet_connections_t *col, netadr_t *to) @@ -2327,7 +2361,7 @@ static neterr_t FTENET_DTLS_SendPacket(ftenet_connections_t *col, int length, co } to->prot = NP_DTLS; if (peer) - return DTLS_Transmit(peer->dtlsstate, data, length); + return peer->funcs->Transmit(peer->dtlsstate, data, length); else return NETERR_NOROUTE; } @@ -2339,7 +2373,7 @@ qboolean NET_DTLS_Decode(ftenet_connections_t *col) { if (NET_CompareAdr(&peer->addr, &net_from)) { - switch(DTLS_Received(peer->dtlsstate, net_message.data, net_message.cursize)) + switch(peer->funcs->Received(peer->dtlsstate, net_message.data, net_message.cursize)) { case NETERR_DISCONNECTED: Sys_Printf("disconnected %p\n", peer->dtlsstate); @@ -2415,14 +2449,19 @@ static qboolean FTENET_AddToCollection_Ptr(ftenet_connections_t *col, const char } return count > 0; } -qboolean FTENET_AddToCollection(ftenet_connections_t *col, const char *name, const char *addresslist, netadrtype_t addrtype, netproto_t addrprot, qboolean islisten) +qboolean FTENET_AddToCollection(ftenet_connections_t *col, const char *name, const char *addresslist, netadrtype_t addrtype, netproto_t addrprot) { + qboolean islisten; netadr_t adr[8]; ftenet_generic_connection_t *(*establish[countof(adr)])(qboolean isserver, const char *address, netadr_t adr); char address[countof(adr)][256]; unsigned int i, j; qboolean success = false; + if (!col) + return false; + islisten = col->islisten; + if (name && strchr(name, ':')) return false; @@ -2432,14 +2471,17 @@ qboolean FTENET_AddToCollection(ftenet_connections_t *col, const char *name, con //resolve the address to something sane so we can determine the address type and thus the connection type to use if (!*address[i]) adr[i].type = NA_INVALID; - else if (islisten) - NET_PortToAdr(addrtype, addrprot, address[i], &adr[i]); - else + else //if (islisten) + { + if (!NET_PortToAdr(addrtype, addrprot, address[i], &adr[i])) + return false; + } +/* else { if (!NET_StringToAdr(address[i], 0, &adr[i])) return false; } - +*/ #ifdef HAVE_WEBSOCKCL if (adr[i].prot == NP_WS && adr[i].type == NA_WEBSOCKET) establish[i] = FTENET_WebSocket_EstablishConnection; else if (adr[i].prot == NP_WSS && adr[i].type == NA_WEBSOCKET) establish[i] = FTENET_WebSocket_EstablishConnection; else @@ -2963,7 +3005,7 @@ static qboolean FTENET_Datagram_ChangeLocalAddress(struct ftenet_generic_connect { struct sockaddr_qstorage address; netadr_t current; - int namelen; + int namelen = sizeof(address); if (getsockname (con->thesocket, (struct sockaddr *)&address, &namelen) == 0) { SockadrToNetadr(&address, ¤t); @@ -6521,7 +6563,7 @@ neterr_t NET_SendPacket (netsrc_t netsrc, int length, const void *data, netadr_t return NET_SendPacketCol (collection, length, data, to); } -qboolean NET_EnsureRoute(ftenet_connections_t *collection, char *routename, char *host, qboolean islisten) +qboolean NET_EnsureRoute(ftenet_connections_t *collection, char *routename, char *host) { netadr_t adr; @@ -6539,7 +6581,7 @@ qboolean NET_EnsureRoute(ftenet_connections_t *collection, char *routename, char case NP_WSS: case NP_TLS: case NP_STREAM: - if (!FTENET_AddToCollection(collection, routename, host, adr.type, adr.prot, islisten)) + if (!FTENET_AddToCollection(collection, routename, host, adr.type, adr.prot)) return false; Con_Printf("Establishing connection to %s\n", host); break; @@ -7154,11 +7196,11 @@ void SVNET_AddPort_f(void) { svs.sockets = FTENET_CreateCollection(true); #ifndef SERVERONLY - FTENET_AddToCollection(svs.sockets, "SVLoopback", STRINGIFY(PORT_QWSERVER), NA_LOOPBACK, NP_DGRAM, true); + FTENET_AddToCollection(svs.sockets, "SVLoopback", STRINGIFY(PORT_QWSERVER), NA_LOOPBACK, NP_DGRAM); #endif } - FTENET_AddToCollection(svs.sockets, conname, *s?s:NULL, *s?NA_IP:NA_INVALID, NP_DGRAM, true); + FTENET_AddToCollection(svs.sockets, conname, *s?s:NULL, *s?NA_IP:NA_INVALID, NP_DGRAM); } #endif @@ -7288,27 +7330,27 @@ void NET_InitClient(qboolean loopbackonly) if (!cls.sockets) cls.sockets = FTENET_CreateCollection(false); #ifndef CLIENTONLY - FTENET_AddToCollection(cls.sockets, "CLLoopback", "1", NA_LOOPBACK, NP_DGRAM, true); + FTENET_AddToCollection(cls.sockets, "CLLoopback", "1", NA_LOOPBACK, NP_DGRAM); #endif if (loopbackonly) port = ""; #if defined(HAVE_IPV4) && defined(HAVE_IPV6) if (net_hybriddualstack.ival) { - FTENET_AddToCollection(cls.sockets, "CLUDP", port, NA_IP, NP_DGRAM, true); + FTENET_AddToCollection(cls.sockets, "CLUDP", port, NA_IP, NP_DGRAM); } else #endif { #ifdef HAVE_IPV4 - FTENET_AddToCollection(cls.sockets, "CLUDP4", port, NA_IP, NP_DGRAM, true); + FTENET_AddToCollection(cls.sockets, "CLUDP4", port, NA_IP, NP_DGRAM); #endif #ifdef HAVE_IPV6 - FTENET_AddToCollection(cls.sockets, "CLUDP6", port, NA_IPV6, NP_DGRAM, true); + FTENET_AddToCollection(cls.sockets, "CLUDP6", port, NA_IPV6, NP_DGRAM); #endif } #ifdef USEIPX - FTENET_AddToCollection(cls.sockets, "CLIPX", port, NA_IPX, NP_DGRAM, true); + FTENET_AddToCollection(cls.sockets, "CLIPX", port, NA_IPX, NP_DGRAM); #endif // Con_TPrintf("Client port Initialized\n"); @@ -7320,9 +7362,9 @@ void NET_InitClient(qboolean loopbackonly) void QDECL SV_Tcpport_Callback(struct cvar_s *var, char *oldvalue) { if (!strcmp(var->string, "0")) //qtv_streamport had an old default value of 0. make sure we don't end up listening on random ports. - FTENET_AddToCollection(svs.sockets, var->name, "", NA_IP, NP_STREAM, true); + FTENET_AddToCollection(svs.sockets, var->name, "", NA_IP, NP_STREAM); else - FTENET_AddToCollection(svs.sockets, var->name, var->string, NA_IP, NP_STREAM, true); + FTENET_AddToCollection(svs.sockets, var->name, var->string, NA_IP, NP_STREAM); } cvar_t sv_port_tcp = CVARFC("sv_port_tcp", "", CVAR_SERVERINFO, SV_Tcpport_Callback); #ifndef NOLEGACY @@ -7333,35 +7375,35 @@ cvar_t qtv_streamport = CVARAFCD( "qtv_streamport", "", #ifdef IPPROTO_IPV6 void QDECL SV_Tcpport6_Callback(struct cvar_s *var, char *oldvalue) { - FTENET_AddToCollection(svs.sockets, var->name, var->string, NA_IPV6, NP_STREAM, true); + FTENET_AddToCollection(svs.sockets, var->name, var->string, NA_IPV6, NP_STREAM); } cvar_t sv_port_tcp6 = CVARC("sv_port_tcp6", "", SV_Tcpport6_Callback); #endif #ifdef HAVE_IPV4 void QDECL SV_Port_Callback(struct cvar_s *var, char *oldvalue) { - FTENET_AddToCollection(svs.sockets, var->name, var->string, NA_IP, NP_DGRAM, true); + FTENET_AddToCollection(svs.sockets, var->name, var->string, NA_IP, NP_DGRAM); } cvar_t sv_port_ipv4 = CVARC("sv_port", STRINGIFY(PORT_QWSERVER), SV_Port_Callback); #endif #ifdef IPPROTO_IPV6 void QDECL SV_PortIPv6_Callback(struct cvar_s *var, char *oldvalue) { - FTENET_AddToCollection(svs.sockets, var->name, var->string, NA_IPV6, NP_DGRAM, true); + FTENET_AddToCollection(svs.sockets, var->name, var->string, NA_IPV6, NP_DGRAM); } cvar_t sv_port_ipv6 = CVARCD("sv_port_ipv6", "", SV_PortIPv6_Callback, "Port to use for incoming ipv6 udp connections. Due to hybrid sockets this might not be needed. You can specify an ipv4 address:port for a second ipv4 port if you want."); #endif #ifdef USEIPX void QDECL SV_PortIPX_Callback(struct cvar_s *var, char *oldvalue) { - FTENET_AddToCollection(svs.sockets, var->name, var->string, NA_IPX, NP_DGRAM, true); + FTENET_AddToCollection(svs.sockets, var->name, var->string, NA_IPX, NP_DGRAM); } cvar_t sv_port_ipx = CVARC("sv_port_ipx", "", SV_PortIPX_Callback); #endif #ifdef HAVE_NATPMP void QDECL SV_Port_NatPMP_Callback(struct cvar_s *var, char *oldvalue) { - FTENET_AddToCollection(svs.sockets, var->name, va("natpmp://%s", var->string), NA_IP, NP_NATPMP, true); + FTENET_AddToCollection(svs.sockets, var->name, va("natpmp://%s", var->string), NA_IP, NP_NATPMP); } #if 1//def SERVERONLY #define NATPMP_DEFAULT_PORT "" //don't fuck with dedicated servers @@ -7443,7 +7485,7 @@ void NET_InitServer(void) { svs.sockets = FTENET_CreateCollection(true); #ifndef SERVERONLY - FTENET_AddToCollection(svs.sockets, "SVLoopback", STRINGIFY(PORT_QWSERVER), NA_LOOPBACK, NP_DGRAM, true); + FTENET_AddToCollection(svs.sockets, "SVLoopback", STRINGIFY(PORT_QWSERVER), NA_LOOPBACK, NP_DGRAM); #endif } @@ -7478,7 +7520,7 @@ void NET_InitServer(void) #ifndef SERVERONLY svs.sockets = FTENET_CreateCollection(true); - FTENET_AddToCollection(svs.sockets, "SVLoopback", STRINGIFY(PORT_QWSERVER), NA_LOOPBACK, NP_DGRAM, true); + FTENET_AddToCollection(svs.sockets, "SVLoopback", STRINGIFY(PORT_QWSERVER), NA_LOOPBACK, NP_DGRAM); #endif } } diff --git a/engine/common/netinc.h b/engine/common/netinc.h index b0bd10f7..359e7175 100644 --- a/engine/common/netinc.h +++ b/engine/common/netinc.h @@ -293,12 +293,24 @@ typedef struct ftenet_generic_connection_s { } ftenet_generic_connection_t; #ifdef HAVE_DTLS -void *DTLS_CreateContext(char *remotehost, void *cbctx, neterr_t(*push)(void *cbctx, const qbyte *data, size_t datasize), qboolean isserver); //if remotehost is null then their certificate will not be validated. -void DTLS_DestroyContext(void *ctx); -neterr_t DTLS_Transmit(void *ctx, const qbyte *data, size_t datasize); -neterr_t DTLS_Received(void *ctx, qbyte *data, size_t datasize); -neterr_t DTLS_Timeouts(void *ctx); -qboolean DTLS_HasServerCertificate(void); +typedef struct dtlsfuncs_s +{ + void *(*CreateContext)(const char *remotehost, void *cbctx, neterr_t(*push)(void *cbctx, const qbyte *data, size_t datasize), qboolean isserver); //if remotehost is null then their certificate will not be validated. + void (*DestroyContext)(void *ctx); + neterr_t (*Transmit)(void *ctx, const qbyte *data, size_t datasize); + neterr_t (*Received)(void *ctx, qbyte *data, size_t datasize); + neterr_t (*Timeouts)(void *ctx); +} dtlsfuncs_t; +const dtlsfuncs_t *DTLS_InitServer(void); +const dtlsfuncs_t *DTLS_InitClient(void); +#ifdef HAVE_WINSSPI + 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 + 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 #endif @@ -320,6 +332,7 @@ typedef struct ftenet_connections_s #ifdef HAVE_DTLS struct dtlspeer_s *dtls; //linked list. linked lists are shit, but at least it keeps pointers valid when things are resized. + const dtlsfuncs_t *dtlsfuncs; #endif } ftenet_connections_t; @@ -330,7 +343,7 @@ void QDECL ICE_AddLCandidateInfo(struct icestate_s *con, netadr_t *adr, int adrn ftenet_connections_t *FTENET_CreateCollection(qboolean listen); void FTENET_CloseCollection(ftenet_connections_t *col); -qboolean FTENET_AddToCollection(struct ftenet_connections_s *col, const char *name, const char *address, netadrtype_t addrtype, netproto_t addrprot, qboolean islisten); +qboolean FTENET_AddToCollection(struct ftenet_connections_s *col, const char *name, const char *address, netadrtype_t addrtype, netproto_t addrprot); int NET_EnumerateAddresses(ftenet_connections_t *collection, struct ftenet_generic_connection_s **con, unsigned int *adrflags, netadr_t *addresses, int maxaddresses); vfsfile_t *FS_OpenSSL(const char *hostname, vfsfile_t *source, qboolean server); diff --git a/engine/common/pr_bgcmd.c b/engine/common/pr_bgcmd.c index 75be8119..3f46108e 100644 --- a/engine/common/pr_bgcmd.c +++ b/engine/common/pr_bgcmd.c @@ -1074,7 +1074,7 @@ void QCBUILTIN PF_getsurfacepointattribute(pubprogfuncs_t *prinst, struct global } } -qbyte qcpvs[(MAX_MAP_LEAFS+7)/8]; +pvsbuffer_t qcpvs; //#240 float(vector viewpos, entity viewee) checkpvs (FTE_QC_CHECKPVS) //note: this requires a correctly setorigined entity. void QCBUILTIN PF_checkpvs(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) @@ -1091,9 +1091,9 @@ void QCBUILTIN PF_checkpvs(pubprogfuncs_t *prinst, struct globalvars_s *pr_globa { //FIXME: Make all alternatives of FatPVS not recalulate the pvs. //and yeah, this is overkill what with the whole fat thing and all. - world->worldmodel->funcs.FatPVS(world->worldmodel, viewpos, qcpvs, sizeof(qcpvs), false); + world->worldmodel->funcs.FatPVS(world->worldmodel, viewpos, &qcpvs, false); - G_FLOAT(OFS_RETURN) = world->worldmodel->funcs.EdictInFatPVS(world->worldmodel, &ent->pvsinfo, qcpvs); + G_FLOAT(OFS_RETURN) = world->worldmodel->funcs.EdictInFatPVS(world->worldmodel, &ent->pvsinfo, qcpvs.buffer); } } @@ -4260,10 +4260,17 @@ void QCBUILTIN PF_digest_hex (pubprogfuncs_t *prinst, struct globalvars_s *pr_gl digestsize = 16; Com_BlockFullChecksum(str, strlen(str), digest); } + //md5? else if (!strcmp(hashtype, "SHA1")) { digestsize = SHA1(digest, sizeof(digest), str, strlen(str)); } +// else if (!strcmp(hashtype, "SHA256")) +// { +// digestsize = SHA2(digest, sizeof(digest), str, strlen(str)); +// } + //sha384 + //sha512 else if (!strcmp(hashtype, "CRC16")) { digestsize = 2; diff --git a/engine/common/q1bsp.c b/engine/common/q1bsp.c index d7d5d394..99b3f55a 100644 --- a/engine/common/q1bsp.c +++ b/engine/common/q1bsp.c @@ -1741,10 +1741,8 @@ Server only functions #ifndef CLIENTONLY //does the recursive work of Q1BSP_FatPVS -static void SV_Q1BSP_AddToFatPVS (model_t *mod, vec3_t org, mnode_t *node, qbyte *buffer, unsigned int buffersize) +static void SV_Q1BSP_AddToFatPVS (model_t *mod, vec3_t org, mnode_t *node, pvsbuffer_t *pvsbuffer) { - int i; - qbyte *pvs; mplane_t *plane; float d; @@ -1755,9 +1753,7 @@ static void SV_Q1BSP_AddToFatPVS (model_t *mod, vec3_t org, mnode_t *node, qbyte { if (node->contents != Q1CONTENTS_SOLID) { - pvs = Q1BSP_LeafPVS (mod, (mleaf_t *)node, NULL, 0); - for (i=0; ichildren[1]; else { // go down both - SV_Q1BSP_AddToFatPVS (mod, org, node->children[0], buffer, buffersize); + SV_Q1BSP_AddToFatPVS (mod, org, node->children[0], pvsbuffer); node = node->children[1]; } } @@ -1784,15 +1780,14 @@ Calculates a PVS that is the inclusive or of all leafs within 8 pixels of the given point. ============= */ -static unsigned int Q1BSP_FatPVS (model_t *mod, vec3_t org, qbyte *pvsbuffer, unsigned int buffersize, qboolean add) +static unsigned int Q1BSP_FatPVS (model_t *mod, vec3_t org, pvsbuffer_t *pvsbuffer, qboolean add) { - unsigned int fatbytes = (mod->numleafs+31)>>3; - if (fatbytes > buffersize) - Sys_Error("map had too much pvs data (too many leaves)\n");; + if (pvsbuffer->buffersize < mod->pvsbytes) + pvsbuffer->buffer = BZ_Realloc(pvsbuffer->buffer, pvsbuffer->buffersize=mod->pvsbytes); if (!add) - Q_memset (pvsbuffer, 0, fatbytes); - SV_Q1BSP_AddToFatPVS (mod, org, mod->nodes, pvsbuffer, fatbytes); - return fatbytes; + Q_memset (pvsbuffer->buffer, 0, mod->pvsbytes); + SV_Q1BSP_AddToFatPVS (mod, org, mod->nodes, pvsbuffer); + return mod->pvsbytes; } #endif @@ -1879,7 +1874,7 @@ PVS type stuff Mod_DecompressVis =================== */ -static qbyte *Q1BSP_DecompressVis (qbyte *in, model_t *model, qbyte *decompressed, unsigned int buffersize) +static qbyte *Q1BSP_DecompressVis (qbyte *in, model_t *model, qbyte *decompressed, unsigned int buffersize, qboolean merge) { int c; qbyte *out; @@ -1891,9 +1886,6 @@ static qbyte *Q1BSP_DecompressVis (qbyte *in, model_t *model, qbyte *decompresse if (buffersize < row) row = buffersize; -#if 0 - memcpy (out, in, row); -#else if (!in) { // no vis info, so make all visible while (row) @@ -1904,63 +1896,115 @@ static qbyte *Q1BSP_DecompressVis (qbyte *in, model_t *model, qbyte *decompresse return decompressed; } - do + if (merge) { - if (*in) + do { - *out++ = *in++; - continue; - } + if (*in) + { + *out++ |= *in++; + continue; + } + out += in[1]; + in += 2; + } while (out - decompressed < row); + } + else + { + do + { + if (*in) + { + *out++ = *in++; + continue; + } - c = in[1]; - in += 2; - while (c) - { - *out++ = 0; - c--; - } - } while (out - decompressed < row); -#endif + c = in[1]; + in += 2; + while (c) + { + *out++ = 0; + c--; + } + } while (out - decompressed < row); + } return decompressed; } -static FTE_ALIGN(4) qbyte mod_novis[MAX_MAP_LEAFS/8]; +static pvsbuffer_t mod_novis; +static pvsbuffer_t mod_tempvis; -qbyte *Q1BSP_LeafPVS (model_t *model, mleaf_t *leaf, qbyte *buffer, unsigned int buffersize) +qbyte *Q1BSP_LeafPVS (model_t *model, mleaf_t *leaf, pvsbuffer_t *buffer, qboolean merge) { - static FTE_ALIGN(4) qbyte decompressed[MAX_MAP_LEAFS/8]; - if (leaf == model->leafs) - return mod_novis; - - if (!buffer) { - buffer = decompressed; - buffersize = sizeof(decompressed); + if (mod_novis.buffersize < model->pvsbytes) + { + mod_novis.buffer = BZ_Realloc(mod_novis.buffer, mod_novis.buffersize=model->pvsbytes); + memset(mod_novis.buffer, 0xff, mod_novis.buffersize); + } + return mod_novis.buffer; } - return Q1BSP_DecompressVis (leaf->compressed_vis, model, buffer, buffersize); + if (!buffer) + buffer = &mod_tempvis; + + if (buffer->buffersize < model->pvsbytes) + buffer->buffer = BZ_Realloc(buffer->buffer, buffer->buffersize=model->pvsbytes); + + return Q1BSP_DecompressVis (leaf->compressed_vis, model, buffer->buffer, buffer->buffersize, merge); } //pvs is 1-based. clusters are 0-based. otherwise, q1bsp has a 1:1 mapping. -static qbyte *Q1BSP_ClusterPVS (model_t *model, int cluster, qbyte *buffer, unsigned int buffersize) +static qbyte *Q1BSP_ClusterPVS (model_t *model, int cluster, pvsbuffer_t *buffer, pvsmerge_t merge) { - static FTE_ALIGN(4) qbyte decompressed[MAX_MAP_LEAFS/8]; - if (cluster == -1) - return mod_novis; + { + if (merge == PVM_FAST) + { + if (mod_novis.buffersize < model->pvsbytes) + { + mod_novis.buffer = BZ_Realloc(mod_novis.buffer, mod_novis.buffersize=model->pvsbytes); + memset(mod_novis.buffer, 0xff, mod_novis.buffersize); + } + return mod_novis.buffer; + } + if (buffer->buffersize < model->pvsbytes) + buffer->buffer = BZ_Realloc(buffer->buffer, buffer->buffersize=model->pvsbytes); + memset(buffer->buffer, 0xff, model->pvsbytes); + return buffer->buffer; + } cluster++; - if (!buffer) - { - buffer = decompressed; - buffersize = sizeof(decompressed); - } + if (merge == PVM_FAST && model->pvs) + return model->pvs + cluster * model->pvsbytes; - return Q1BSP_DecompressVis (model->leafs[cluster].compressed_vis, model, buffer, buffersize); + if (!buffer) + buffer = &mod_tempvis; + + if (buffer->buffersize < model->pvsbytes) + buffer->buffer = BZ_Realloc(buffer->buffer, buffer->buffersize=model->pvsbytes); + + return Q1BSP_DecompressVis (model->leafs[cluster].compressed_vis, model, buffer->buffer, buffer->buffersize, merge==PVM_MERGE); } +/*static qbyte *Q1BSP_ClusterPHS (model_t *model, int cluster, pvsbuffer_t *buffer) +{ + if (cluster == -1 || !model->phs) + { //without any phs info, this turns into a broadcast. + if (mod_novis.buffersize < model->pvsbytes) + { + mod_novis.buffer = BZ_Realloc(mod_novis.buffer, mod_novis.buffersize=model->pvsbytes); + memset(mod_novis.buffer, 0xff, mod_novis.buffersize); + } + return mod_novis.buffer; + } + cluster++; + + return model->phs + cluster * model->pvsbytes; +}*/ + //returns the leaf number, which is used as a bit index into the pvs. static int Q1BSP_LeafnumForPoint (model_t *model, vec3_t p) { @@ -2039,7 +2083,6 @@ Init stuff void Q1BSP_Init(void) { - memset (mod_novis, 0xff, sizeof(mod_novis)); } //sets up the functions a server needs. @@ -2057,6 +2100,7 @@ void Q1BSP_SetModelFuncs(model_t *mod) mod->funcs.ClusterForPoint = Q1BSP_ClusterForPoint; mod->funcs.ClusterPVS = Q1BSP_ClusterPVS; +// mod->funcs.ClusterPHS = Q1BSP_ClusterPHS; mod->funcs.NativeTrace = Q1BSP_Trace; mod->funcs.PointContents = Q1BSP_PointContents; } diff --git a/engine/common/world.h b/engine/common/world.h index 2c3f772c..4f737bb9 100644 --- a/engine/common/world.h +++ b/engine/common/world.h @@ -312,7 +312,7 @@ int VARGS WorldQ2_AreaEdicts (world_t *w, vec3_t mins, vec3_t maxs, q2edict_t ** trace_t WorldQ2_Move (world_t *w, vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, int hitcontentsmask, q2edict_t *passedict); #endif #if defined(Q2BSPS) || defined(Q3BSPS) -unsigned int Q23BSP_FatPVS (model_t *mod, vec3_t org, qbyte *buffer, unsigned int buffersize, qboolean add); +unsigned int Q23BSP_FatPVS(model_t *mod, vec3_t org, pvsbuffer_t *buffer, qboolean merge); qboolean Q23BSP_EdictInFatPVS(model_t *mod, struct pvscache_s *ent, qbyte *pvs); void Q23BSP_FindTouchedLeafs(model_t *mod, struct pvscache_s *ent, float *mins, float *maxs); #endif diff --git a/engine/d3d/vid_d3d.c b/engine/d3d/vid_d3d.c index 89f3aaae..15e9022b 100644 --- a/engine/d3d/vid_d3d.c +++ b/engine/d3d/vid_d3d.c @@ -273,6 +273,10 @@ static LRESULT WINAPI D3D9_WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA // keep Alt-Space from happening break; + case WM_APPCOMMAND: + lRet = INS_AppCommand(lParam); + break; + // this is complicated because Win32 seems to pack multiple mouse events into // one update sometimes, so we always check all states and look for events case WM_LBUTTONDOWN: diff --git a/engine/d3d/vid_d3d11.c b/engine/d3d/vid_d3d11.c index 3ef4068b..c09b413c 100644 --- a/engine/d3d/vid_d3d11.c +++ b/engine/d3d/vid_d3d11.c @@ -411,6 +411,10 @@ static LRESULT WINAPI D3D11_WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPAR INS_TranslateKeyEvent (wParam, lParam, false, 0, false); break; + case WM_APPCOMMAND: + lRet = INS_AppCommand(lParam); + break; + case WM_SYSCHAR: // keep Alt-Space from happening break; diff --git a/engine/d3d/vid_d3d8.c b/engine/d3d/vid_d3d8.c index fdb64f30..40ee276f 100644 --- a/engine/d3d/vid_d3d8.c +++ b/engine/d3d/vid_d3d8.c @@ -277,6 +277,10 @@ static LRESULT WINAPI D3D8_WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA // keep Alt-Space from happening break; + case WM_APPCOMMAND: + lRet = INS_AppCommand(lParam); + break; + // this is complicated because Win32 seems to pack multiple mouse events into // one update sometimes, so we always check all states and look for events case WM_LBUTTONDOWN: diff --git a/engine/dotnet2005/emscripten.vcproj b/engine/dotnet2005/emscripten.vcproj index ee9ac30d..0748e570 100644 --- a/engine/dotnet2005/emscripten.vcproj +++ b/engine/dotnet2005/emscripten.vcproj @@ -23,7 +23,7 @@ > -#else - #include -#endif - #include "com_mesh.h" #if defined(RTLIGHTS) diff --git a/engine/gl/gl_backend.c b/engine/gl/gl_backend.c index cb4b28f3..c4bd1c96 100644 --- a/engine/gl/gl_backend.c +++ b/engine/gl/gl_backend.c @@ -10,11 +10,6 @@ void DumpGLState(void); #include "glquake.h" #include "shader.h" -#ifdef _WIN32 -#include -#else -#include -#endif #ifdef FORCESTATE #pragma warningmsg("FORCESTATE is active") diff --git a/engine/gl/gl_heightmap.c b/engine/gl/gl_heightmap.c index 0c83df4f..b80094fa 100644 --- a/engine/gl/gl_heightmap.c +++ b/engine/gl/gl_heightmap.c @@ -4243,10 +4243,13 @@ typedef struct int id; int min[3], max[3]; } hmpvsent_t; -unsigned int Heightmap_FatPVS (model_t *mod, vec3_t org, qbyte *pvsbuffer, unsigned int pvssize, qboolean add) +unsigned int Heightmap_FatPVS (model_t *mod, vec3_t org, pvsbuffer_t *pvsbuffer, qboolean add) { //embed the org onto the pvs - hmpvs_t *hmpvs = (hmpvs_t*)pvsbuffer; + hmpvs_t *hmpvs; + if (pvsbuffer->buffersize < sizeof(*hmpvs)) + pvsbuffer->buffer = BZ_Realloc(pvsbuffer->buffer, pvsbuffer->buffersize=sizeof(*hmpvs)); + hmpvs = (hmpvs_t*)pvsbuffer->buffer; hmpvs->id = 0xdeadbeef; VectorCopy(org, hmpvs->pos); return sizeof(*hmpvs); @@ -4306,7 +4309,7 @@ void Heightmap_MarkLights (dlight_t *light, int bit, mnode_t *node) { } -qbyte *Heightmap_ClusterPVS (model_t *model, int num, qbyte *buffer, unsigned int buffersize) +qbyte *Heightmap_ClusterPVS (model_t *model, int num, pvsbuffer_t *buffer, pvsmerge_t merge) { return NULL; // static qbyte heightmappvs = 255; @@ -6085,13 +6088,6 @@ static qboolean Terr_Brush_DeleteId(heightmap_t *hm, unsigned int brushid) return false; } - -#if defined(_WIN32) || defined(__DJGPP__) - #include -#else - #include -#endif - static void Brush_Serialise(sizebuf_t *sb, brushes_t *br) { unsigned int i; @@ -7160,6 +7156,7 @@ qboolean Terr_ReformEntitiesLump(model_t *mod, heightmap_t *hm, char *entities) submod->funcs.FatPVS = Heightmap_FatPVS; #endif submod->loadstate = MLS_LOADED; + submod->pvsbytes = sizeof(hmpvs_t); #ifdef RUNTIMELIGHTING subhm->relightcontext = LightStartup(hm->relightcontext, submod, false, false); @@ -7477,6 +7474,7 @@ qboolean QDECL Terr_LoadTerrainModel (model_t *mod, void *buffer, size_t bufsize mod->hulls[2].funcs.HullPointContents = Heightmap_PointContents; mod->hulls[3].funcs.HullPointContents = Heightmap_PointContents; */ + mod->pvsbytes = sizeof(hmpvs_t); mod->terrain = hm; diff --git a/engine/gl/gl_model.c b/engine/gl/gl_model.c index 66e11695..49368981 100644 --- a/engine/gl/gl_model.c +++ b/engine/gl/gl_model.c @@ -4014,9 +4014,9 @@ static qboolean Mod_LoadLeafs (model_t *loadmodel, qbyte *mod_base, lump_t *l, i return false; } count = len / sizeof(*in); - if (count > MAX_MAP_LEAFS) + if (count > SANITY_MAX_MAP_LEAFS) { - Con_Printf (CON_ERROR "Mod_LoadLeafs: %s has more than %i leafs\n",loadmodel->name, MAX_MAP_LEAFS); + Con_Printf (CON_ERROR "Mod_LoadLeafs: %s has more than %i leafs\n",loadmodel->name, SANITY_MAX_MAP_LEAFS); return false; } out = ZG_Malloc(&loadmodel->memgroup, count*sizeof(*out)); @@ -4024,6 +4024,7 @@ static qboolean Mod_LoadLeafs (model_t *loadmodel, qbyte *mod_base, lump_t *l, i loadmodel->leafs = out; loadmodel->numleafs = count; loadmodel->numclusters = count-1; + loadmodel->pvsbytes = ((loadmodel->numclusters+31)>>3)&~3; for ( i=0 ; i MAX_MAP_LEAFS) + if (count > SANITY_MAX_MAP_LEAFS) { - Con_Printf (CON_ERROR "Mod_LoadLeafs: %s has more than %i leafs\n",loadmodel->name, MAX_MAP_LEAFS); + Con_Printf (CON_ERROR "Mod_LoadLeafs: %s has more than %i leafs\n",loadmodel->name, SANITY_MAX_MAP_LEAFS); return false; } out = ZG_Malloc(&loadmodel->memgroup, count*sizeof(*out)); @@ -4087,6 +4088,7 @@ static qboolean Mod_LoadLeafs (model_t *loadmodel, qbyte *mod_base, lump_t *l, i loadmodel->leafs = out; loadmodel->numleafs = count; loadmodel->numclusters = count-1; + loadmodel->pvsbytes = ((loadmodel->numclusters+31)>>3)&~3; for ( i=0 ; i MAX_MAP_LEAFS) + if (count > SANITY_MAX_MAP_LEAFS) { - Con_Printf (CON_ERROR "Mod_LoadLeafs: %s has more than %i leafs\n",loadmodel->name, MAX_MAP_LEAFS); + Con_Printf (CON_ERROR "Mod_LoadLeafs: %s has more than %i leafs\n",loadmodel->name, SANITY_MAX_MAP_LEAFS); return false; } out = ZG_Malloc(&loadmodel->memgroup, count*sizeof(*out)); @@ -4150,6 +4152,7 @@ static qboolean Mod_LoadLeafs (model_t *loadmodel, qbyte *mod_base, lump_t *l, i loadmodel->leafs = out; loadmodel->numleafs = count; loadmodel->numclusters = count-1; + loadmodel->pvsbytes = ((loadmodel->numclusters+31)>>3)&~3; for ( i=0 ; ikeynum ) + return &cl_visedicts[i]; + } + } + return NULL; +} static entity_t *R_NearestPortal(plane_t *plane) { int i; entity_t *best = NULL; float dist, bestd = 0; + //for q3-compat, portals on world scan for a visedict to use for their view. for (i = 0; i < cl_numvisedicts; i++) { @@ -913,7 +927,7 @@ void R_ObliqueNearClip(float *viewmat, mplane_t *wplane); void CL_DrawDebugPlane(float *normal, float dist, float r, float g, float b, qboolean enqueue); void GLR_DrawPortal(batch_t *batch, batch_t **blist, batch_t *depthmasklist[2], int portaltype) { - entity_t *view; + entity_t *view, *surfent; // GLdouble glplane[4]; plane_t plane, oplane; float vmat[16]; @@ -921,7 +935,7 @@ void GLR_DrawPortal(batch_t *batch, batch_t **blist, batch_t *depthmasklist[2], vec3_t r; int i; mesh_t *mesh = batch->mesh[batch->firstmesh]; - qbyte newvis[(MAX_MAP_LEAFS+7)/8]; + pvsbuffer_t newvis; float ivmat[16], trmat[16]; if (!mesh->xyz_array) @@ -1014,11 +1028,9 @@ void GLR_DrawPortal(batch_t *batch, batch_t **blist, batch_t *depthmasklist[2], int clust, i, j; float d; vec3_t point; - int pvsbytes = (cl.worldmodel->numclusters+7)>>3; - if (pvsbytes > sizeof(newvis)) - pvsbytes = sizeof(newvis); r_refdef.forcevis = true; r_refdef.forcedvis = NULL; + newvis.buffer = alloca(newvis.buffersize=cl.worldmodel->pvsbytes); for (i = batch->firstmesh; i < batch->meshes; i++) { mesh = batch->mesh[i]; @@ -1032,21 +1044,9 @@ void GLR_DrawPortal(batch_t *batch, batch_t **blist, batch_t *depthmasklist[2], clust = cl.worldmodel->funcs.ClusterForPoint(cl.worldmodel, point); if (i == batch->firstmesh) - r_refdef.forcedvis = cl.worldmodel->funcs.ClusterPVS(cl.worldmodel, clust, newvis, sizeof(newvis)); + r_refdef.forcedvis = cl.worldmodel->funcs.ClusterPVS(cl.worldmodel, clust, &newvis, PVM_REPLACE); else - { - if (r_refdef.forcedvis != newvis) - { - memcpy(newvis, r_refdef.forcedvis, pvsbytes); - } - r_refdef.forcedvis = cl.worldmodel->funcs.ClusterPVS(cl.worldmodel, clust, NULL, sizeof(newvis)); - - for (j = 0; j < pvsbytes; j+= 4) - { - *(int*)&newvis[j] |= *(int*)&r_refdef.forcedvis[j]; - } - r_refdef.forcedvis = newvis; - } + r_refdef.forcedvis = cl.worldmodel->funcs.ClusterPVS(cl.worldmodel, clust, &newvis, PVM_MERGE); } // memset(newvis, 0xff, pvsbytes); } @@ -1071,25 +1071,52 @@ void GLR_DrawPortal(batch_t *batch, batch_t **blist, batch_t *depthmasklist[2], if (Cvar_Get("temp_useplaneclip", "1", 0, "temp")->ival) portaltype = 1; //make sure the near clipplane is used. + break; } - else #endif - if (!(view = R_NearestPortal(&plane)) || VectorCompare(view->origin, view->oldorigin)) - { - //a portal with no portal entity, or a portal rentity with an origin equal to its oldorigin, is a mirror. -// r_refdef.flipcull ^= SHADER_CULL_FLIP; - R_MirrorMatrix(&plane); - Matrix4x4_CM_ModelViewMatrixFromAxis(vmat, vpn, vright, vup, r_refdef.vieworg); - - VectorCopy(mesh->xyz_array[0], r_refdef.pvsorigin); - for (i = 1; i < mesh->numvertexes; i++) - VectorAdd(r_refdef.pvsorigin, mesh->xyz_array[i], r_refdef.pvsorigin); - VectorScale(r_refdef.pvsorigin, 1.0/mesh->numvertexes, r_refdef.pvsorigin); - - portaltype = 1; - } + surfent = batch->ent; + if (batch->ent->keynum) + view = R_FindPortalCamera(batch->ent); else { + view = R_NearestPortal(&plane); + if (view) + { //for q3bsps where the portal surface is embedded in the bsp itself, we need an extra leyer of indirection. + entity_t *oc = R_FindPortalCamera(view); + if(oc) + { + surfent = view; + view = oc; + } + } + } + + if (view && view->rtype == RT_PORTALCAMERA) + { //q1-style portal, where the portal is defined via attachments + //the portal plane itself is assumed to be facing directly forwards from the entity that we're drawing, and with the same origin. + oplane = plane; + + TransformCoord(r_refdef.vieworg, surfent->axis, surfent->origin, view->axis, view->origin, r_refdef.vieworg); + TransformDir(vpn, surfent->axis, view->axis, vpn); + TransformDir(vright, surfent->axis, view->axis, vright); + TransformDir(vup, surfent->axis, view->axis, vup); + + //transform the old surface plane into the new view matrix + Matrix4_Invert(r_refdef.m_view, ivmat); + Matrix4x4_CM_ModelViewMatrixFromAxis(vmat, vpn, vright, vup, r_refdef.vieworg); + Matrix4_Multiply(ivmat, vmat, trmat); + plane.normal[0] = -(oplane.normal[0] * trmat[0] + oplane.normal[1] * trmat[1] + oplane.normal[2] * trmat[2]); + plane.normal[1] = -(oplane.normal[0] * trmat[4] + oplane.normal[1] * trmat[5] + oplane.normal[2] * trmat[6]); + plane.normal[2] = -(oplane.normal[0] * trmat[8] + oplane.normal[1] * trmat[9] + oplane.normal[2] * trmat[10]); + plane.dist = -oplane.dist + trmat[12]*oplane.normal[0] + trmat[13]*oplane.normal[1] + trmat[14]*oplane.normal[2]; + + portaltype = 1; //make sure the near clipplane is used. + break; + } + + //portal surfaces with the same origin+oldorigin are explicit mirrors, and skipped in this case. + if (view && view->rtype == RT_PORTALSURFACE && !VectorCompare(view->origin, view->oldorigin)) + { //q3-style portal, where a single entity provides orientation+two origins float d; vec3_t paxis[3], porigin, vaxis[3], vorg; void PerpendicularVector( vec3_t dst, const vec3_t src ); @@ -1146,7 +1173,20 @@ void GLR_DrawPortal(batch_t *batch, batch_t **blist, batch_t *depthmasklist[2], plane.dist = -oplane.dist + trmat[12]*oplane.normal[0] + trmat[13]*oplane.normal[1] + trmat[14]*oplane.normal[2]; portaltype = 1; } + break; } + //fixme: q3 gamecode has explicit mirrors. we 'should' just ignore the surface if we've not seen it yet. + + //a portal with no portal entity, or a portal rentity with an origin equal to its oldorigin, is a mirror. + R_MirrorMatrix(&plane); + Matrix4x4_CM_ModelViewMatrixFromAxis(vmat, vpn, vright, vup, r_refdef.vieworg); + + VectorCopy(mesh->xyz_array[0], r_refdef.pvsorigin); + for (i = 1; i < mesh->numvertexes; i++) + VectorAdd(r_refdef.pvsorigin, mesh->xyz_array[i], r_refdef.pvsorigin); + VectorScale(r_refdef.pvsorigin, 1.0/mesh->numvertexes, r_refdef.pvsorigin); + + portaltype = 1; break; } diff --git a/engine/gl/gl_shader.c b/engine/gl/gl_shader.c index 017bc610..a8fa6849 100644 --- a/engine/gl/gl_shader.c +++ b/engine/gl/gl_shader.c @@ -5516,7 +5516,14 @@ char *Shader_DefaultBSPWater(shader_t *s, const char *shortname) qboolean explicitalpha = false; cvar_t *alphavars[] = { &r_wateralpha, &r_lavaalpha, &r_slimealpha, &r_telealpha}; cvar_t *stylevars[] = { &r_waterstyle, &r_lavastyle, &r_slimestyle, &r_telestyle}; - if (!strncmp(shortname, "*lava", 5)) + + if (!strncmp(shortname, "*portal", 7)) + { + return "{\n" + "portal\n" + "}\n"; + } + else if (!strncmp(shortname, "*lava", 5)) type = 1; else if (!strncmp(shortname, "*slime", 6)) type = 2; @@ -5745,7 +5752,14 @@ void Shader_DefaultBSPQ2(const char *shortname, shader_t *s, const void *args) void Shader_DefaultBSPQ1(const char *shortname, shader_t *s, const void *args) { char *builtin = NULL; - if (r_mirroralpha.value < 1 && (!strcmp(shortname, "window02_1") || !strncmp(shortname, "mirror", 6))) + + if (!strcmp(shortname, "mirror_portal")) + { + builtin = "{\n" + "portal\n" + "}\n"; + } + else if (r_mirroralpha.value < 1 && (!strcmp(shortname, "window02_1") || !strncmp(shortname, "mirror", 6))) { if (r_mirroralpha.value < 0) { diff --git a/engine/gl/gl_shadow.c b/engine/gl/gl_shadow.c index 59125067..53a1b9cd 100644 --- a/engine/gl/gl_shadow.c +++ b/engine/gl/gl_shadow.c @@ -79,7 +79,7 @@ cvar_t r_sun_colour = CVARFD ("r_sun_colour", "0 0 0", CVAR_ARCHIVE, "Spec static void Sh_DrawEntLighting(dlight_t *light, vec3_t colour); -static qbyte lvisb[(MAX_MAP_LEAFS+7)>>3]; +static pvsbuffer_t lvisb; /* called on framebuffer resize. @@ -1423,7 +1423,7 @@ static struct shadowmesh_s *SHM_BuildShadowMesh(dlight_t *dl, unsigned char *lvi { int clus; clus = cl.worldmodel->funcs.ClusterForPoint(cl.worldmodel, dl->origin); - lvis = cl.worldmodel->funcs.ClusterPVS(cl.worldmodel, clus, lvisb, sizeof(lvisb)); + lvis = cl.worldmodel->funcs.ClusterPVS(cl.worldmodel, clus, &lvisb, PVM_FAST); } firstedge=0; @@ -2563,7 +2563,7 @@ qboolean Sh_GenerateShadowMap(dlight_t *l) { int clus; clus = cl.worldmodel->funcs.ClusterForPoint(cl.worldmodel, l->origin); - lvis = cl.worldmodel->funcs.ClusterPVS(cl.worldmodel, clus, lvisb, sizeof(lvisb)); + lvis = cl.worldmodel->funcs.ClusterPVS(cl.worldmodel, clus, &lvisb, PVM_FAST); //FIXME: surely we can use the phs for this? if (!Sh_VisOverlaps(lvis, vvis)) //The two viewing areas do not intersect. @@ -2655,7 +2655,7 @@ static void Sh_DrawShadowMapLight(dlight_t *l, vec3_t colour, vec3_t axis[3], qb { int clus; clus = cl.worldmodel->funcs.ClusterForPoint(cl.worldmodel, l->origin); - lvis = cl.worldmodel->funcs.ClusterPVS(cl.worldmodel, clus, lvisb, sizeof(lvisb)); + lvis = cl.worldmodel->funcs.ClusterPVS(cl.worldmodel, clus, &lvisb, PVM_FAST); //FIXME: surely we can use the phs for this? if (!Sh_VisOverlaps(lvis, vvis)) //The two viewing areas do not intersect. @@ -3044,7 +3044,7 @@ static qboolean Sh_DrawStencilLight(dlight_t *dl, vec3_t colour, vec3_t axis[3], else { clus = cl.worldmodel->funcs.ClusterForPoint(cl.worldmodel, dl->origin); - lvis = cl.worldmodel->funcs.ClusterPVS(cl.worldmodel, clus, lvisb, sizeof(lvisb)); + lvis = cl.worldmodel->funcs.ClusterPVS(cl.worldmodel, clus, &lvisb, PVM_FAST); if (!Sh_VisOverlaps(lvis, vvis)) //The two viewing areas do not intersect. { @@ -3274,7 +3274,7 @@ static void Sh_DrawShadowlessLight(dlight_t *dl, vec3_t colour, vec3_t axis[3], qbyte *lvis; clus = cl.worldmodel->funcs.ClusterForPoint(cl.worldmodel, dl->origin); - lvis = cl.worldmodel->funcs.ClusterPVS(cl.worldmodel, clus, lvisb, sizeof(lvisb)); + lvis = cl.worldmodel->funcs.ClusterPVS(cl.worldmodel, clus, &lvisb, PVM_FAST); SHM_BuildShadowMesh(dl, lvis, vvis, SMT_SHADOWLESS); @@ -3472,7 +3472,7 @@ void Sh_PreGenerateLights(void) shadowtype = SMT_STENCILVOLUME; leaf = cl.worldmodel->funcs.ClusterForPoint(cl.worldmodel, dl->origin); - lvis = cl.worldmodel->funcs.ClusterPVS(cl.worldmodel, leaf, lvisb, sizeof(lvisb)); + lvis = cl.worldmodel->funcs.ClusterPVS(cl.worldmodel, leaf, &lvisb, PVM_FAST); SHM_BuildShadowMesh(dl, lvis, NULL, shadowtype); continue; diff --git a/engine/gl/gl_vidnt.c b/engine/gl/gl_vidnt.c index 43cd66f4..6814301f 100644 --- a/engine/gl/gl_vidnt.c +++ b/engine/gl/gl_vidnt.c @@ -208,6 +208,7 @@ extern cvar_t vid_gl_context_forwardcompatible; extern cvar_t vid_gl_context_compatibility; extern cvar_t vid_gl_context_robustness; extern cvar_t vid_gl_context_selfreset; +extern cvar_t vid_gl_context_noerror; static dllhandle_t *hInstGL = NULL; static dllhandle_t *hInstwgl = NULL; @@ -233,22 +234,23 @@ static BOOL (WINAPI *qwglSwapIntervalEXT) (int); static BOOL (APIENTRY *qwglChoosePixelFormatARB)(HDC hdc, const int *piAttribIList, const FLOAT *pfAttribFList, UINT nMaxFormats, int* piFormats, UINT* nNumFormats); static HGLRC (APIENTRY *qwglCreateContextAttribsARB)(HDC hDC, HGLRC hShareContext, const int *attribList); -#define WGL_CONTEXT_MAJOR_VERSION_ARB 0x2091 -#define WGL_CONTEXT_MINOR_VERSION_ARB 0x2092 -#define WGL_CONTEXT_LAYER_PLANE_ARB 0x2093 -#define WGL_CONTEXT_FLAGS_ARB 0x2094 -#define WGL_CONTEXT_DEBUG_BIT_ARB 0x0001 -#define WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x0002 -#define WGL_CONTEXT_ROBUST_ACCESS_BIT_ARB 0x0004 /*WGL_ARB_create_context_robustness*/ -#define WGL_CONTEXT_PROFILE_MASK_ARB 0x9126 /*WGL_ARB_create_context_profile*/ -#define WGL_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001 -#define WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002 -#define WGL_CONTEXT_ES2_PROFILE_BIT_EXT 0x00000004 /*WGL_CONTEXT_ES2_PROFILE_BIT_EXT*/ -#define ERROR_INVALID_VERSION_ARB 0x2095 -#define ERROR_INVALID_PROFILE_ARB 0x2096 +#define WGL_CONTEXT_MAJOR_VERSION_ARB 0x2091 +#define WGL_CONTEXT_MINOR_VERSION_ARB 0x2092 +#define WGL_CONTEXT_LAYER_PLANE_ARB 0x2093 +#define WGL_CONTEXT_FLAGS_ARB 0x2094 +#define WGL_CONTEXT_DEBUG_BIT_ARB 0x0001 +#define WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x0002 +#define WGL_CONTEXT_ROBUST_ACCESS_BIT_ARB 0x0004 /*WGL_ARB_create_context_robustness*/ +#define WGL_CONTEXT_PROFILE_MASK_ARB 0x9126 /*WGL_ARB_create_context_profile*/ +#define WGL_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001 +#define WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002 +#define WGL_CONTEXT_ES2_PROFILE_BIT_EXT 0x00000004 /*WGL_CONTEXT_ES2_PROFILE_BIT_EXT*/ +#define ERROR_INVALID_VERSION_ARB 0x2095 +#define ERROR_INVALID_PROFILE_ARB 0x2096 #define WGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB 0x8256 /*WGL_ARB_create_context_robustness*/ #define WGL_NO_RESET_NOTIFICATION_ARB 0x8261 #define WGL_LOSE_CONTEXT_ON_RESET_ARB 0x8252 +#define WGL_CONTEXT_OPENGL_NO_ERROR_ARB 0x31B3 /*WGL_ARB_create_context_no_error*/ //pixel format stuff @@ -809,9 +811,9 @@ static qboolean Win32VK_CreateSurface(void) static void Win32VK_Present(struct vkframe *theframe) { // if (theframe) -// PostMessage(mainwindow, WM_USER+7, 0, (LPARAM)theframe); +// PostMessage(mainwindow, WM_USER_VKPRESENT, 0, (LPARAM)theframe); // else - SendMessage(mainwindow, WM_USER+7, 0, (LPARAM)theframe); + SendMessage(mainwindow, WM_USER_VKPRESENT, 0, (LPARAM)theframe); } #else #define Win32VK_Present NULL @@ -866,7 +868,7 @@ static qboolean Win32NVVK_CreateSurface(void) } static void Win32NVVK_Present(struct vkframe *theframe) { - SendMessage(mainwindow, WM_USER+8, 0, (LPARAM)theframe); + SendMessage(mainwindow, WM_USER_NVVKPRESENT, 0, (LPARAM)theframe); } static void Win32NVVK_DoPresent(struct vkframe *theframe) { @@ -1886,6 +1888,12 @@ qboolean VID_AttachGL (rendererstate_t *info) attribs[i++] = WGL_LOSE_CONTEXT_ON_RESET_ARB; } + if (vid_gl_context_noerror.ival && WGL_CheckExtension("WGL_ARB_create_context_no_error")) + { + attribs[i++] = WGL_CONTEXT_OPENGL_NO_ERROR_ARB; + attribs[i++] = !vid_gl_context_robustness.ival && !vid_gl_context_debug.ival; + } + /*only switch contexts if there's actually a point*/ if (i || !vid_gl_context_compatibility.ival || vid_gl_context_es.ival) { @@ -2730,6 +2738,10 @@ static LONG WINAPI GLMainWndProc ( INS_TranslateKeyEvent(wParam, lParam, false, 0, false); break; + case WM_APPCOMMAND: + lRet = INS_AppCommand(lParam); + break; + case WM_MOUSEACTIVATE: lRet = MA_ACTIVATEANDEAT; break; @@ -2815,19 +2827,19 @@ static LONG WINAPI GLMainWndProc ( break; #ifdef VKQUAKE - case WM_USER+7: + case WM_USER_VKPRESENT: VK_DoPresent((struct vkframe*)lParam); break; #endif #if defined(VKQUAKE) && defined(USE_WGL) - case WM_USER+8: + case WM_USER_NVVKPRESENT: Win32NVVK_DoPresent((struct vkframe*)lParam); break; #endif - case WM_USER+4: + case WM_USER_VIDSHUTDOWN: PostQuitMessage(0); break; - case WM_USER: + case WM_USER_SPEECHTOTEXT: #ifdef HAVE_SPEECHTOTEXT STT_Event(); #endif @@ -3236,7 +3248,7 @@ static qboolean NVVKVID_Init (rendererstate_t *info, unsigned char *palette) } rendererinfo_t nvvkrendererinfo = { - "Vulkan (nvidia workaround)", + "GL_NV_draw_vulkan_image", { "nvvk", }, diff --git a/engine/http/iwebiface.c b/engine/http/iwebiface.c index b84a44af..7f07c8f3 100644 --- a/engine/http/iwebiface.c +++ b/engine/http/iwebiface.c @@ -576,22 +576,29 @@ void IWebInit(void) } void IWebRun(void) { -#ifdef WEBSERVER - extern qboolean httpserverfailed, ftpserverfailed; - - FTP_ServerRun(ftpserver.ival!= 0, ftpserver_port.ival); - HTTP_ServerPoll(httpserver.ival!=0, httpserver_port.ival); - if (ftpserverfailed) +#ifdef FTPSERVER { - Con_Printf("FTP Server failed to load, setting %s to 0\n", ftpserver.name); - Cvar_SetValue(&ftpserver, 0); - ftpserverfailed = false; + extern qboolean ftpserverfailed; + FTP_ServerRun(ftpserver.ival!= 0, ftpserver_port.ival); + if (ftpserverfailed) + { + Con_Printf("FTP Server failed to load, setting %s to 0\n", ftpserver.name); + Cvar_SetValue(&ftpserver, 0); + ftpserverfailed = false; + } } - if (httpserverfailed) +#endif + +#ifdef WEBSERVER { - Con_Printf("HTTP Server failed to load, setting %s to 0\n", httpserver.name); - Cvar_SetValue(&httpserver, 0); - httpserverfailed = false; + extern qboolean httpserverfailed; + HTTP_ServerPoll(httpserver.ival!=0, httpserver_port.ival); + if (httpserverfailed) + { + Con_Printf("HTTP Server failed to load, setting %s to 0\n", httpserver.name); + Cvar_SetValue(&httpserver, 0); + httpserverfailed = false; + } } #endif } diff --git a/engine/qclib/qcc.h b/engine/qclib/qcc.h index 8755fd2d..26725abc 100644 --- a/engine/qclib/qcc.h +++ b/engine/qclib/qcc.h @@ -1113,3 +1113,17 @@ extern void *(*pHash_Get)(hashtable_t *table, const char *name); extern void *(*pHash_GetNext)(hashtable_t *table, const char *name, void *old); extern void *(*pHash_Add)(hashtable_t *table, const char *name, void *data, bucket_t *); extern void (*pHash_RemoveData)(hashtable_t *table, const char *name, void *data); + +typedef struct vfile_s +{ //when originally running from a .dat, we load up all the functions and work from those rather than actual files. + //(these get re-written into the resulting .dat) + struct vfile_s *next; + void *fdata; + size_t fsize; + size_t msize; + char name[1]; +} vfile_t; +vfile_t *QCC_FindVFile(const char *name); +vfile_t *QCC_AddVFile(const char *name, void *data, size_t size); +void QCC_CatVFile(vfile_t *, const char *fmt, ...); +void QCC_InsertVFile(vfile_t *, size_t pos, const char *fmt, ...); diff --git a/engine/qclib/qcc_pr_comp.c b/engine/qclib/qcc_pr_comp.c index 4fec7fe7..2bb49f08 100644 --- a/engine/qclib/qcc_pr_comp.c +++ b/engine/qclib/qcc_pr_comp.c @@ -5955,28 +5955,32 @@ QCC_sref_t QCC_PR_ParseFunctionCall (QCC_ref_t *funcref) //warning, the func cou } else + e = QCC_PR_RefExpression(¶mbuf[arg], TOP_PRIORITY, EXPR_DISALLOW_COMMA); + //with vectorcalls, we store the vector into the args as individual floats //this allows better reuse of vector constants. - //copy it into the offset now, because we can. - if (opt_vectorcalls && pr_token_type == tt_immediate && pr_immediate_type == type_vector && arg < MAX_PARMS) + //the immediate vector def will be discarded while linking, if its still unused. + if (opt_vectorcalls && e->cast == type_vector && e->type == REF_GLOBAL && !e->postinc && e->readonly) { - QCC_sref_t t = QCC_GetTemp(type_vector); - t.sym = &def_parms[arg]; - t.cast = type_float; - t.ofs = 0; - QCC_FreeTemp(QCC_PR_StatementFlags (&pr_opcodes[OP_STORE_F], QCC_MakeFloatConst(pr_immediate.vector[0]), t, NULL, 0)); - t.ofs = 1; - QCC_FreeTemp(QCC_PR_StatementFlags (&pr_opcodes[OP_STORE_F], QCC_MakeFloatConst(pr_immediate.vector[1]), t, NULL, 0)); - t.ofs = 2; - QCC_FreeTemp(QCC_PR_StatementFlags (&pr_opcodes[OP_STORE_F], QCC_MakeFloatConst(pr_immediate.vector[2]), t, NULL, 0)); + const QCC_eval_t *eval = QCC_SRef_EvalConst(e->base); + if (eval) + { + QCC_sref_t t = QCC_GetTemp(type_vector); + t.cast = type_float; + t.ofs = 0; + QCC_FreeTemp(QCC_PR_StatementFlags (&pr_opcodes[OP_STORE_F], QCC_MakeFloatConst(eval->vector[0]), t, NULL, STFL_PRESERVEB)); + t.ofs = 1; + QCC_FreeTemp(QCC_PR_StatementFlags (&pr_opcodes[OP_STORE_F], QCC_MakeFloatConst(eval->vector[1]), t, NULL, STFL_PRESERVEB)); + t.ofs = 2; + QCC_FreeTemp(QCC_PR_StatementFlags (&pr_opcodes[OP_STORE_F], QCC_MakeFloatConst(eval->vector[2]), t, NULL, STFL_PRESERVEB)); - t.ofs = 0; + t.ofs = 0; + QCC_FreeTemp(e->base); - QCC_PR_Lex(); - e = QCC_PR_BuildRef(¶mbuf[arg], REF_GLOBAL, t, nullsref, type_vector, true); + e = QCC_PR_BuildRef(¶mbuf[arg], REF_GLOBAL, t, nullsref, type_vector, true); + } } - else - e = QCC_PR_RefExpression(¶mbuf[arg], TOP_PRIORITY, EXPR_DISALLOW_COMMA); + if (p) { if (typecmp(e->cast, p)) @@ -7210,6 +7214,7 @@ QCC_ref_t *QCC_PR_ParseRefValue (QCC_ref_t *refbuf, QCC_type_t *assumeclass, pbo d = QCC_PR_ParseImmediate (); // d.sym->referenced = true; // return QCC_DefToRef(refbuf, d); + name = NULL; } else if (QCC_PR_CheckToken("[")) { @@ -7247,6 +7252,7 @@ QCC_ref_t *QCC_PR_ParseRefValue (QCC_ref_t *refbuf, QCC_type_t *assumeclass, pbo d = QCC_PR_GenerateVector(x,y,z); // d.sym->referenced = true; // return QCC_DefToRef(refbuf, d); + name = NULL; } else { @@ -7402,7 +7408,7 @@ QCC_ref_t *QCC_PR_ParseRefValue (QCC_ref_t *refbuf, QCC_type_t *assumeclass, pbo d.sym->referenced = true; //class code uses self as though it was 'this'. its a hack, but this is QC. - if (assumeclass && pr_classtype && !strcmp(name, "self")) + if (assumeclass && pr_classtype && name && !strcmp(name, "self")) { //use 'this' instead. QCC_sref_t t = QCC_PR_GetSRef(NULL, "this", pr_scope, false, 0, false); @@ -7640,6 +7646,20 @@ QCC_sref_t QCC_EvaluateCast(QCC_sref_t src, QCC_type_t *cast, pbool implicit) if (src.cast->type == ev_accessor) src.cast = src.cast->parentclass; + else if (flag_laxcasts) + { + if (implicit) + { + char typea[256]; + char typeb[256]; + TypeName(src.cast, typea, sizeof(typea)); + TypeName(cast, typeb, sizeof(typeb)); + QCC_PR_ParseWarning(0, "Implicit lax cast from %s to %s", typea, typeb); + } + r = src; + r.cast = cast; //decompilers suck + return r; + } else { char typea[256]; @@ -9971,7 +9991,7 @@ void QCC_PR_ParseStatement (void) { //optres_compound_jumps++; QCC_FreeTemp(e); - if ((!eval->_float) != wasuntil) + if ((!eval->_float) != wasuntil) QCC_FreeTemp(QCC_PR_Statement (&pr_opcodes[OP_GOTO], nullsref, nullsref, &patch1)); else patch1 = NULL; @@ -10211,7 +10231,7 @@ void QCC_PR_ParseStatement (void) statements[numstatements-1].op == OP_GOTO; //the last statement of the if was a return, so we don't need the goto at the end - if (lastwasreturn && opt_compound_jumps && !QCC_AStatementJumpsTo(numstatements, patch1-statements, numstatements)) + if (lastwasreturn && opt_compound_jumps && patch1 && !QCC_AStatementJumpsTo(numstatements, patch1-statements, numstatements)) { // QCC_PR_ParseWarning(0, "optimised the else"); optres_compound_jumps++; diff --git a/engine/qclib/qcc_pr_lex.c b/engine/qclib/qcc_pr_lex.c index 00cf26d6..27261995 100644 --- a/engine/qclib/qcc_pr_lex.c +++ b/engine/qclib/qcc_pr_lex.c @@ -780,7 +780,7 @@ pbool QCC_PR_Precompiler(void) QCC_PR_SkipToEndOfLine(false); - QCC_PR_ParseError(ERR_HASHERROR, "#Error: %s\n", msg); + QCC_PR_ParseError(ERR_HASHERROR, "#Error: %s", msg); } else if (!strncmp(directive, "warning", 7)) { @@ -1050,6 +1050,12 @@ pbool QCC_PR_Precompiler(void) } else if (!QC_strcasecmp(qcc_token, "COPYRIGHT")) { + char *e = strrchr(msg+1, '\"'); + if (*msg == '\"' && e && e != msg) + { //FIXME: handle \ns + memmove(msg, msg+1, e-(msg+1)); + msg[e-(msg+1)] = 0; + } if (strlen(msg) >= sizeof(QCC_copyright)) QCC_PR_ParseWarning(WARN_STRINGTOOLONG, "Copyright message is too long\n"); QC_strlcpy(QCC_copyright, msg, sizeof(QCC_copyright)-1); diff --git a/engine/qclib/qccgui.c b/engine/qclib/qccgui.c index c2140129..d34b5ae6 100644 --- a/engine/qclib/qccgui.c +++ b/engine/qclib/qccgui.c @@ -64,6 +64,7 @@ void AddSourceFile(const char *parentsrc, const char *filename); #define SC_EOL_CR 1 #define SC_EOL_LF 2 #define SCI_SETEOLMODE 2031 +#define SCI_SETTABWIDTH 2036 #define SCI_SETCODEPAGE 2037 #define SCI_MARKERDEFINE 2040 #define SCI_MARKERSETFORE 2041 @@ -343,14 +344,6 @@ static pbool QCC_RegSetValue(HKEY base, char *keyname, char *valuename, int type } */ -typedef struct vfile_s -{ //when originally running from a .dat, we load up all the functions and work from those rather than actual files. - //(these get re-written into the resulting .dat) - struct vfile_s *next; - void *fdata; - size_t fsize; - char name[1]; -} vfile_t; static vfile_t *qcc_vfiles; vfile_t *QCC_FindVFile(const char *name) { @@ -368,7 +361,7 @@ vfile_t *QCC_FindVFile(const char *name) } return NULL; } -pbool QCC_AddVFile(const char *name, void *data, size_t size) +vfile_t *QCC_AddVFile(const char *name, void *data, size_t size) { vfile_t *f = QCC_FindVFile(name); if (!f) @@ -382,8 +375,48 @@ pbool QCC_AddVFile(const char *name, void *data, size_t size) free(f->fdata); f->fdata = malloc(size); memcpy(f->fdata, data, size); - f->fsize = size; - return true; + f->fsize = f->msize = size; + return f; +} +void QCC_CatVFile(vfile_t *f, const char *fmt, ...) +{ + va_list argptr; + char msg[8192]; + size_t n; + + va_start (argptr,fmt); + QC_vsnprintf (msg,sizeof(msg)-1, fmt, argptr); + va_end (argptr); + + n = strlen(msg); + if (f->fsize+n > f->msize) + { + size_t msize = f->msize + n + 8192; + f->fdata = realloc(f->fdata, msize); + f->msize = msize; + } + memcpy((char*)f->fdata+f->fsize, msg, n); + f->fsize += n; +} +void QCC_InsertVFile(vfile_t *f, size_t pos, const char *fmt, ...) +{ + va_list argptr; + char msg[8192]; + size_t n; + va_start (argptr,fmt); + QC_vsnprintf (msg,sizeof(msg)-1, fmt, argptr); + va_end (argptr); + + n = strlen(msg); + if (f->fsize+n > f->msize) + { + size_t msize = f->msize + n + 8192; + f->fdata = realloc(f->fdata, msize); + f->msize = msize; + } + memmove((char*)f->fdata+pos+n, (char*)f->fdata+pos, f->fsize-pos); + f->fsize += n; + memcpy((char*)f->fdata+pos, msg, n); } void QCC_EnumerateFilesResult(const char *name, const void *compdata, size_t compsize, int method, size_t plainsize) @@ -617,7 +650,7 @@ pbool PDECL QCC_WriteFile (const char *name, void *data, int len) } if (QCC_FindVFile(name)) - return QCC_AddVFile(name, data, len); + return !!QCC_AddVFile(name, data, len); f = fopen(name, "wb"); if (!f) @@ -698,6 +731,7 @@ void GUIPrint(HWND wnd, char *msg); char finddef[256]; char greptext[256]; extern pbool fl_extramargins; +extern int fl_tabsize; extern char enginebinary[MAX_PATH]; extern char enginebasedir[MAX_PATH]; extern char enginecommandline[8192]; @@ -1278,8 +1312,9 @@ HWND CreateAnEditControl(HWND parent, pbool *scintillaokay) SendMessage(newc, SCI_AUTOCSETORDER, SC_ORDER_PERFORMSORT, 0); SendMessage(newc, SCI_AUTOCSETFILLUPS, 0, (LPARAM)".,[<>(*/+-=\t\n"); - //line numbers - SendMessage(newc, SCI_SETMARGINWIDTHN, 0, (LPARAM)fl_extramargins?40:0); + //Set up gui options. + SendMessage(newc, SCI_SETMARGINWIDTHN, 0, (LPARAM)fl_extramargins?40:0); //line numbers+folding + SendMessage(newc, SCI_SETTABWIDTH, fl_tabsize, 0); //tab size //add margin for breakpoints SendMessage(newc, SCI_SETMARGINMASKN, 1, (LPARAM)~SC_MASK_FOLDERS); @@ -1459,18 +1494,18 @@ HWND CreateAnEditControl(HWND parent, pbool *scintillaokay) fprintf(f, "%i\t%i\t%#x\n", SCI_STYLESETFORE, i, val); val = SendMessage(newc, SCI_STYLEGETBACK, i, 0); fprintf(f, "%i\t%i\t%#x\n", SCI_STYLESETBACK, i, val); - val = SendMessage(newc, SCI_STYLEGETUNDERLINE, i, 0); - fprintf(f, "%i\t%i\t%#x\n", SCI_STYLESETUNDERLINE, i, val); - val = SendMessage(newc, SCI_STYLEGETITALIC, i, 0); - fprintf(f, "%i\t%i\t%#x\n", SCI_STYLESETITALIC, i, val); val = SendMessage(newc, SCI_STYLEGETBOLD, i, 0); fprintf(f, "%i\t%i\t%#x\n", SCI_STYLESETBOLD, i, val); + val = SendMessage(newc, SCI_STYLEGETITALIC, i, 0); + fprintf(f, "%i\t%i\t%#x\n", SCI_STYLESETITALIC, i, val); val = SendMessage(newc, SCI_STYLEGETSIZE, i, 0); fprintf(f, "%i\t%i\t%#x\n", SCI_STYLESETSIZE, i, val); - val = SendMessage(newc, SCI_STYLEGETCASE, i, 0); - fprintf(f, "%i\t%i\t%#x\n", SCI_STYLESETCASE, i, val); val = SendMessage(newc, SCI_STYLEGETFONT, i, (LPARAM)buf); fprintf(f, "%i\t%i\t\"%s\"\n", SCI_STYLESETFONT, i, buf); + val = SendMessage(newc, SCI_STYLEGETUNDERLINE, i, 0); + fprintf(f, "%i\t%i\t%#x\n", SCI_STYLESETUNDERLINE, i, val); + val = SendMessage(newc, SCI_STYLEGETCASE, i, 0); + fprintf(f, "%i\t%i\t%#x\n", SCI_STYLESETCASE, i, val); } fclose(f); } @@ -1524,7 +1559,8 @@ enum { IDM_GOTODEF, IDM_RETURNDEF, IDM_OUTPUT_WINDOW, - IDM_SHOWLINENUMBERS, + IDM_UI_SHOWLINENUMBERS, + IDM_UI_TABSIZE, IDM_SAVE, IDM_RECOMPILE, IDM_FIND, @@ -1607,6 +1643,10 @@ void GenericMenu(WPARAM wParam) QueryOpenFile(); break; + case IDM_QUIT: + PostQuitMessage(0); + break; + case IDM_RECOMPILE: buttons[ID_COMPILE].washit = true; break; @@ -1619,7 +1659,7 @@ void GenericMenu(WPARAM wParam) break; case IDM_ABOUT: - MessageBox(NULL, "FTE QuakeC Compiler ("__DATE__" "__TIME__")\nWritten by Forethought Entertainment, whoever that is.\n\nIf you have problems with wordpad corrupting your qc files, try saving them using utf-16 encoding via notepad.", "About", 0); + MessageBox(NULL, "FTE QuakeC Compiler ("__DATE__" "__TIME__")\nWritten by Forethought Entertainment, whoever that is.\n\nIf you have problems with wordpad corrupting your qc files, try saving them using utf-16 encoding via notepad.\nDecompiler component derived from frikdec.", "About", 0); break; case IDM_CASCADE: @@ -1639,14 +1679,14 @@ void GenericMenu(WPARAM wParam) else SplitterFocus(outputbox, 64, 128); break; - case IDM_SHOWLINENUMBERS: + case IDM_UI_SHOWLINENUMBERS: { editor_t *ed; MENUITEMINFO mii = {sizeof(mii)}; fl_extramargins = !fl_extramargins; mii.fMask = MIIM_STATE; mii.fState = fl_extramargins?MFS_CHECKED:MFS_UNCHECKED; - SetMenuItemInfo(GetMenu(mainwindow), IDM_SHOWLINENUMBERS, FALSE, &mii); + SetMenuItemInfo(GetMenu(mainwindow), IDM_UI_SHOWLINENUMBERS, FALSE, &mii); for (ed = editors; ed; ed = ed->next) { @@ -1658,6 +1698,24 @@ void GenericMenu(WPARAM wParam) } } break; + case IDM_UI_TABSIZE: + { + editor_t *ed; + MENUITEMINFO mii = {sizeof(mii)}; + fl_tabsize = (fl_tabsize>4)?4:8; + mii.fMask = MIIM_STATE; + mii.fState = (fl_tabsize>4)?MFS_CHECKED:MFS_UNCHECKED; + SetMenuItemInfo(GetMenu(mainwindow), IDM_UI_TABSIZE, FALSE, &mii); + + for (ed = editors; ed; ed = ed->next) + { + if (ed->scintilla) + { + SendMessage(ed->editpane, SCI_SETTABWIDTH, fl_tabsize, 0); + } + } + } + break; case IDM_DEBUG_RUN: EditFile(NULL, -1, true); EngineGiveFocus(); @@ -5719,7 +5777,8 @@ static LRESULT CALLBACK MainWndProc(HWND hWnd,UINT message, AppendMenu(m, 0, IDM_GREP, "Grep for selection\tCtrl+G"); AppendMenu(m, 0, IDM_OPENDOCU, "Open selected file"); AppendMenu(m, 0, IDM_OUTPUT_WINDOW, "Show Output Window\tF6"); - AppendMenu(m, (fl_extramargins?MF_CHECKED:MF_UNCHECKED), IDM_SHOWLINENUMBERS, "Show Line Numbers"); + AppendMenu(m, (fl_extramargins?MF_CHECKED:MF_UNCHECKED), IDM_UI_SHOWLINENUMBERS, "Show Line Numbers"); + AppendMenu(m, ((fl_tabsize>4)?MF_CHECKED:MF_UNCHECKED), IDM_UI_TABSIZE, "Large Tabs"); AppendMenu(m, MF_SEPARATOR, 0, NULL); AppendMenu(m, 0, IDM_ENCODING_PRIVATEUSE, "Convert to UTF-8"); AppendMenu(m, 0, IDM_ENCODING_DEPRIVATEUSE, "Convert to Quake encoding"); @@ -6777,26 +6836,12 @@ void UpdateFileList(void) if (projecttree) { - int size; + size_t size; char *buffer; AddSourceFile(NULL, progssrcname); - f = fopen (progssrcname, "rb"); - if (!f) - return; - fseek(f, 0, SEEK_END); - size = ftell(f); - fseek(f, 0, SEEK_SET); - buffer = malloc(size+1); - if (!buffer) - { - fclose(f); - return; - } - buffer[size] = '\0'; - fread(buffer, 1, size, f); - fclose(f); + buffer = QCC_ReadFile(progssrcname, NULL, 0, &size); pr_file_p = QCC_COM_Parse(buffer); if (*qcc_token == '#') @@ -6917,9 +6962,9 @@ int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLin ofn.lStructSize = sizeof(ofn); ofn.hInstance = ghInstance; ofn.lpstrFile = filename; - ofn.lpstrTitle = "Please find progs.src"; + ofn.lpstrTitle = "Please find progs.src or progs.dat"; ofn.nMaxFile = sizeof(filename)-1; - ofn.lpstrFilter = "QuakeC source\0*.src\0All files\0*.*\0"; + ofn.lpstrFilter = "QuakeC Projects\0*.src;*.dat\0All files\0*.*\0"; memset(filename, 0, sizeof(filename)); GetCurrentDirectory(sizeof(oldpath)-1, oldpath); ofn.lpstrInitialDir = oldpath; @@ -6953,16 +6998,16 @@ int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLin resetprogssrc = true; - wndclass.style = 0; - wndclass.lpfnWndProc = MainWndProc; - wndclass.cbClsExtra = 0; - wndclass.cbWndExtra = 0; - wndclass.hInstance = ghInstance; - wndclass.hIcon = LoadIcon(ghInstance, IDI_ICON_FTEQCC); - wndclass.hCursor = LoadCursor (NULL,IDC_ARROW); + wndclass.style = 0; + wndclass.lpfnWndProc = MainWndProc; + wndclass.cbClsExtra = 0; + wndclass.cbWndExtra = 0; + wndclass.hInstance = ghInstance; + wndclass.hIcon = LoadIcon(ghInstance, IDI_ICON_FTEQCC); + wndclass.hCursor = LoadCursor (NULL,IDC_ARROW); wndclass.hbrBackground = (void *)COLOR_WINDOW; - wndclass.lpszMenuName = 0; - wndclass.lpszClassName = MDI_WINDOW_CLASS_NAME; + wndclass.lpszMenuName = 0; + wndclass.lpszClassName = MDI_WINDOW_CLASS_NAME; RegisterClass(&wndclass); accelerators = CreateAcceleratorTable(acceleratorlist, sizeof(acceleratorlist)/sizeof(acceleratorlist[0])); @@ -7032,7 +7077,23 @@ int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLin buf = malloc(size); fread(buf, 1, size, f); fclose(f); - QC_EnumerateFilesFromBlob(buf, size, QCC_EnumerateFilesResult); + if (!QC_EnumerateFilesFromBlob(buf, size, QCC_EnumerateFilesResult)) + { + char *c = ReadProgsCopyright(buf, size); + if (!c || !*c) + c = "COPYRIGHT OWNER NOT KNOWN"; //all work is AUTOMATICALLY copyrighted under the terms of the Berne Convention. It _IS_ copyrighted, even if there's no license etc included. Good luck guessing what rights you have. + if (MessageBox(mainwindow, va("The copyright message from this progs is\n%s\n\nPlease respect the wishes and legal rights of the person who created this.", c), "Copyright", MB_OKCANCEL|MB_DEFBUTTON2|MB_ICONSTOP) == IDOK) + { + CreateOutputWindow(true); + compilecb(); + DecompileProgsDat(progssrcname, buf, size); + if (SplitterGet(outputbox)) + { + SendMessage(outputbox, WM_SETREDRAW, TRUE, 0); + RedrawWindow(outputbox, NULL, NULL, RDW_ERASE | RDW_FRAME | RDW_INVALIDATE | RDW_ALLCHILDREN); + } + } + } free(buf); } strcpy(progssrcname, "progs.src"); diff --git a/engine/qclib/qccguistuff.c b/engine/qclib/qccguistuff.c index c8061900..9030bbc1 100644 --- a/engine/qclib/qccguistuff.c +++ b/engine/qclib/qccguistuff.c @@ -10,6 +10,7 @@ pbool fl_compileonstart; pbool fl_showall; pbool fl_log; pbool fl_extramargins; +int fl_tabsize; char parameters[16384]; char progssrcname[256]; @@ -244,6 +245,12 @@ static void GUI_WriteConfigLine(FILE *file, char *part1, char *part2, char *part } fputs("\n", file); } +static void GUI_WriteConfigInt(FILE *file, char *part1, int part2, char *desc) +{ + char buf[64]; + QC_snprintfz(buf, sizeof(buf), "%i", part2); + GUI_WriteConfigLine(file, part1, buf, NULL, desc); +} void GUI_SaveConfig(void) { FILE *file = fopen("fteqcc.ini", "wt"); @@ -276,6 +283,7 @@ void GUI_SaveConfig(void) GUI_WriteConfigLine(file, "srcfile", progssrcname, NULL, "The progs.src file to load to find ordering of other qc files."); GUI_WriteConfigLine(file, "src", progssrcdir, NULL, "Additional subdir to read qc files from. Typically blank (ie: the working directory)."); + GUI_WriteConfigInt (file, "tabsize", fl_tabsize, "Specifies the size of tabs in scintilla windows."); GUI_WriteConfigLine(file, "extramargins", fl_extramargins?"on":"off", NULL, "Enables line number and folding margins."); GUI_WriteConfigLine(file, "hexen2", fl_hexen2?"on":"off", NULL, "Enable the extra tweaks needed for compatibility with hexen2 engines."); GUI_WriteConfigLine(file, "extendedopcodes", fl_ftetarg?"on":"off", NULL, "Utilise an extended instruction set, providing support for pointers and faster arrays and other speedups."); @@ -324,6 +332,18 @@ static char *GUI_ParseInPlace(char **state) *state = end+1; return str; } +static int GUI_ParseIntInPlace(char **state, int defaultval) +{ + char *token = GUI_ParseInPlace(state); + if (!stricmp(token, "default")) + return defaultval; + else if (!stricmp(token, "on") || !stricmp(token, "true") || !stricmp(token, "yes")) + return 1; + else if (!stricmp(token, "off") || !stricmp(token, "false") || !stricmp(token, "no")) + return 0; + else + return atoi(token); +} static int GUI_ParseBooleanInPlace(char **state, int defaultval) { char *token = GUI_ParseInPlace(state); @@ -342,6 +362,10 @@ void GUI_LoadConfig(void) char *token, *str; FILE *file = fopen("fteqcc.ini", "rb"); int p; + //initialise gui-only stuff. + fl_compileonstart = false; + fl_extramargins = false; + fl_tabsize = 8; if (!file) return; fl_nondfltopts = false; @@ -405,6 +429,8 @@ void GUI_LoadConfig(void) else if (!stricmp(token, "showall")) fl_showall = GUI_ParseBooleanInPlace(&str, false); + else if (!stricmp(token, "tabsize")) + fl_tabsize = GUI_ParseIntInPlace(&str, false); else if (!stricmp(token, "extramargins")) fl_extramargins = GUI_ParseBooleanInPlace(&str, false); else if (!stricmp(token, "hexen2")) diff --git a/engine/qclib/qcd.h b/engine/qclib/qcd.h index 50fac10d..bebca2f4 100644 --- a/engine/qclib/qcd.h +++ b/engine/qclib/qcd.h @@ -1,9 +1,10 @@ pbool QC_decodeMethodSupported(int method); char *QC_decode(progfuncs_t *progfuncs, int complen, int len, int method, const char *info, char *buffer); int QC_encode(progfuncs_t *progfuncs, int len, int method, const char *in, int handle); -pbool QC_EnumerateFilesFromBlob(const void *blob, size_t blobsize, void (*cb)(const char *name, const void *compdata, size_t compsize, int method, size_t plainsize)); +int QC_EnumerateFilesFromBlob(const void *blob, size_t blobsize, void (*cb)(const char *name, const void *compdata, size_t compsize, int method, size_t plainsize)); int QC_encodecrc(int len, char *in); char *PDECL filefromprogs(pubprogfuncs_t *progfuncs, progsnum_t prnum, char *fname, size_t *size, char *buffer); char *filefromnewprogs(pubprogfuncs_t *progfuncs, char *prname, char *fname, size_t *size, char *buffer);//fixme - remove parm 1 +void DecompileProgsDat(char *name, void *buf, size_t bufsize); diff --git a/engine/qclib/qcd_main.c b/engine/qclib/qcd_main.c index addb448f..d9ac32eb 100644 --- a/engine/qclib/qcd_main.c +++ b/engine/qclib/qcd_main.c @@ -179,27 +179,28 @@ static int QC_ReadRawShort(const unsigned char *blob) { return (blob[0]<<0) | (blob[1]<<8); } -pbool QC_EnumerateFilesFromBlob(const void *blob, size_t blobsize, void (*cb)(const char *name, const void *compdata, size_t compsize, int method, size_t plainsize)) +int QC_EnumerateFilesFromBlob(const void *blob, size_t blobsize, void (*cb)(const char *name, const void *compdata, size_t compsize, int method, size_t plainsize)) { unsigned int cdentries; unsigned int cdlen; const unsigned char *eocd; const unsigned char *cd; int nl,el,cl; + int ret = 0; if (blobsize < 22) - return false; + return ret; eocd = blob; eocd += blobsize-22; if (QC_ReadRawInt(eocd+0) != 0x06054b50) - return false; + return ret; if (QC_ReadRawShort(eocd+4) || QC_ReadRawShort(eocd+6) || QC_ReadRawShort(eocd+20) || QC_ReadRawShort(eocd+8) != QC_ReadRawShort(eocd+10)) - return false; + return ret; cd = blob; cd += QC_ReadRawInt(eocd+16); cdlen = QC_ReadRawInt(eocd+12); cdentries = QC_ReadRawInt(eocd+10); if (cd+cdlen>=(const unsigned char*)blob+blobsize) - return false; + return ret; for(; cdentries --> 0; cd += 46 + nl+el+cl) @@ -246,9 +247,10 @@ pbool QC_EnumerateFilesFromBlob(const void *blob, size_t blobsize, void (*cb)(co QC_strlcpy(name, cd+46, (nl+1funcs.ClusterForPoint(sv.world.worldmodel, checkorg); - checkpvs = sv.world.worldmodel->funcs.ClusterPVS (sv.world.worldmodel, cluster, checkpvsbuffer, sizeof(checkpvsbuffer)); + checkpvs = sv.world.worldmodel->funcs.ClusterPVS (sv.world.worldmodel, cluster, &checkpvsbuffer, PVM_FAST); } return i; diff --git a/engine/server/sv_ents.c b/engine/server/sv_ents.c index 1cb0533d..2f34b8f1 100644 --- a/engine/server/sv_ents.c +++ b/engine/server/sv_ents.c @@ -34,7 +34,7 @@ typedef struct edict_t *ent[SV_PVS_CAMERAS]; //ents in this list are always sent, even if the server thinks that they are invisible. vec3_t org[SV_PVS_CAMERAS]; - qbyte pvs[(MAX_MAP_LEAFS+7)>>3]; + pvsbuffer_t pvs; } pvscamera_t; static void *AllocateBoneSpace(packet_entities_t *pack, unsigned char bonecount, unsigned int *allocationpos) @@ -68,12 +68,10 @@ int needcleanup; //int fatbytes; #if defined(Q2BSPS) || defined(Q3BSPS) -unsigned int SV_Q2BSP_FatPVS (model_t *mod, vec3_t org, qbyte *resultbuf, unsigned int buffersize, qboolean add) +unsigned int SV_Q2BSP_FatPVS (model_t *mod, vec3_t org, pvsbuffer_t *result, qboolean merge) { int leafs[64]; int i, j, count; - unsigned int longs; - qbyte *src; vec3_t mins, maxs; for (i=0 ; i<3 ; i++) @@ -86,41 +84,36 @@ unsigned int SV_Q2BSP_FatPVS (model_t *mod, vec3_t org, qbyte *resultbuf, unsig if (count < 1) Sys_Error ("SV_Q2FatPVS: count < 1"); - longs = CM_ClusterBytes(mod); - longs = (longs+(sizeof(longs)-1))/sizeof(longs); - // convert leafs to clusters for (i=0 ; ibuffersize < mod->pvsbytes) + result->buffer = BZ_Realloc(result->buffer, result->buffersize=mod->pvsbytes); if (count == 1 && leafs[0] == -1) - { - memset(resultbuf, 0xff, longs<<2); + { //if the only leaf is the outside then broadcast it. + memset(result->buffer, 0xff, mod->pvsbytes); i = count; } - else if (!add) - { - memcpy (resultbuf, CM_ClusterPVS(mod, leafs[0], NULL, 0), longs<<2); - i = 1; - } else - i = 0; - // or in all the other leaf bits - for ( ; ifuncs.ClusterPVS(mod, leafs[i++], result, PVM_REPLACE); + // or in all the other leaf bits + for ( ; ifuncs.ClusterPVS(mod, leafs[i], result, PVM_MERGE); + } } - return longs*sizeof(longs); + return mod->pvsbytes; } #endif @@ -1303,7 +1296,7 @@ static void SVFTE_WriteUpdate(unsigned int bits, entity_state_t *state, sizebuf_ if (bits & UF_TAGINFO) { MSG_WriteEntity(msg, state->tagentity); - MSG_WriteByte(msg, state->tagindex); + MSG_WriteByte(msg, state->tagindex&0xff); } if (bits & UF_LIGHT) { @@ -2691,7 +2684,7 @@ void SV_WritePlayersToClient (client_t *client, client_frame_t *frame, edict_t * continue; // ignore if not touching a PV leaf - if (cameras && !sv.world.worldmodel->funcs.EdictInFatPVS(sv.world.worldmodel, &ent->pvsinfo, cameras->pvs)) + if (cameras && !sv.world.worldmodel->funcs.EdictInFatPVS(sv.world.worldmodel, &ent->pvsinfo, cameras->pvs.buffer)) continue; if (!((int)clent->xv->dimension_see & ((int)ent->xv->dimension_seen | (int)ent->xv->dimension_ghost))) @@ -3116,13 +3109,13 @@ qboolean SV_GibFilter(edict_t *ent) #if defined(Q2BSPS) || defined(Q3BSPS) static int clientarea; -unsigned int Q23BSP_FatPVS(model_t *mod, vec3_t org, qbyte *buffer, unsigned int buffersize, qboolean add) +unsigned int Q23BSP_FatPVS(model_t *mod, vec3_t org, pvsbuffer_t *buffer, qboolean merge) {//fixme: this doesn't add areas int leafnum; leafnum = CM_PointLeafnum (mod, org); clientarea = CM_LeafArea (mod, leafnum); - return SV_Q2BSP_FatPVS (mod, org, buffer, buffersize, add); + return SV_Q2BSP_FatPVS (mod, org, buffer, merge); } qboolean Q23BSP_EdictInFatPVS(model_t *mod, pvscache_t *ent, qbyte *pvs) @@ -3719,13 +3712,13 @@ void SV_Snapshot_BuildQ1(client_t *client, packet_entities_t *pack, pvscamera_t } else { - if (!sv.world.worldmodel->funcs.EdictInFatPVS(sv.world.worldmodel, &((wedict_t*)tracecullent)->pvsinfo, cameras->pvs)) + if (!sv.world.worldmodel->funcs.EdictInFatPVS(sv.world.worldmodel, &((wedict_t*)tracecullent)->pvsinfo, cameras->pvs.buffer)) continue; } } else { - if (!sv.world.worldmodel->funcs.EdictInFatPVS(sv.world.worldmodel, &((wedict_t*)ent)->pvsinfo, cameras->pvs)) + if (!sv.world.worldmodel->funcs.EdictInFatPVS(sv.world.worldmodel, &((wedict_t*)ent)->pvsinfo, cameras->pvs.buffer)) continue; tracecullent = ent; } @@ -3892,7 +3885,7 @@ void SV_AddCameraEntity(pvscamera_t *cameras, edict_t *ent, vec3_t viewofs) else VectorCopy (ent->v->origin, org); - sv.world.worldmodel->funcs.FatPVS(sv.world.worldmodel, org, cameras->pvs, sizeof(cameras->pvs), cameras->numents!=0); + sv.world.worldmodel->funcs.FatPVS(sv.world.worldmodel, org, &cameras->pvs, cameras->numents!=0); if (cameras->numents < SV_PVS_CAMERAS) { cameras->ent[cameras->numents] = ent; @@ -3964,7 +3957,9 @@ void SV_WriteEntitiesToClient (client_t *client, sizebuf_t *msg, qboolean ignore packet_entities_t *pack; edict_t *clent; client_frame_t *frame; - pvscamera_t camerasbuf, *cameras = &camerasbuf; + pvscamera_t camerasbuf; + pvscamera_t *cameras = &camerasbuf; + cameras->pvs.buffer = alloca(cameras->pvs.buffersize=sv.world.worldmodel->pvsbytes); // this is the frame we are creating frame = &client->frameunion.frames[client->netchan.incoming_sequence & UPDATE_MASK]; diff --git a/engine/server/sv_init.c b/engine/server/sv_init.c index 758c0545..8b222d59 100644 --- a/engine/server/sv_init.c +++ b/engine/server/sv_init.c @@ -447,9 +447,10 @@ void SV_CalcPHS (void) int i, j, k, l, index, num; int bitbyte; unsigned *dest, *src; - qbyte *scan, *lf; + qbyte *scan, pvs; int count, vcount; model_t *model = sv.world.worldmodel; + pvsbuffer_t buf; if (model->pvs || model->fromgame == fg_quake2 || model->fromgame == fg_quake3) { @@ -457,35 +458,38 @@ void SV_CalcPHS (void) return; } + if (model->pvsbytes > 4096) + return; + //FIXME: this can take a significant time on some maps, and should ideally be pushed to a worker thread. num = model->numclusters; - rowwords = (num+31)>>5; - rowbytes = rowwords*4; + rowbytes = model->pvsbytes; + rowwords = rowbytes/sizeof(*dest); + buf.buffersize = model->pvsbytes; if (!sv_calcphs.ival || (sv_calcphs.ival == 2 && (rowbytes*num >= 0x100000 || (!deathmatch.ival && !coop.ival)))) { - model->pvs = ZG_Malloc(&model->memgroup, rowbytes*num); - scan = model->pvs; + pvs = NULL;/*ZG_Malloc(&model->memgroup, rowbytes*num); + scan = pvs; for (i=0 ; ifuncs.ClusterPVS(model, i, scan, rowbytes); - if (lf != scan) - memcpy (scan, lf, rowbytes); - } + buf.buffer = scan; + model->funcs.ClusterPVS(model, i, &buf, PVM_REPLACE); + }*/ Con_DPrintf("Skipping PHS\n"); + model->pvs = pvs; model->phs = NULL; return; } - model->pvs = ZG_Malloc(&model->memgroup, rowbytes*num); - scan = model->pvs; + pvs = ZG_Malloc(&model->memgroup, rowbytes*num); + scan = pvs; vcount = 0; for (i=0 ; ifuncs.ClusterPVS(model, i, scan, rowbytes); - if (lf != scan) - memcpy (scan, lf, rowbytes); + buf.buffer = scan; + model->funcs.ClusterPVS(model, i, &buf, PVM_REPLACE); if (i == 0) continue; for (j=0 ; jpvs = pvs; model->phs = ZG_Malloc (&model->memgroup, rowbytes*num); /*this routine takes an exponential amount of time, so cache it if its too big*/ @@ -523,7 +528,7 @@ void SV_CalcPHS (void) } count = 0; - scan = model->pvs; + scan = pvs; dest = (unsigned *)model->phs; for (i=0 ; i= num) continue; - src = (unsigned *)model->pvs + index*rowwords; + src = (unsigned *)pvs + index*rowwords; for (l=0 ; lstring) + var->ival = 1; //FIXME: change to 2 when better tested. + if (var->ival) - if (!DTLS_HasCertificate()) + { + if (!svs.sockets->dtlsfuncs) + svs.sockets->dtlsfuncs = DTLS_InitServer(); + if (!svs.sockets->dtlsfuncs) + { + if (var->ival >= 2) + Con_Printf("Unable to set %s to \"%s\", no DTLS certificate available.\n", var->name, var->string); var->ival = 0; //disable the cvar (internally) if we don't have a usable certificate. this allows us to default the cvar to enabled without it breaking otherwise. + } + } } #endif diff --git a/engine/server/sv_mvd.c b/engine/server/sv_mvd.c index 10f31b9b..92c222a0 100644 --- a/engine/server/sv_mvd.c +++ b/engine/server/sv_mvd.c @@ -233,7 +233,6 @@ enum qtvstatus_e }; int SV_MVD_GotQTVRequest(vfsfile_t *clientstream, char *headerstart, char *headerend, qtvpendingstate_t *p) { - unsigned short ushort_result; char *e; qboolean server = false; @@ -244,9 +243,10 @@ int SV_MVD_GotQTVRequest(vfsfile_t *clientstream, char *headerstart, char *heade enum { QTVAM_NONE, QTVAM_PLAIN, - QTVAM_CCITT, - QTVAM_MD4, - QTVAM_MD5, +// QTVAM_CCITT, //16bit = ddos it + QTVAM_MD4, //fucked +// QTVAM_MD5, //no hash implemented + QTVAM_SHA1, } authmethod = QTVAM_NONE; start = headerstart; @@ -319,12 +319,14 @@ int SV_MVD_GotQTVRequest(vfsfile_t *clientstream, char *headerstart, char *heade thisauth = QTVAM_PLAIN; else if (!strcmp(com_token, "PLAIN")) thisauth = QTVAM_PLAIN; - else if (!strcmp(com_token, "CCIT")) - thisauth = QTVAM_CCITT; +// else if (!strcmp(com_token, "CCIT")) +// thisauth = QTVAM_CCITT; else if (!strcmp(com_token, "MD4")) thisauth = QTVAM_MD4; -// else if (!strcmp(com_token, "MD5")) -// thisauth = QTVAM_MD5; +// else if (!strcmp(com_token, "MD5")) +// thisauth = QTVAM_MD5; + else if (!strcmp(com_token, "SHA1")) + thisauth = QTVAM_SHA1; else { thisauth = QTVAM_NONE; @@ -384,12 +386,15 @@ int SV_MVD_GotQTVRequest(vfsfile_t *clientstream, char *headerstart, char *heade case QTVAM_PLAIN: p->hasauthed = !strcmp(qtv_password.string, password); break; - case QTVAM_CCITT: - QCRC_Init(&ushort_result); - QCRC_AddBlock(&ushort_result, p->challenge, strlen(p->challenge)); - QCRC_AddBlock(&ushort_result, qtv_password.string, strlen(qtv_password.string)); - p->hasauthed = (ushort_result == strtoul(password, NULL, 0)); - break; + /*case QTVAM_CCITT: + { + unsigned short ushort_result; + QCRC_Init(&ushort_result); + QCRC_AddBlock(&ushort_result, p->challenge, strlen(p->challenge)); + QCRC_AddBlock(&ushort_result, qtv_password.string, strlen(qtv_password.string)); + p->hasauthed = (ushort_result == strtoul(password, NULL, 0)); + } + break;*/ case QTVAM_MD4: { char hash[512]; @@ -401,7 +406,18 @@ int SV_MVD_GotQTVRequest(vfsfile_t *clientstream, char *headerstart, char *heade p->hasauthed = !strcmp(password, hash); } break; - case QTVAM_MD5: + case QTVAM_SHA1: + { + char hash[512]; + int digest[5]; + + snprintf(hash, sizeof(hash), "%s%s", p->challenge, qtv_password.string); + SHA1((char*)digest, sizeof(digest), hash, strlen(hash)); + sprintf(hash, "%08X%08X%08X%08X%08X", digest[0], digest[1], digest[2], digest[3], digest[4]); + p->hasauthed = !strcmp(password, hash); + } + break; +// case QTVAM_MD5: default: e = ("QTVSV 1\n" "PERROR: FTEQWSV bug detected.\n\n"); @@ -434,13 +450,13 @@ int SV_MVD_GotQTVRequest(vfsfile_t *clientstream, char *headerstart, char *heade if (0) { - case QTVAM_CCITT: + /*case QTVAM_CCITT: e = ("QTVSV 1\n" "AUTH: CCITT\n" "CHALLENGE: "); } else if (0) - { + {*/ case QTVAM_MD4: e = ("QTVSV 1\n" "AUTH: MD4\n" @@ -448,11 +464,18 @@ int SV_MVD_GotQTVRequest(vfsfile_t *clientstream, char *headerstart, char *heade } else { - case QTVAM_MD5: + /*case QTVAM_MD5: e = ("QTVSV 1\n" "AUTH: MD5\n" "CHALLENGE: "); } + else + {*/ + case QTVAM_SHA1: + e = ("QTVSV 1\n" + "AUTH: SHA1\n" + "CHALLENGE: "); + } VFS_WRITE(clientstream, e, strlen(e)); VFS_WRITE(clientstream, p->challenge, strlen(p->challenge)); @@ -2752,7 +2775,7 @@ void SV_MVDInfo_f (void) - +#ifdef SERVER_DEMO_PLAYBACK void SV_MVDPlayNum_f(void) { char namebuf[MAX_QPATH]; @@ -2780,6 +2803,7 @@ void SV_MVDPlayNum_f(void) else Con_Printf("invalid demo num\n"); } +#endif @@ -2787,22 +2811,41 @@ void SV_MVDInit(void) { MVD_Init(); -#ifdef SERVERONLY //client command would conflict otherwise. - Cmd_AddCommand ("record", SV_MVD_Record_f); - Cmd_AddCommand ("stop", SV_MVDStop_f); + //names that conflict with the client and thus only exist in dedicated servers (and thus shouldn't be used by mods that want mvds). +#ifdef SERVERONLY + Cmd_AddCommand ("record", SV_MVD_Record_f); + Cmd_AddCommand ("stop", SV_MVDStop_f); //client version should still work for mvds too. #endif - Cmd_AddCommand ("cancel", SV_MVD_Cancel_f); - Cmd_AddCommand ("qtvreverse", SV_MVD_QTVReverse_f); - Cmd_AddCommand ("mvdrecord", SV_MVD_Record_f); - Cmd_AddCommand ("easyrecord", SV_MVDEasyRecord_f); - Cmd_AddCommand ("mvdstop", SV_MVDStop_f); - Cmd_AddCommand ("mvdcancel", SV_MVD_Cancel_f); - //Cmd_AddCommand ("mvdplaynum", SV_MVDPlayNum_f); - Cmd_AddCommand ("mvdlist", SV_MVDList_f); - Cmd_AddCommand ("demolist", SV_MVDList_f); - Cmd_AddCommand ("rmdemo", SV_MVDRemove_f); - Cmd_AddCommand ("rmdemonum", SV_MVDRemoveNum_f); + //these don't currently conflict, but hey... + Cmd_AddCommand ("cancel", SV_MVD_Cancel_f); + Cmd_AddCommand ("easyrecord", SV_MVDEasyRecord_f); + Cmd_AddCommand ("demolist", SV_MVDList_f); + Cmd_AddCommand ("rmdemo", SV_MVDRemove_f); + Cmd_AddCommand ("rmdemonum", SV_MVDRemoveNum_f); + //serverside only names that won't conflict (matching mvdsv) + Cmd_AddCommand ("sv_demorecord", SV_MVD_Record_f); + Cmd_AddCommand ("sv_demostop", SV_MVDStop_f); + Cmd_AddCommand ("sv_democancel", SV_MVD_Cancel_f); + Cmd_AddCommand ("sv_demoeasyrecord",SV_MVDEasyRecord_f); + Cmd_AddCommand ("sv_demolist", SV_MVDList_f); + Cmd_AddCommand ("sv_demoremove", SV_MVDRemove_f); + Cmd_AddCommand ("sv_demonumremove", SV_MVDRemoveNum_f); + + //old fte names to avoid conflicts. + Cmd_AddCommand ("mvdrecord", SV_MVD_Record_f); + Cmd_AddCommand ("mvdstop", SV_MVDStop_f); + Cmd_AddCommand ("mvdcancel", SV_MVD_Cancel_f); + Cmd_AddCommand ("mvdlist", SV_MVDList_f); +#ifdef SERVER_DEMO_PLAYBACK + Cmd_AddCommand ("mvdplaynum", SV_MVDPlayNum_f); +#endif + + Cmd_AddCommand ("sv_demoinfoadd", SV_MVDInfoAdd_f); + Cmd_AddCommand ("sv_demoinforemove",SV_MVDInfoRemove_f); + Cmd_AddCommand ("sv_demoinfo", SV_MVDInfo_f); + + Cmd_AddCommand ("qtvreverse", SV_MVD_QTVReverse_f); Cvar_Register(&qtv_maxstreams, "MVD Streaming"); Cvar_Register(&qtv_password, "MVD Streaming"); } diff --git a/engine/server/sv_send.c b/engine/server/sv_send.c index b864fb1a..1c3b7aa5 100644 --- a/engine/server/sv_send.c +++ b/engine/server/sv_send.c @@ -703,7 +703,7 @@ void SV_MulticastProtExt(vec3_t origin, multicast_t to, int dimension_mask, int case MULTICAST_PHS: leafnum = CM_PointLeafnum (sv.world.worldmodel, origin); cluster = CM_LeafCluster (sv.world.worldmodel, leafnum); - mask = CM_ClusterPHS (sv.world.worldmodel, cluster); + mask = CM_ClusterPHS (sv.world.worldmodel, cluster, NULL); break; case MULTICAST_PVS_R: @@ -711,7 +711,7 @@ void SV_MulticastProtExt(vec3_t origin, multicast_t to, int dimension_mask, int case MULTICAST_PVS: leafnum = CM_PointLeafnum (sv.world.worldmodel, origin); cluster = CM_LeafCluster (sv.world.worldmodel, leafnum); - mask = CM_ClusterPVS (sv.world.worldmodel, cluster, NULL, 0); + mask = CM_ClusterPVS (sv.world.worldmodel, cluster, NULL, PVM_FAST); break; case MULTICAST_ONE_R: @@ -868,7 +868,7 @@ void SV_MulticastProtExt(vec3_t origin, multicast_t to, int dimension_mask, int { cluster = sv.world.worldmodel->funcs.ClusterForPoint(sv.world.worldmodel, origin); if (cluster >= 0) - mask = sv.world.worldmodel->phs + cluster * 4*((sv.world.worldmodel->numclusters+31)>>5); + mask = sv.world.worldmodel->phs + cluster*sv.world.worldmodel->pvsbytes; else mask = NULL; } @@ -879,7 +879,7 @@ void SV_MulticastProtExt(vec3_t origin, multicast_t to, int dimension_mask, int case MULTICAST_PVS: cluster = sv.world.worldmodel->funcs.ClusterForPoint(sv.world.worldmodel, origin); if (cluster >= 0) - mask = sv.world.worldmodel->pvs + cluster * 4*((sv.world.worldmodel->numclusters+31)>>5); + mask = sv.world.worldmodel->funcs.ClusterPVS(sv.world.worldmodel, cluster, NULL, PVM_FAST); else mask = NULL; break; @@ -1102,7 +1102,7 @@ void SV_MulticastCB(vec3_t origin, multicast_t to, int dimension_mask, void (*ca { cluster = sv.world.worldmodel->funcs.ClusterForPoint(sv.world.worldmodel, origin); if (cluster >= 0) - mask = sv.world.worldmodel->phs + cluster * 4*((sv.world.worldmodel->numclusters+31)>>5); + mask = sv.world.worldmodel->phs + cluster * sv.world.worldmodel->pvsbytes; else mask = NULL; } @@ -1113,7 +1113,7 @@ void SV_MulticastCB(vec3_t origin, multicast_t to, int dimension_mask, void (*ca case MULTICAST_PVS: cluster = sv.world.worldmodel->funcs.ClusterForPoint(sv.world.worldmodel, origin); if (cluster >= 0) - mask = sv.world.worldmodel->pvs + cluster * 4*((sv.world.worldmodel->numclusters+31)>>5); + mask = sv.world.worldmodel->funcs.ClusterPVS(sv.world.worldmodel, cluster, NULL, PVM_FAST); else mask = NULL; break; diff --git a/engine/server/sv_user.c b/engine/server/sv_user.c index bd5147ab..c68cd85b 100644 --- a/engine/server/sv_user.c +++ b/engine/server/sv_user.c @@ -1602,12 +1602,12 @@ void SVQW_PreSpawn_f (void) if (host_client->prespawn_stage == PRESPAWN_MAPCHECK) { - check = COM_RemapMapChecksum(atoi(Cmd_Argv(3))); + check = atoi(Cmd_Argv(3)); // Con_DPrintf("Client check = %d\n", check); if (sv_mapcheck.value && check != sv.world.worldmodel->checksum && - check != COM_RemapMapChecksum(LittleLong(sv.world.worldmodel->checksum2))) + COM_RemapMapChecksum(sv.world.worldmodel, check) != COM_RemapMapChecksum(sv.world.worldmodel, LittleLong(sv.world.worldmodel->checksum2))) #ifdef SERVER_DEMO_PLAYBACK if (!sv.demofile || (sv.demofile && !sv.democausesreconnect)) //demo playing causes no check. If it's the return level, check anyway to avoid that loophole. #endif @@ -2098,7 +2098,10 @@ void SV_DarkPlacesDownloadChunk(client_t *cl, sizebuf_t *msg) size = 1024; //fixme if (size > msg->maxsize - msg->cursize) - size = msg->maxsize - msg->cursize - 16; + size = msg->maxsize - msg->cursize; + if (size <= 7) + return; //no space. + size -= 7; if (size > MAXDPDOWNLOADCHUNK) //don't clog it too much size = MAXDPDOWNLOADCHUNK; @@ -2124,6 +2127,7 @@ void SVDP_StartDownload_f(void) if (!host_client->download) return; host_client->downloadstarted = true; + host_client->downloadacked = true; } void SV_DarkPlacesDownloadAck(client_t *cl) @@ -3231,6 +3235,8 @@ void SV_BeginDownload_f(void) ClientReliableWrite_Long (host_client, -1); ClientReliableWrite_Long (host_client, DLERR_REDIRECTFILE); ClientReliableWrite_String (host_client, redirection); + if (ISNQCLIENT(host_client)) + host_client->send_message = true; return; } else if (result == DLERR_REDIRECTFILE && host_client->protocol == SCP_QUAKEWORLD) @@ -3240,6 +3246,8 @@ void SV_BeginDownload_f(void) char *s = va("download \"%s\"\n", redirection); ClientReliableWrite_Begin (host_client, svc_stufftext, 2+strlen(s)); ClientReliableWrite_String (host_client, s); + if (ISNQCLIENT(host_client)) + host_client->send_message = true; return; } #endif @@ -3305,6 +3313,8 @@ void SV_BeginDownload_f(void) ClientReliableWrite_Short (host_client, -1); ClientReliableWrite_Byte (host_client, 0); } + if (ISNQCLIENT(host_client)) + host_client->send_message = true; return; } @@ -6198,6 +6208,10 @@ static qboolean AddEntityToPmove(edict_t *player, edict_t *check) q1contents = Q1CONTENTS_LADDER; //legacy crap switch(q1contents) { + case Q1CONTENTS_SOLID: + pe->nonsolid = false; + pe->forcecontentsmask = FTECONTENTS_SOLID; + break; case Q1CONTENTS_WATER: pe->nonsolid = true; pe->forcecontentsmask = FTECONTENTS_WATER; @@ -7919,8 +7933,7 @@ void SVNQ_ReadClientMove (usercmd_t *move) move->buttons = bits; i = MSG_ReadByte (); - if (i) - move->impulse = i; + move->impulse = i; if (host_client->protocol == SCP_DARKPLACES6 || host_client->protocol == SCP_DARKPLACES7 || (host_client->fteprotocolextensions2 & PEXT2_PRYDONCURSOR)) { diff --git a/engine/server/svq2_ents.c b/engine/server/svq2_ents.c index 4ce09bad..83bc8c65 100644 --- a/engine/server/svq2_ents.c +++ b/engine/server/svq2_ents.c @@ -698,7 +698,7 @@ void SVQ2_BuildClientFrame (client_t *client) int l; int seat; int c_fullsend; - qbyte clientpvs[(MAX_MAP_LEAFS+7)>>3]; + pvsbuffer_t clientpvs; qbyte *clientphs = NULL; int seats; @@ -707,6 +707,8 @@ void SVQ2_BuildClientFrame (client_t *client) SVQ2_Ents_Init(); + clientpvs.buffer = alloca(clientpvs.buffersize=sv.world.worldmodel->pvsbytes); + #if 0 numprojs = 0; // no projectiles yet #endif @@ -748,8 +750,9 @@ void SVQ2_BuildClientFrame (client_t *client) // calculate the visible areas frame->areabytes = CM_WriteAreaBits (sv.world.worldmodel, frame->areabits, clientarea[seat], seat != 0); - sv.world.worldmodel->funcs.FatPVS(sv.world.worldmodel, org[seat], clientpvs, sizeof(clientpvs), seat!=0); - clientphs = CM_ClusterPHS (sv.world.worldmodel, clientcluster); + sv.world.worldmodel->funcs.FatPVS(sv.world.worldmodel, org[seat], &clientpvs, seat!=0); + if (seat==0) //FIXME + clientphs = CM_ClusterPHS (sv.world.worldmodel, clientcluster, NULL); frame->ps[seat] = clent[seat]->client->ps; if (sv.paused) @@ -809,7 +812,7 @@ void SVQ2_BuildClientFrame (client_t *client) if (ent->num_clusters == -1) { // too many leafs for individual check, go by headnode - if (!CM_HeadnodeVisible (sv.world.worldmodel, ent->headnode, clientpvs)) + if (!CM_HeadnodeVisible (sv.world.worldmodel, ent->headnode, clientpvs.buffer)) continue; c_fullsend++; } @@ -818,7 +821,7 @@ void SVQ2_BuildClientFrame (client_t *client) for (i=0 ; i < ent->num_clusters ; i++) { l = ent->clusternums[i]; - if (clientpvs[l >> 3] & (1 << (l&7) )) + if (clientpvs.buffer[l >> 3] & (1 << (l&7) )) break; } if (i == ent->num_clusters) diff --git a/engine/server/svq2_game.c b/engine/server/svq2_game.c index 39fac965..9f9bfd44 100644 --- a/engine/server/svq2_game.c +++ b/engine/server/svq2_game.c @@ -458,7 +458,7 @@ static qboolean VARGS PFQ2_inPVS (vec3_t p1, vec3_t p2) leafnum = CM_PointLeafnum (sv.world.worldmodel, p1); cluster = CM_LeafCluster (sv.world.worldmodel, leafnum); area1 = CM_LeafArea (sv.world.worldmodel, leafnum); - mask = CM_ClusterPVS (sv.world.worldmodel, cluster, NULL, 0); + mask = CM_ClusterPVS (sv.world.worldmodel, cluster, NULL, PVM_FAST); leafnum = CM_PointLeafnum (sv.world.worldmodel, p2); cluster = CM_LeafCluster (sv.world.worldmodel, leafnum); @@ -489,7 +489,7 @@ static qboolean VARGS PFQ2_inPHS (vec3_t p1, vec3_t p2) leafnum = CM_PointLeafnum (sv.world.worldmodel, p1); cluster = CM_LeafCluster (sv.world.worldmodel, leafnum); area1 = CM_LeafArea (sv.world.worldmodel, leafnum); - mask = CM_ClusterPHS (sv.world.worldmodel, cluster); + mask = CM_ClusterPHS (sv.world.worldmodel, cluster, NULL); leafnum = CM_PointLeafnum (sv.world.worldmodel, p2); cluster = CM_LeafCluster (sv.world.worldmodel, leafnum); diff --git a/engine/server/svq3_game.c b/engine/server/svq3_game.c index 4387e730..dc3baf27 100644 --- a/engine/server/svq3_game.c +++ b/engine/server/svq3_game.c @@ -2234,6 +2234,7 @@ static qboolean SVQ3_EntityIsVisible(q3client_frame_t *snap, q3sharedEntity_t *e return true; } +#ifdef Q3OVERQW static q3playerState_t *SVQ3Q1_BuildPlayerState(client_t *client) { static q3playerState_t state; @@ -2286,6 +2287,7 @@ static q3playerState_t *SVQ3Q1_BuildPlayerState(client_t *client) state.ammo[4] = client->edict->v->ammo_cells; return &state; } +#endif void SVQ3_BuildClientSnapshot( client_t *client ) { @@ -2298,7 +2300,7 @@ void SVQ3_BuildClientSnapshot( client_t *client ) q3playerState_t *ps; int portalarea; int i; - static qbyte pvsbuffer[(MAX_MAP_LEAFS+7)>>3]; + static pvsbuffer_t pvsbuffer; if (!q3_snapshot_entities) { @@ -2308,16 +2310,18 @@ void SVQ3_BuildClientSnapshot( client_t *client ) } clientNum = client - svs.clients; - if (svs.gametype == GT_QUAKE3) - { - clent = GENTITY_FOR_NUM( clientNum ); - ps = PS_FOR_NUM( clientNum ); - } - else +#ifdef Q3OVERQW + if (svs.gametype != GT_QUAKE3) { clent = NULL; ps = SVQ3Q1_BuildPlayerState(client); } + else +#endif + { + clent = GENTITY_FOR_NUM( clientNum ); + ps = PS_FOR_NUM( clientNum ); + } // this is the frame we are creating snap = &client->frameunion.q3frames[client->netchan.outgoing_sequence & Q3UPDATE_MASK]; @@ -2342,7 +2346,7 @@ void SVQ3_BuildClientSnapshot( client_t *client ) org[2] += ps->viewheight; clientarea = CM_PointLeafnum(sv.world.worldmodel, org); - bitvector = sv.world.worldmodel->funcs.ClusterPVS(sv.world.worldmodel, CM_LeafCluster(sv.world.worldmodel, clientarea), pvsbuffer, sizeof(pvsbuffer)); + bitvector = sv.world.worldmodel->funcs.ClusterPVS(sv.world.worldmodel, CM_LeafCluster(sv.world.worldmodel, clientarea), &pvsbuffer, PVM_REPLACE); clientarea = CM_LeafArea(sv.world.worldmodel, clientarea); /* if (client->areanum != clientarea) @@ -2367,7 +2371,6 @@ void SVQ3_BuildClientSnapshot( client_t *client ) // check for SVF_PORTAL entities first for( i=0 ; is.origin2); //merge pvs bits so we can see other ents through it - merge = sv.world.worldmodel->funcs.ClusterPVS(sv.world.worldmodel, CM_LeafCluster(sv.world.worldmodel, portalarea), NULL, 0); - c = (sv.world.worldmodel->numclusters+31)/32; - while (c-->0) - ((int *)bitvector)[c] |= ((int *)merge)[c]; + merge = sv.world.worldmodel->funcs.ClusterPVS(sv.world.worldmodel, CM_LeafCluster(sv.world.worldmodel, portalarea), &pvsbuffer, PVM_MERGE); //and merge areas, so we can see the world too (client will calc its own pvs) portalarea = CM_LeafArea(sv.world.worldmodel, portalarea); CM_WriteAreaBits(sv.world.worldmodel, snap->areabits, portalarea, true); diff --git a/engine/sw/sw_vidwin.c b/engine/sw/sw_vidwin.c index 4e356193..ee67d6ed 100644 --- a/engine/sw/sw_vidwin.c +++ b/engine/sw/sw_vidwin.c @@ -495,6 +495,10 @@ LONG WINAPI MainWndProc ( INS_TranslateKeyEvent(wParam, lParam, false, 0, false); break; + case WM_APPCOMMAND: + lRet = INS_AppCommand(lParam); + break; + // this is complicated because Win32 seems to pack multiple mouse events into // one update sometimes, so we always check all states and look for events case WM_LBUTTONDOWN: diff --git a/engine/vk/vk_backend.c b/engine/vk/vk_backend.c index 1570bf0a..981243c4 100644 --- a/engine/vk/vk_backend.c +++ b/engine/vk/vk_backend.c @@ -5173,7 +5173,7 @@ static void R_DrawPortal(batch_t *batch, batch_t **blist, batch_t *depthmasklist vec3_t r; int i; mesh_t *mesh = batch->mesh[batch->firstmesh]; - qbyte newvis[(MAX_MAP_LEAFS+7)/8]; + pvsbuffer_t newvis; float ivmat[16], trmat[16]; if (r_refdef.recurse >= R_MAX_RECURSE-1) @@ -5260,11 +5260,9 @@ static void R_DrawPortal(batch_t *batch, batch_t **blist, batch_t *depthmasklist int clust, i, j; float d; vec3_t point; - int pvsbytes = (cl.worldmodel->numclusters+7)>>3; - if (pvsbytes > sizeof(newvis)) - pvsbytes = sizeof(newvis); r_refdef.forcevis = true; r_refdef.forcedvis = NULL; + newvis.buffer = alloca(newvis.buffersize=cl.worldmodel->pvsbytes); for (i = batch->firstmesh; i < batch->meshes; i++) { mesh = batch->mesh[i]; @@ -5278,21 +5276,9 @@ static void R_DrawPortal(batch_t *batch, batch_t **blist, batch_t *depthmasklist clust = cl.worldmodel->funcs.ClusterForPoint(cl.worldmodel, point); if (i == batch->firstmesh) - r_refdef.forcedvis = cl.worldmodel->funcs.ClusterPVS(cl.worldmodel, clust, newvis, sizeof(newvis)); + r_refdef.forcedvis = cl.worldmodel->funcs.ClusterPVS(cl.worldmodel, clust, &newvis, PVM_REPLACE); else - { - if (r_refdef.forcedvis != newvis) - { - memcpy(newvis, r_refdef.forcedvis, pvsbytes); - } - r_refdef.forcedvis = cl.worldmodel->funcs.ClusterPVS(cl.worldmodel, clust, NULL, sizeof(newvis)); - - for (j = 0; j < pvsbytes; j+= 4) - { - *(int*)&newvis[j] |= *(int*)&r_refdef.forcedvis[j]; - } - r_refdef.forcedvis = newvis; - } + r_refdef.forcedvis = cl.worldmodel->funcs.ClusterPVS(cl.worldmodel, clust, &newvis, PVM_MERGE); } // memset(newvis, 0xff, pvsbytes); } diff --git a/fteqtv/source.c b/fteqtv/source.c index cc80278c..338b5b76 100644 --- a/fteqtv/source.c +++ b/fteqtv/source.c @@ -31,8 +31,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. //AUTH: specifies an auth method, the exact specs varies based on the method // PLAIN: the password is sent as a PASSWORD line // MD4: the server responds with an "AUTH: MD4\n" line as well as a "CHALLENGE: somerandomchallengestring\n" line, the client sends a new 'initial' request with CHALLENGE: MD4\nRESPONSE: hexbasedmd4checksumhere\n" -// MD5: same as md4 -// CCITT: same as md4, but using the CRC stuff common to all quake engines. +// etc: same idea as md4 +// CCITT: same as md4, but using the CRC stuff common to all quake engines. should not be used. // if the supported/allowed auth methods don't match, the connection is silently dropped. //SOURCE: which stream to play from, DEFAULT is special. Without qualifiers, it's assumed to be a tcp address. //COMPRESSION: Suggests a compression method (multiple are allowed). You'll get a COMPRESSION response, and compression will begin with the binary data. @@ -416,7 +416,7 @@ void Net_SendQTVConnectionRequest(sv_t *qtv, char *authmethod, char *challenge) str = qtv->connectpassword; Net_QueueUpstream(qtv, strlen(str), str); str = "\"\n"; Net_QueueUpstream(qtv, strlen(str), str); } - else if (challenge && strlen(challenge)>=32 && !strcmp(authmethod, "CCITT")) + /*else if (challenge && strlen(challenge)>=32 && !strcmp(authmethod, "CCITT")) { unsigned short crcvalue; str = "AUTH: CCITT\n"; Net_QueueUpstream(qtv, strlen(str), str); @@ -428,7 +428,7 @@ void Net_SendQTVConnectionRequest(sv_t *qtv, char *authmethod, char *challenge) str = hash; Net_QueueUpstream(qtv, strlen(str), str); str = "\"\n"; Net_QueueUpstream(qtv, strlen(str), str); - } + }*/ else if (challenge && strlen(challenge)>=8 && !strcmp(authmethod, "MD4")) { unsigned int md4sum[4]; @@ -442,6 +442,19 @@ void Net_SendQTVConnectionRequest(sv_t *qtv, char *authmethod, char *challenge) str = hash; Net_QueueUpstream(qtv, strlen(str), str); str = "\"\n"; Net_QueueUpstream(qtv, strlen(str), str); } + else if (challenge && strlen(challenge)>=8 && !strcmp(authmethod, "SHA1")) + { + unsigned int digest[5]; + str = "AUTH: SHA1\n"; Net_QueueUpstream(qtv, strlen(str), str); + str = "PASSWORD: \""; Net_QueueUpstream(qtv, strlen(str), str); + + snprintf(hash, sizeof(hash), "%s%s", challenge, qtv->connectpassword); + SHA1((unsigned char*)digest, sizeof(digest), hash, strlen(hash)); + sprintf(hash, "%08X%08X%8X%08X%08X", digest[0], digest[1], digest[2], digest[3], digest[4]); + + str = hash; Net_QueueUpstream(qtv, strlen(str), str); + str = "\"\n"; Net_QueueUpstream(qtv, strlen(str), str); + } else if (!strcmp(authmethod, "NONE")) { str = "AUTH: NONE\n"; Net_QueueUpstream(qtv, strlen(str), str); @@ -457,8 +470,9 @@ void Net_SendQTVConnectionRequest(sv_t *qtv, char *authmethod, char *challenge) } else { + str = "AUTH: SHA1\n"; Net_QueueUpstream(qtv, strlen(str), str); str = "AUTH: MD4\n"; Net_QueueUpstream(qtv, strlen(str), str); - str = "AUTH: CCITT\n"; Net_QueueUpstream(qtv, strlen(str), str); +// str = "AUTH: CCITT\n"; Net_QueueUpstream(qtv, strlen(str), str); str = "AUTH: PLAIN\n"; Net_QueueUpstream(qtv, strlen(str), str); str = "AUTH: NONE\n"; Net_QueueUpstream(qtv, strlen(str), str); } diff --git a/plugins/ezhud/ezquakeisms.c b/plugins/ezhud/ezquakeisms.c index 34e87d36..35cfcddc 100644 --- a/plugins/ezhud/ezquakeisms.c +++ b/plugins/ezhud/ezquakeisms.c @@ -680,7 +680,7 @@ qintptr_t EZHud_Draw(qintptr_t *args) return true; } -int keydown[256]; +int keydown[K_MAX]; float cursor_x; float cursor_y; float mouse_x; @@ -708,11 +708,13 @@ qintptr_t EZHud_MenuEvent(qintptr_t *args) mouse_y = 0; break; case 1: - keydown[param] = true; + if (param < K_MAX) + keydown[param] = true; HUD_Editor_Key(param, 0, true); break; case 2: - keydown[param] = false; + if (param < K_MAX) + keydown[param] = false; HUD_Editor_Key(param, 0, false); break; } diff --git a/plugins/irc/ircclient.c b/plugins/irc/ircclient.c index f035936a..99a2b1d7 100644 --- a/plugins/irc/ircclient.c +++ b/plugins/irc/ircclient.c @@ -1242,10 +1242,12 @@ struct ircice_s *IRC_ICE_Create(ircclient_t *irc, const char *sender, enum icepr if (creator && type == ICEP_VOICE) { //note: the engine will ignore codecs it does not support. - piceapi->ICE_Set(ice, "codec96", "speex@16000"); //wide - piceapi->ICE_Set(ice, "codec97", "speex@8000"); //narrow - piceapi->ICE_Set(ice, "codec98", "speex@32000"); //ultrawide - piceapi->ICE_Set(ice, "codec99", "opus"); + piceapi->ICE_Set(ice, "codec96", "opus@48000"); + piceapi->ICE_Set(ice, "codec97", "speex@16000"); //wide + piceapi->ICE_Set(ice, "codec98", "speex@8000"); //narrow + piceapi->ICE_Set(ice, "codec99", "speex@32000"); //ultrawide + piceapi->ICE_Set(ice, "codec8", "pcma@8000"); + piceapi->ICE_Set(ice, "codec0", "pcmu@8000"); } //query dns to see if there's a stunserver hosted by the same domain @@ -1276,6 +1278,7 @@ struct ircice_s *IRC_ICE_Create(ircclient_t *irc, const char *sender, enum icepr } void IRC_ICE_Update(ircclient_t *irc, struct ircice_s *ice, char updatetype) { + //I was originally using colons to separate terms, but switched to slashes to avoid smilies for irc clients that print unknown CTCP messages. char message[1024]; struct icecandinfo_s *c; char *icetype; @@ -1307,28 +1310,33 @@ void IRC_ICE_Update(ircclient_t *irc, struct ircice_s *ice, char updatetype) piceapi->ICE_Get(ice->ice, "lufrag", ufrag, sizeof(ufrag)); piceapi->ICE_Get(ice->ice, "lpwd", pwd, sizeof(pwd)); - Q_snprintf(message, sizeof(message), " ufrag:%s pwd:%s", ufrag, pwd); + Q_snprintf(message, sizeof(message), " ufrag/%s pwd/%s", ufrag, pwd); } if (updatetype == '+' || updatetype == '=') { unsigned int i; - for (i = 96; i <= 127; i++) + for (i = 0; i <= 127; i++) { char codec[256]; char codecname[64]; char argn[64]; Q_snprintf(argn, sizeof(argn), "codec%i", i); - piceapi->ICE_Get(ice->ice, argn, codecname, sizeof(codecname)); + if (!piceapi->ICE_Get(ice->ice, argn, codecname, sizeof(codecname))) + continue; if (!strcmp(codecname, "speex@8000")) //speex narrowband - Q_snprintf(codec, sizeof(codec), "codec:%i:speex:8000", i); + Q_snprintf(codec, sizeof(codec), "codec/%i/speex/8000", i); else if (!strcmp(codecname, "speex@16000")) //speex wideband - Q_snprintf(codec, sizeof(codec), "codec:%i:speex:16000", i); + Q_snprintf(codec, sizeof(codec), "codec/%i/speex/16000", i); else if (!strcmp(codecname, "speex@32000")) //speex ultrawideband - Q_snprintf(codec, sizeof(codec), "codec:%i:speex:32000", i); - else if (!strcmp(codecname, "opus")) //opus codec. - Q_snprintf(codec, sizeof(codec), "codec:%i:opus:48000", i); + Q_snprintf(codec, sizeof(codec), "codec/%i/speex/32000", i); + else if (!strcmp(codecname, "pcma@8000")) //speex wideband + Q_snprintf(codec, sizeof(codec), "codec/%i/pcma/8000", i); + else if (!strcmp(codecname, "pcmu@8000")) //speex ultrawideband + Q_snprintf(codec, sizeof(codec), "codec/%i/pcmu/8000", i); + else if (!strcmp(codecname, "opus@48000")) //opus codec. + Q_snprintf(codec, sizeof(codec), "codec/%i/opus/48000", i); else continue; @@ -1356,10 +1364,10 @@ void IRC_ICE_Update(ircclient_t *irc, struct ircice_s *ice, char updatetype) { char type[] = "hspr"; char cand[256]; - Q_snprintf(cand, sizeof(cand), "cand:" - "%c%c:%i:%i:" - "%i:%i:%i:" - "%i:%s:%s", + Q_snprintf(cand, sizeof(cand), "cand/" + "%c%c/%i/%i/" + "%i/%i/%i/" + "%i/%s/%s", type[c->type], 'u', c->priority, c->port, c->network, c->generation, c->foundation, c->component, c->candidateid, c->addr); @@ -1394,13 +1402,13 @@ void IRC_ICE_ParseCandidate(struct icestate_s *ice, char *cand) case 'r': info.type = ICE_RELAY; break; } info.transport = (cand[6] == 't')?1:0; - info.priority = strtol(cand+8, &cand, 0); if (*cand != ':')return; - info.port = strtol(cand+1, &cand, 0); if (*cand != ':')return; - info.network = strtol(cand+1, &cand, 0); if (*cand != ':')return; - info.generation = strtol(cand+1, &cand, 0); if (*cand != ':')return; - info.foundation = strtol(cand+1, &cand, 0); if (*cand != ':')return; - info.component = strtol(cand+1, &cand, 0); if (*cand != ':')return; - addr = strchr(cand+1, ':'); + info.priority = strtol(cand+8, &cand, 0); if (*cand != '/')return; + info.port = strtol(cand+1, &cand, 0); if (*cand != '/')return; + info.network = strtol(cand+1, &cand, 0); if (*cand != '/')return; + info.generation = strtol(cand+1, &cand, 0); if (*cand != '/')return; + info.foundation = strtol(cand+1, &cand, 0); if (*cand != '/')return; + info.component = strtol(cand+1, &cand, 0); if (*cand != '/')return; + addr = strchr(cand+1, '/'); if (!addr) return; *addr++ = 0; @@ -1416,8 +1424,8 @@ void IRC_ICE_ParseCodec(struct icestate_s *ice, char *codec) unsigned int num; char name[64]; unsigned int rate; - num = strtoul(codec+6, &codec, 0); if (*codec != ':')return; - start = codec+1; codec = strchr(codec, ':'); if (!codec)return;*codec = 0; Q_strlcpy(name, start, sizeof(name)); + num = strtoul(codec+6, &codec, 0); if (*codec != '/')return; + start = codec+1; codec = strchr(codec, '/'); if (!codec)return;*codec = 0; Q_strlcpy(name, start, sizeof(name)); rate = strtoul(codec+1, &codec, 0); Q_strlcat(name, va("@%u", rate), sizeof(name)); @@ -1458,13 +1466,13 @@ void IRC_ICE_Parse(ircclient_t *irc, const char *sender, char *message) while(message) { message = COM_Parse(message, token, sizeof(token)); - if (!strncmp(token, "cand:", 5)) + if (!strncmp(token, "cand/", 5)) IRC_ICE_ParseCandidate(ice->ice, token); - else if (!strncmp(token, "codec:", 6)) + else if (!strncmp(token, "codec/", 6)) IRC_ICE_ParseCodec(ice->ice, token); - else if (!strncmp(token, "ufrag:", 6)) + else if (!strncmp(token, "ufrag/", 6)) piceapi->ICE_Set(ice->ice, "rufrag", token+6); - else if (!strncmp(token, "pwd:", 4)) + else if (!strncmp(token, "pwd/", 4)) piceapi->ICE_Set(ice->ice, "rpwd", token+4); else if (*token) IRC_Printf(irc, sender, "unknown ice token %s\n", token); @@ -2207,13 +2215,13 @@ int IRC_ClientFrame(ircclient_t *irc) { str = COM_Parse(str, token, sizeof(token)); if (*token == '@') //they're an operator - IRC_Printf(irc, channel, COLOURGREEN"@"COLORWHITE"%s\n", token+1); + IRC_Printf(irc, channel, "^[@"COLOURGREEN"%s\\act\\user\\who\\%s\\tip\\Channel Operator^]\n", token+1, token+1); else if (*token == '%') //they've got half-op - IRC_Printf(irc, channel, COLOURGREEN"%"COLORWHITE"%s\n", token+1); + IRC_Printf(irc, channel, "^[%%"COLOURGREEN"%s\\act\\user\\who\\%s\\tip\\Channel Half-Operator^]\n", token+1, token+1); else if (*token == '+') //they've got voice - IRC_Printf(irc, channel, COLOURGREEN"+"COLORWHITE"%s\n", token+1); + IRC_Printf(irc, channel, "^[+"COLOURGREEN"%s\\act\\user\\who\\%s\\tip\\Voice^]\n", token+1, token+1); else - IRC_Printf(irc, channel, " %s\n", token); + IRC_Printf(irc, channel, " ^["COLOURGREEN"%s\\act\\user\\who\\%s^]\n", token, token); } if (secret == 1) { diff --git a/plugins/jabber/jabberclient.c b/plugins/jabber/jabberclient.c index 2509ae5e..60aab569 100644 --- a/plugins/jabber/jabberclient.c +++ b/plugins/jabber/jabberclient.c @@ -1499,6 +1499,7 @@ qintptr_t JCL_ConsoleLink(qintptr_t *args) JCL_Info_ValueForKey(link, "xmppsid", what, sizeof(what)); if (jcl && jcl->status == JCL_ACTIVE) JCL_Join(jcl, who, what, true, ICEP_INVALID); + jclient_updatebuddylist = true; return true; } else if (!strcmp(what, "jdeny") && (jcl->enabledcapabilities & (CAP_VOICE|CAP_VIDEO|CAP_GAMEINVITE|CAP_GOOGLE_VOICE))) @@ -1506,30 +1507,35 @@ qintptr_t JCL_ConsoleLink(qintptr_t *args) JCL_Info_ValueForKey(link, "xmppsid", what, sizeof(what)); if (jcl && jcl->status == JCL_ACTIVE) JCL_Join(jcl, who, what, false, ICEP_INVALID); + jclient_updatebuddylist = true; return true; } else if (!strcmp(what, "join") && (jcl->enabledcapabilities & CAP_GAMEINVITE)) { if (jcl && jcl->status == JCL_ACTIVE) JCL_Join(jcl, who, NULL, true, ICEP_QWCLIENT); + jclient_updatebuddylist = true; return true; } else if (!strcmp(what, "invite") && (jcl->enabledcapabilities & CAP_GAMEINVITE)) { if (jcl && jcl->status == JCL_ACTIVE) JCL_Join(jcl, who, NULL, true, ICEP_QWSERVER); + jclient_updatebuddylist = true; return true; } else if (!strcmp(what, "call") && (jcl->enabledcapabilities & (CAP_VOICE|CAP_GOOGLE_VOICE))) { if (jcl && jcl->status == JCL_ACTIVE) JCL_Join(jcl, who, NULL, true, ICEP_VOICE); + jclient_updatebuddylist = true; return true; } else if (!strcmp(what, "vidcall") && (jcl->enabledcapabilities & (CAP_VIDEO))) { if (jcl && jcl->status == JCL_ACTIVE) JCL_Join(jcl, who, NULL, true, ICEP_VIDEO); + jclient_updatebuddylist = true; return true; } #endif @@ -1573,6 +1579,13 @@ qintptr_t JCL_ConsoleLink(qintptr_t *args) } } } + else if (!strcmp(what, "forgetacc")) + { + if (jcl) + { + JCL_CloseConnection(jcl, "", false); + } + } else if (!strcmp(what, "newaccount")) { pCon_SetConsoleFloat(BUDDYLISTTITLE, "linebuffered", true); @@ -1921,7 +1934,6 @@ qboolean JCL_Reconnect(jclient_t *jcl) jcl->outbufmax = 0; jcl->instreampos = 0; jcl->bufferedinammount = 0; - jcl->tagdepth = 0; Q_strlcpy(jcl->localalias, ">>", sizeof(jcl->localalias)); jcl->authmode = -1; @@ -1943,8 +1955,9 @@ qboolean JCL_Reconnect(jclient_t *jcl) } else { - Q_strncpyz(jcl->errormsg, "Unable to determine service", sizeof(jcl->errormsg)); - return false; + //SRV lookup failed. attempt to just use the domain directly. + Con_DPrintf("XMPP: Trying to connect to %s\n", jcl->domain); + jcl->socket = pNet_TCPConnect(jcl->domain, jcl->serverport); //port is only used if the url doesn't contain one. It's a default. } } else @@ -1967,6 +1980,7 @@ qboolean JCL_Reconnect(jclient_t *jcl) jcl->issecure = true; jcl->status = JCL_AUTHING; + jcl->connecting = true; JCL_AddClientMessageString(jcl, "" @@ -2731,24 +2745,39 @@ qboolean XMPP_NewGoogleMailsReply(jclient_t *jcl, xmltree_t *tree, struct iq_s * return true; } -static void JCL_RosterUpdate(jclient_t *jcl, xmltree_t *listp) +static void JCL_RosterUpdate(jclient_t *jcl, xmltree_t *listp, char *from) { xmltree_t *i; buddy_t *buddy; int cnum = 0; + char *at = strrchr(from, '@'); + if (at) + { + if (strlen(jcl->username) != at-from || strncasecmp(from, jcl->username, at-from)) + return; + from = at+1; + } + if (strcmp(from, jcl->domain)) + return; //ignore if from somewhere invalid + while ((i = XML_ChildOfTree(listp, "item", cnum++))) { char *name = XML_GetParameter(i, "name", ""); char *jid = XML_GetParameter(i, "jid", ""); -// char *sub = XML_GetParameter(i, "subscription", ""); + char *sub = XML_GetParameter(i, "subscription", "both"); + char *ask = XML_GetParameter(i, "ask", ""); JCL_FindBuddy(jcl, jid, &buddy, NULL, true); if (*name) Q_strlcpy(buddy->name, name, sizeof(buddy->name)); else buddy->vcardphotochanged = true; //try to query their actual name - buddy->friended = true; + if (strcasecmp(sub, "none")) + buddy->friended = true; + if (*ask) + buddy->askfriend = true; } + jclient_updatebuddylist = true; } static qboolean JCL_RosterReply(jclient_t *jcl, xmltree_t *tree, struct iq_s *iq) { @@ -2759,7 +2788,7 @@ static qboolean JCL_RosterReply(jclient_t *jcl, xmltree_t *tree, struct iq_s *iq c = XML_ChildOfTree(tree, "query", 0); if (c) { - JCL_RosterUpdate(jcl, c); + JCL_RosterUpdate(jcl, c, jcl->domain); return true; } return false; @@ -3363,10 +3392,10 @@ void JCL_ParseIQ(jclient_t *jcl, xmltree_t *tree) #endif c = XML_ChildOfTree(tree, "query", 0); - if (c && !strcmp(c->xmlns, "jabber:iq:roster") && !strcmp(from, jcl->domain)) + if (c && !strcmp(c->xmlns, "jabber:iq:roster")) { unparsable = false; - JCL_RosterUpdate(jcl, c); + JCL_RosterUpdate(jcl, c, from); } //google-specific - new mail notifications. @@ -3381,11 +3410,17 @@ void JCL_ParseIQ(jclient_t *jcl, xmltree_t *tree) #ifdef JINGLE c = XML_ChildOfTreeNS(tree, "urn:xmpp:jingle:1", "jingle", 0); if (c && (jcl->enabledcapabilities & (CAP_GAMEINVITE|CAP_VOICE|CAP_VIDEO))) + { unparsable = !JCL_ParseJingle(jcl, c, from, id); + jclient_updatebuddylist = true; + } #ifdef VOIP_LEGACY c = XML_ChildOfTreeNS(tree, "http://www.google.com/session", "session", 0); if (c && (jcl->enabledcapabilities & (CAP_GOOGLE_VOICE))) + { unparsable = !JCL_HandleGoogleSession(jcl, c, from, id); + jclient_updatebuddylist = true; + } #endif #endif @@ -4120,8 +4155,6 @@ int JCL_ClientFrame(jclient_t *jcl, char **error) int ret; qboolean unparsable; - int olddepth; - ret = pNet_Recv(jcl->socket, jcl->bufferedinmessage+jcl->bufferedinammount, sizeof(jcl->bufferedinmessage)-1 - jcl->bufferedinammount); if (ret == 0) { @@ -4143,8 +4176,6 @@ int JCL_ClientFrame(jclient_t *jcl, char **error) jcl->bufferedinmessage[jcl->bufferedinammount] = 0; } - olddepth = jcl->tagdepth; - //we never end parsing in the middle of a < > //this means we can filter out the , and < /> stuff properly for (pos = jcl->instreampos; pos < jcl->bufferedinammount; pos++) @@ -4158,7 +4189,7 @@ int JCL_ClientFrame(jclient_t *jcl, char **error) if (pos < 1) break; //erm... - if (jcl->bufferedinmessage[pos-1] != '/') // is a tag without a body +/* if (jcl->bufferedinmessage[pos-1] != '/') // is a tag without a body { if (jcl->bufferedinmessage[jcl->instreampos+1] != '?') // is a tag without a body { @@ -4171,20 +4202,19 @@ int JCL_ClientFrame(jclient_t *jcl, char **error) } } } - +*/ jcl->instreampos=pos+1; } } - if (jcl->tagdepth == 1 && olddepth == 0) + pos = 0; + while (jcl->connecting) { //first bit of info - - pos = 0; tree = XML_Parse(jcl->bufferedinmessage, &pos, jcl->instreampos, true, ""); - while (tree && !strcmp(tree->name, "?xml")) + if (tree && !strcmp(tree->name, "?xml")) { XML_Destroy(tree); - tree = XML_Parse(jcl->bufferedinmessage, &pos, jcl->instreampos, true, ""); + continue; } if (jcl->streamdebug == 2) @@ -4217,44 +4247,40 @@ int JCL_ClientFrame(jclient_t *jcl, char **error) // XML_ConPrintTree(ot, 0); XML_Destroy(ot); - if (!tree) - { - memmove(jcl->bufferedinmessage, jcl->bufferedinmessage+pos, jcl->bufferedinammount - (pos)); - jcl->bufferedinammount-=pos; - jcl->instreampos-=pos; - - return JCL_DONE; - } + jcl->connecting = false; } - else + +/* if (jcl->tagdepth != 1) { - if (jcl->tagdepth != 1) + if (jcl->tagdepth < 1 && jcl->bufferedinammount==jcl->instreampos) { - if (jcl->tagdepth < 1 && jcl->bufferedinammount==jcl->instreampos) - { - *error = "End of XML stream"; - return JCL_KILL; - } - return JCL_DONE; + *error = "End of XML stream"; + return JCL_KILL; } + return JCL_DONE; + } +*/ + tree = XML_Parse(jcl->bufferedinmessage, &pos, jcl->instreampos, false, jcl->defaultnamespace); + if (jcl->streamdebug == 2 && tree) + { + char t = jcl->bufferedinmessage[pos]; + jcl->bufferedinmessage[pos] = 0; + XMPP_ConversationPrintf("xmppin", "xmppin", jcl->bufferedinmessage); + XMPP_ConversationPrintf("xmppin", "xmppin", "\n"); + jcl->bufferedinmessage[pos] = t; + } + + if (!tree) + { + //make sure any prior crap is flushed. + memmove(jcl->bufferedinmessage, jcl->bufferedinmessage+pos, jcl->bufferedinammount-pos); + jcl->bufferedinammount -= pos; + jcl->instreampos -= pos; pos = 0; - tree = XML_Parse(jcl->bufferedinmessage, &pos, jcl->instreampos, false, jcl->defaultnamespace); - if (jcl->streamdebug == 2 && tree) - { - char t = jcl->bufferedinmessage[pos]; - jcl->bufferedinmessage[pos] = 0; - XMPP_ConversationPrintf("xmppin", "xmppin", jcl->bufferedinmessage); - XMPP_ConversationPrintf("xmppin", "xmppin", "\n"); - jcl->bufferedinmessage[pos] = t; - } - - if (!tree) - { // Con_Printf("No input tree: %s", jcl->bufferedinmessage); - return JCL_DONE; - } + return JCL_DONE; } // Con_Printf("read\n"); @@ -4401,7 +4427,6 @@ int JCL_ClientFrame(jclient_t *jcl, char **error) //Restart everything, basically. jcl->bufferedinammount = 0; jcl->instreampos = 0; - jcl->tagdepth = 0; if (!BUILTINISVALID(Net_SetTLSClient)) { @@ -4422,6 +4447,7 @@ int JCL_ClientFrame(jclient_t *jcl, char **error) Con_Printf("XMPP: WARNING: Connecting via TLS without validating certificate\n"); jcl->issecure = true; + jcl->connecting = true; JCL_AddClientMessageString(jcl, "" "" "=0) + { + payload = XML_CreateNode(description, "payload-type", "", ""); + XML_AddParameter(payload, "channels", "1"); + XML_AddParameter(payload, "clockrate", "8000"); + XML_AddParameteri(payload, "id", pcma); + XML_AddParameter(payload, "name", "pcma"); + } + if (pcmu>=0) + { + payload = XML_CreateNode(description, "payload-type", "", ""); + XML_AddParameter(payload, "channels", "1"); + XML_AddParameter(payload, "clockrate", "8000"); + XML_AddParameteri(payload, "id", pcmu); + XML_AddParameter(payload, "name", "pcmu"); + } } enum @@ -788,16 +811,22 @@ static qboolean JCL_JingleHandleInitiate_GoogleSession(jclient_t *jcl, xmltree_t char parm[64]; char val[64]; //note: the engine will ignore codecs it does not support, returning false. - if (!strcasecmp(name, "SPEEX")) + if (!strcasecmp(name, "speex")) { Q_snprintf(parm, sizeof(parm), "codec%i", atoi(id)); Q_snprintf(val, sizeof(val), "speex@%i", atoi(clock)); okay |= piceapi->ICE_Set(c2c->content[c].ice, parm, val); } - else if (!strcasecmp(name, "OPUS")) + else if (!strcasecmp(name, "pcma") || !strcasecmp(name, "pcmu")) { Q_snprintf(parm, sizeof(parm), "codec%i", atoi(id)); - okay |= piceapi->ICE_Set(c2c->content[c].ice, parm, "opus"); + Q_snprintf(val, sizeof(val), "%s@%i", name, atoi(clock)); + okay |= piceapi->ICE_Set(c2c->content[c].ice, parm, val); + } + else if (!strcasecmp(name, "opus")) + { + Q_snprintf(parm, sizeof(parm), "codec%i", atoi(id)); + okay |= piceapi->ICE_Set(c2c->content[c].ice, parm, "opus@48000"); } } //don't do it if we couldn't successfully set any codecs, because the engine doesn't support the ones that were listed, or something. @@ -915,16 +944,16 @@ static struct c2c_s *JCL_JingleHandleInitiate(jclient_t *jcl, xmltree_t *inj, ch char parm[64]; char val[64]; //note: the engine will ignore codecs it does not support, returning false. - if (!strcasecmp(name, "SPEEX")) + if (!strcasecmp(name, "speex") || !strcasecmp(name, "pcma") || !strcasecmp(name, "pcmu")) { Q_snprintf(parm, sizeof(parm), "codec%i", atoi(id)); - Q_snprintf(val, sizeof(val), "speex@%i", atoi(clock)); + Q_snprintf(val, sizeof(val), "%s@%i", name, atoi(clock)); okay |= piceapi->ICE_Set(c2c->content[c].ice, parm, val); } - else if (!strcasecmp(name, "OPUS")) + else if (!strcasecmp(name, "opus")) { Q_snprintf(parm, sizeof(parm), "codec%i", atoi(id)); - okay |= piceapi->ICE_Set(c2c->content[c].ice, parm, "opus"); + okay |= piceapi->ICE_Set(c2c->content[c].ice, parm, "opus@48000"); } } } diff --git a/plugins/jabber/xmpp.h b/plugins/jabber/xmpp.h index 17fc833e..1b2039a8 100644 --- a/plugins/jabber/xmpp.h +++ b/plugins/jabber/xmpp.h @@ -21,7 +21,7 @@ #endif -#define JCL_BUILD "4" +#define JCL_BUILD "5" //#define DEFAULTDOMAIN "triptohell.info" #define DEFAULTRESOURCE "Quake" #define QUAKEMEDIAXMLNS "http://fteqw.com/protocol/quake" @@ -78,6 +78,7 @@ typedef struct buddy_s bresource_t *resources; bresource_t *defaultresource; //this is the one that last replied int defaulttimestamp; + qboolean askfriend; qboolean friended; qboolean chatroom; //chatrooms are bizzare things that need special handling. qboolean vcardphotochanged; @@ -153,10 +154,9 @@ typedef struct jclient_s char authnonce[256]; int authmode; - int tagdepth; - int openbracket; int instreampos; + qboolean connecting; //still waiting for intial stream tag qboolean connected; //fully on server and authed and everything. qboolean issecure; //tls enabled (either upgraded or initially) int streamdebug; //echo the stream to subconsoles