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