diff --git a/engine/Makefile b/engine/Makefile index 68395f610..27ab5b8bc 100644 --- a/engine/Makefile +++ b/engine/Makefile @@ -1100,15 +1100,15 @@ ifneq (,$(findstring linux,$(FTE_TARGET))) NPFTE_CFLAGS=$(NPFTECFLAGS) $(W32_CFLAGS) -DMULTITHREAD -fPIC -DDYNAMIC_LIBPNG -DDYNAMIC_LIBJPEG NPFTEB_DIR=npfte_linux$(BITS) - GLCL_OBJS=$(GL_OBJS) $(D3DGL_OBJS) $(GLQUAKE_OBJS) $(BOTLIB_OBJS) $(SPEEX_OBJS) gl_vidlinuxglx.o gl_videgl.o snd_alsa.o snd_linux.o cd_linux.o sys_linux.o sys_linux_threads.o + GLCL_OBJS=$(GL_OBJS) $(D3DGL_OBJS) $(GLQUAKE_OBJS) $(BOTLIB_OBJS) $(SPEEX_OBJS) gl_vidlinuxglx.o gl_videgl.o snd_alsa.o snd_linux.o snd_sdl.o cd_linux.o sys_linux.o sys_linux_threads.o GL_EXE_NAME=../fteqw.gl$(BITS) GLCL_EXE_NAME=../fteqwcl.gl$(BITS) GL_LDFLAGS=$(GLLDFLAGS) $(XLDFLAGS) $(OGGVORBISLDFLAGS) - GL_CFLAGS=$(GLCFLAGS) -I/usr/X11R6/include $(SPEEXCFLAGS) -DMULTITHREAD -DLIBVORBISFILE_STATIC -DDYNAMIC_LIBPNG -DDYNAMIC_LIBJPEG + GL_CFLAGS=$(GLCFLAGS) -I/usr/X11R6/include $(SPEEXCFLAGS) -DMULTITHREAD -DLIBVORBISFILE_STATIC -DDYNAMIC_LIBPNG -DDYNAMIC_LIBJPEG -DDYNAMIC_SDL GLB_DIR=gl_linux$(BITS) GLCL_DIR=glcl_linux$(BITS) - MCL_OBJS=$(D3DGL_OBJS) $(GLQUAKE_OBJS) $(SOFTWARE_OBJS) $(BOTLIB_OBJS) $(SPEEX_OBJS) gl_vidlinuxglx.o gl_videgl.o snd_linux.o snd_alsa.o cd_linux.o sys_linux.o sys_linux_threads.o + MCL_OBJS=$(D3DGL_OBJS) $(GLQUAKE_OBJS) $(SOFTWARE_OBJS) $(BOTLIB_OBJS) $(SPEEX_OBJS) gl_vidlinuxglx.o gl_videgl.o snd_linux.o snd_sdl.o snd_alsa.o cd_linux.o sys_linux.o sys_linux_threads.o M_EXE_NAME=../fteqw$(BITS) MCL_EXE_NAME=../fteqwcl$(BITS) M_LDFLAGS=$(GL_LDFLAGS) diff --git a/engine/client/cl_input.c b/engine/client/cl_input.c index 42fe2ea20..1da1fb4a2 100644 --- a/engine/client/cl_input.c +++ b/engine/client/cl_input.c @@ -1361,11 +1361,12 @@ qboolean CLQ2_SendCmd (sizebuf_t *buf) int checksumIndex, i; int lightlev; - seq_hash = cls.netchan.outgoing_sequence; + cl.movesequence = cls.netchan.outgoing_sequence; //make sure its correct even over map changes. + seq_hash = cl.movesequence; // send this and the previous cmds in the message, so // if the last packet was dropped, it can be recovered - i = cls.netchan.outgoing_sequence & UPDATE_MASK; + i = cl.movesequence & UPDATE_MASK; cmd = &cl.outframes[i].cmd[0]; if (cls.resendinfo) diff --git a/engine/client/cl_main.c b/engine/client/cl_main.c index 9e1d341aa..71de50544 100644 --- a/engine/client/cl_main.c +++ b/engine/client/cl_main.c @@ -3970,12 +3970,13 @@ void Host_RunFileNotify(struct dl_download *dl) #define HRF_QTVINFO (1<<12) #define HRF_MANIFEST (1<<13) #define HRF_BSP (1<<14) -#define HRF_PACKAGE (1<<15) -#define HRF_MODEL (1<<16) +#define HRF_PACKAGE (1<<15) //pak or pk3 that should be installed. +#define HRF_ARCHIVE (1<<16) //zip - treated as a multiple-file 'installer' +#define HRF_MODEL (1<<17) #define HRF_ACTION (HRF_OVERWRITE|HRF_NOOVERWRITE|HRF_ABORT) #define HRF_DEMO (HRF_DEMO_MVD|HRF_DEMO_QWD|HRF_DEMO_DM2|HRF_DEMO_DEM) -#define HRF_FILETYPES (HRF_DEMO|HRF_QTVINFO|HRF_MANIFEST|HRF_BSP|HRF_PACKAGE|HRF_MODEL) +#define HRF_FILETYPES (HRF_DEMO|HRF_QTVINFO|HRF_MANIFEST|HRF_BSP|HRF_PACKAGE|HRF_MODEL|HRF_ARCHIVE) typedef struct { unsigned int flags; vfsfile_t *srcfile; @@ -3987,18 +3988,27 @@ int waitingformanifest; void Host_DoRunFile(hrf_t *f); void CL_PlayDemoStream(vfsfile_t *file, struct dl_download *, char *filename, qboolean issyspath, int demotype, float bufferdelay); void CL_ParseQTVDescriptor(vfsfile_t *f, const char *name); +qboolean FS_PathURLCache(char *url, char *path, size_t pathsize); void Host_RunFileDownloaded(struct dl_download *dl) { - //fixme: sort out flags from mime type.... hrf_t *f = dl->user_ctx; - f->srcfile = dl->file; - dl->file = NULL; + if (dl->status == DL_FAILED) + { + f->flags |= HRF_ABORT; + f->srcfile = NULL; + } + else + { + f->srcfile = dl->file; + dl->file = NULL; + } Host_DoRunFile(f); } -void Host_BeginFileDownload(struct dl_download *dl, char *mimetype) +qboolean Host_BeginFileDownload(struct dl_download *dl, char *mimetype) { + qboolean result = false; //at this point the file is still downloading, so don't copy it out just yet. hrf_t *f = dl->user_ctx; @@ -4020,6 +4030,8 @@ void Host_BeginFileDownload(struct dl_download *dl, char *mimetype) f->flags |= HRF_MANIFEST; else if (!strcmp(mimetype, "application/x-multiviewdemo")) f->flags |= HRF_DEMO_MVD; + else if (!strcmp(mimetype, "application/zip")) + f->flags |= HRF_ARCHIVE; // else if (!strcmp(mimetype, "application/x-ftebsp")) // f->flags |= HRF_BSP; // else if (!strcmp(mimetype, "application/x-ftepackage")) @@ -4051,11 +4063,14 @@ void Host_BeginFileDownload(struct dl_download *dl, char *mimetype) f->flags |= HRF_PACKAGE; else { - Con_Printf("file extension of %s not recognised\n", f->fname); + if (mimetype) + Con_Printf("mime type \"%s\" and file extension of \"%s\" not recognised\n", mimetype, f->fname); + else + Con_Printf("file extension of \"%s\" not recognised\n", f->fname); //file type not guessable from extension either. f->flags |= HRF_ABORT; Host_DoRunFile(f); - return; + return false; } if (f->flags & HRF_MANIFEST) @@ -4079,16 +4094,37 @@ void Host_BeginFileDownload(struct dl_download *dl, char *mimetype) { //just use a pipe instead of a temp file, working around an issue with temp files on android dl->file = VFSPIPE_Open(); - return; + return true; + } + else if (f->flags & HRF_ARCHIVE) + { + char cachename[MAX_QPATH]; + if (!FS_PathURLCache(f->fname, cachename, sizeof(cachename))) + return false; + f->srcfile = FS_OpenVFS(cachename, "rb", FS_ROOT); + if (f->srcfile) + { + f->flags |= HRF_OPENED; + Host_DoRunFile(f); + return false; + } + FS_CreatePath(cachename, FS_ROOT); + dl->file = FS_OpenVFS(cachename, "wb", FS_ROOT); + if (dl->file) + return true; //okay, continue downloading. } else if (f->flags & HRF_DEMO) Con_Printf("%s: format not supported\n", f->fname); //demos that are not supported in this build for one reason or another else - return; + return true; + + //demos stream, so we want to continue the http download, but we don't want to do anything with the result. + if (f->flags & HRF_DEMO) + result = true; f->flags |= HRF_ABORT; Host_DoRunFile(f); - return; + return result; } void Host_RunFilePrompted(void *ctx, int button) { @@ -4292,6 +4328,21 @@ void Host_DoRunFile(hrf_t *f) Host_DoRunFile(f); return; } + else if (f->flags & HRF_ARCHIVE) + { + struct gamepacks packagespaths[2]; + if (f->srcfile) + VFS_CLOSE(f->srcfile); + f->srcfile = NULL; + + memset(packagespaths, 0, sizeof(packagespaths)); + packagespaths[0].url = f->fname; + + COM_Gamedir("", packagespaths); + f->flags |= HRF_ABORT; + Host_DoRunFile(f); + return; + } else if (!(f->flags & HRF_QTVINFO)) { Con_Printf("Host_DoRunFile: filetype not handled\n"); diff --git a/engine/client/cl_parse.c b/engine/client/cl_parse.c index fef912a89..453d398e0 100644 --- a/engine/client/cl_parse.c +++ b/engine/client/cl_parse.c @@ -320,7 +320,7 @@ int CL_CalcNet (float scale) ; i++) { frame = &cl.outframes[i&UPDATE_MASK]; - if (i > cl.lastackedmovesequence) + if (i > cl.ackedmovesequence) { // no response yet if (cl_countpendingpl.ival) @@ -2861,7 +2861,7 @@ void CLQW_ParseServerData (void) #endif { COM_FlushTempoaryPacks(); - COM_Gamedir(str); + COM_Gamedir(str, NULL); #ifndef CLIENTONLY Info_SetValueForStarKey (svs.info, "*gamedir", str, MAX_SERVERINFO_STRING); #endif @@ -3092,9 +3092,9 @@ void CLQ2_ParseServerData (void) // set gamedir if (!*str) - COM_Gamedir("baseq2"); + COM_Gamedir("baseq2", NULL); else - COM_Gamedir(str); + COM_Gamedir(str, NULL); // if ((*str && (!fs_gamedirvar->string || !*fs_gamedirvar->string || strcmp(fs_gamedirvar->string, str))) || (!*str && (fs_gamedirvar->string || *fs_gamedirvar->string))) // Cvar_Set("game", str); diff --git a/engine/client/clq2_ents.c b/engine/client/clq2_ents.c index d2c6ac0aa..94ad86ebb 100644 --- a/engine/client/clq2_ents.c +++ b/engine/client/clq2_ents.c @@ -722,6 +722,9 @@ static void CLQ2_ParsePacketEntities (q2frame_t *oldframe, q2frame_t *newframe) unsigned int oldindex, oldnum; cl.validsequence = cls.netchan.incoming_sequence; + cl.ackedmovesequence = cl.validsequence; + + cl.outframes[cl.ackedmovesequence&UPDATE_MASK].latency = realtime - cl.outframes[cl.ackedmovesequence&UPDATE_MASK].senttime; newframe->parse_entities = cl.parse_entities; newframe->num_entities = 0; diff --git a/engine/client/clq3_parse.c b/engine/client/clq3_parse.c index f807e34a0..8168506dc 100644 --- a/engine/client/clq3_parse.c +++ b/engine/client/clq3_parse.c @@ -511,7 +511,7 @@ qboolean CLQ3_SystemInfoChanged(char *str) COM_FlushTempoaryPacks(); if (!*value) value = "baseq3"; - COM_Gamedir(value); + COM_Gamedir(value, NULL); #ifndef CLIENTONLY Info_SetValueForStarKey (svs.info, "*gamedir", value, MAX_SERVERINFO_STRING); #endif diff --git a/engine/client/in_win.c b/engine/client/in_win.c index 7fcd35665..146410bcc 100644 --- a/engine/client/in_win.c +++ b/engine/client/in_win.c @@ -610,7 +610,7 @@ int INS_InitDInput (void) if (!hInstDI) { - hInstDI = LoadLibrary("dinput.dll"); + hInstDI = Sys_LoadLibrary("dinput.dll", NULL); if (hInstDI == NULL) { diff --git a/engine/client/m_mp3.c b/engine/client/m_mp3.c index 11ab8c6c7..01fd91b23 100644 --- a/engine/client/m_mp3.c +++ b/engine/client/m_mp3.c @@ -251,9 +251,9 @@ int loadedtracknames; #ifdef WINAMP qboolean WinAmp_GetHandle (void) { - if ((hwnd_winamp = FindWindow("Winamp", NULL))) + if ((hwnd_winamp = FindWindowW(L"Winamp", NULL))) return true; - if ((hwnd_winamp = FindWindow("Winamp v1.x", NULL))) + if ((hwnd_winamp = FindWindowW(L"Winamp v1.x", NULL))) return true; *currenttrack.nicename = '\0'; diff --git a/engine/client/menu.c b/engine/client/menu.c index 30bf68013..35eb6b78d 100644 --- a/engine/client/menu.c +++ b/engine/client/menu.c @@ -38,8 +38,16 @@ void M_DrawTextBox (int x, int y, int width, int lines) cx = x; cy = y; p = R2D_SafeCachePic ("gfx/box_tl.lmp"); - if (!p) - return; //assume we can't find any + switch(R_GetShaderSizes(p, NULL, NULL, false)) + { + case -1: + return; //still pending + case 0: + R2D_ImageColours(0.0, 0.0, 0.0, 1.0); + R2D_FillBlock(x + ((vid.width - 320)>>1), y, width*8+16, lines*8+16); + R2D_ImageColours(1.0, 1.0, 1.0, 1.0); + return; + } M_DrawScalePic (cx, cy, 8, 8, p); p = R2D_SafeCachePic ("gfx/box_ml.lmp"); if (p) diff --git a/engine/client/pr_csqc.c b/engine/client/pr_csqc.c index 733622050..4ef7c4b53 100644 --- a/engine/client/pr_csqc.c +++ b/engine/client/pr_csqc.c @@ -5333,6 +5333,7 @@ static struct { //DP_QC_URI_GET {"uri_get", PF_uri_get, 513}, // #513 float(string uril, float id) uri_get + {"uri_post", PF_uri_get, 513}, // #513 float(string uril, float id) uri_post {"tokenize_console", PF_tokenize_console, 514}, {"argv_start_index", PF_argv_start_index, 515}, diff --git a/engine/client/pr_menu.c b/engine/client/pr_menu.c index fb30906e2..dd9efd66a 100644 --- a/engine/client/pr_menu.c +++ b/engine/client/pr_menu.c @@ -2055,6 +2055,7 @@ static struct { {"uri_unescape", PF_uri_unescape, 511}, {"num_for_edict", PF_etof, 512}, {"uri_get", PF_uri_get, 513}, + {"uri_post", PF_uri_get, 513}, {"tokenize_console", PF_tokenize_console, 514}, {"argv_start_index", PF_argv_start_index, 515}, {"argv_end_index", PF_argv_end_index, 516}, diff --git a/engine/client/r_2d.c b/engine/client/r_2d.c index cc1555473..772d992d6 100644 --- a/engine/client/r_2d.c +++ b/engine/client/r_2d.c @@ -714,7 +714,6 @@ qboolean R2D_Font_WasAdded(char *buffer, char *fontfilename) return true; } extern qboolean WinNT; -qboolean MyRegGetStringValue(HKEY base, char *keyname, char *valuename, void *data, int datalen); qboolean MyRegGetStringValueMultiSz(HKEY base, char *keyname, char *valuename, void *data, int datalen); void R2D_Font_AddFontLink(char *buffer, int buffersize, char *fontname) { @@ -786,15 +785,14 @@ void R2D_Font_Changed(void) #if defined(_WIN32) && !defined(FTE_SDL) && !defined(WINRT) if (!strcmp(gl_font.string, "?")) { - BOOL (APIENTRY *pChooseFontA)(LPCHOOSEFONTA) = NULL; + BOOL (APIENTRY *pChooseFontW)(LPCHOOSEFONTW) = NULL; dllfunction_t funcs[] = { - {(void*)&pChooseFontA, "ChooseFontA"}, + {(void*)&pChooseFontW, "ChooseFontW"}, {NULL} }; - qboolean MyRegGetStringValue(HKEY base, char *keyname, char *valuename, void *data, int datalen); - LOGFONT lf = {0}; - CHOOSEFONTA cf = {sizeof(cf)}; + LOGFONTW lf = {0}; + CHOOSEFONTW cf = {sizeof(cf)}; extern HWND mainwindow; font_default = Font_LoadFont(8, ""); if (tsize != 8) @@ -807,28 +805,30 @@ void R2D_Font_Changed(void) cf.Flags = CF_FORCEFONTEXIST | CF_TTONLY; cf.lpLogFont = &lf; - Sys_LoadLibrary("Comdlg32.dll", funcs); + Sys_LoadLibrary("comdlg32.dll", funcs); - if (pChooseFontA && pChooseFontA(&cf)) + if (pChooseFontW && pChooseFontW(&cf)) { char fname[MAX_OSPATH*8]; + char lfFaceName[MAX_OSPATH]; char *keyname; + narrowen(lfFaceName, sizeof(lfFaceName), lf.lfFaceName); *fname = 0; //FIXME: should enumerate and split & and ignore sizes and () crap. if (!*fname) { - keyname = va("%s%s%s (TrueType)", lf.lfFaceName, lf.lfWeight>=FW_BOLD?" Bold":"", lf.lfItalic?" Italic":""); + keyname = va("%s%s%s (TrueType)", lfFaceName, lf.lfWeight>=FW_BOLD?" Bold":"", lf.lfItalic?" Italic":""); if (!MyRegGetStringValue(HKEY_LOCAL_MACHINE, WinNT?"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Fonts":"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Fonts", keyname, fname, sizeof(fname))) *fname = 0; } if (!*fname) { - keyname = va("%s (OpenType)", lf.lfFaceName); + keyname = va("%s (OpenType)", lfFaceName); if (!MyRegGetStringValue(HKEY_LOCAL_MACHINE, WinNT?"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Fonts":"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Fonts", keyname, fname, sizeof(fname))) *fname = 0; } - R2D_Font_AddFontLink(fname, sizeof(fname), lf.lfFaceName); + R2D_Font_AddFontLink(fname, sizeof(fname), lfFaceName); Cvar_Set(&gl_font, fname); } return; diff --git a/engine/client/snd_al.c b/engine/client/snd_al.c index 136279176..b6d747363 100644 --- a/engine/client/snd_al.c +++ b/engine/client/snd_al.c @@ -809,7 +809,13 @@ static qboolean OpenAL_InitLibrary(void) if (!openallib_tried) { openallib_tried = true; +#ifdef _WIN32 openallib = Sys_LoadLibrary("OpenAL32", openalfuncs); +#else + openallib = Sys_LoadLibrary("libopenal.so.1", openalfuncs); + if (!openallib) + openallib = Sys_LoadLibrary("libopenal", openalfuncs); +#endif } return !!openallib; #endif diff --git a/engine/client/snd_alsa.c b/engine/client/snd_alsa.c index fd9afbbde..8d3198e2b 100755 --- a/engine/client/snd_alsa.c +++ b/engine/client/snd_alsa.c @@ -68,6 +68,10 @@ snd_pcm_sframes_t (*psnd_pcm_mmap_commit) (snd_pcm_t *pcm, snd_pcm_uframes_t off snd_pcm_sframes_t (*psnd_pcm_writei) (snd_pcm_t *pcm, const void *buffer, snd_pcm_uframes_t size); int (*psnd_pcm_prepare) (snd_pcm_t *pcm); +int (*psnd_device_name_hint) (int card, const char *iface, void ***hints); +char * (*psnd_device_name_get_hint) (const void *hint, const char *id); +int (*psnd_device_name_free_hint) (void **hints); + static unsigned int ALSA_MMap_GetDMAPos (soundcardinfo_t *sc) { @@ -178,6 +182,8 @@ static void ALSA_Shutdown (soundcardinfo_t *sc) if (sc->Submit == ALSA_RW_Submit) free(sc->sn.buffer); + + Con_DPrintf("Alsa closed\n"); } static void *ALSA_LockBuffer(soundcardinfo_t *sc, unsigned int *sampidx) @@ -213,35 +219,39 @@ static qboolean Alsa_InitAlsa(void) } - psnd_pcm_open = dlsym(alsasharedobject, "snd_pcm_open"); - psnd_pcm_close = dlsym(alsasharedobject, "snd_pcm_close"); - psnd_strerror = dlsym(alsasharedobject, "snd_strerror"); - psnd_pcm_hw_params_any = dlsym(alsasharedobject, "snd_pcm_hw_params_any"); - psnd_pcm_hw_params_set_access = dlsym(alsasharedobject, "snd_pcm_hw_params_set_access"); - psnd_pcm_hw_params_set_format = dlsym(alsasharedobject, "snd_pcm_hw_params_set_format"); - psnd_pcm_hw_params_set_channels = dlsym(alsasharedobject, "snd_pcm_hw_params_set_channels"); - psnd_pcm_hw_params_set_rate_near = dlsym(alsasharedobject, "snd_pcm_hw_params_set_rate_near"); + psnd_pcm_open = dlsym(alsasharedobject, "snd_pcm_open"); + psnd_pcm_close = dlsym(alsasharedobject, "snd_pcm_close"); + psnd_strerror = dlsym(alsasharedobject, "snd_strerror"); + psnd_pcm_hw_params_any = dlsym(alsasharedobject, "snd_pcm_hw_params_any"); + psnd_pcm_hw_params_set_access = dlsym(alsasharedobject, "snd_pcm_hw_params_set_access"); + psnd_pcm_hw_params_set_format = dlsym(alsasharedobject, "snd_pcm_hw_params_set_format"); + psnd_pcm_hw_params_set_channels = dlsym(alsasharedobject, "snd_pcm_hw_params_set_channels"); + psnd_pcm_hw_params_set_rate_near = dlsym(alsasharedobject, "snd_pcm_hw_params_set_rate_near"); psnd_pcm_hw_params_set_period_size_near = dlsym(alsasharedobject, "snd_pcm_hw_params_set_period_size_near"); - psnd_pcm_hw_params = dlsym(alsasharedobject, "snd_pcm_hw_params"); - psnd_pcm_sw_params_current = dlsym(alsasharedobject, "snd_pcm_sw_params_current"); + psnd_pcm_hw_params = dlsym(alsasharedobject, "snd_pcm_hw_params"); + psnd_pcm_sw_params_current = dlsym(alsasharedobject, "snd_pcm_sw_params_current"); psnd_pcm_sw_params_set_start_threshold = dlsym(alsasharedobject, "snd_pcm_sw_params_set_start_threshold"); psnd_pcm_sw_params_set_stop_threshold = dlsym(alsasharedobject, "snd_pcm_sw_params_set_stop_threshold"); - psnd_pcm_sw_params = dlsym(alsasharedobject, "snd_pcm_sw_params"); - psnd_pcm_hw_params_get_buffer_size = dlsym(alsasharedobject, "snd_pcm_hw_params_get_buffer_size"); - psnd_pcm_avail_update = dlsym(alsasharedobject, "snd_pcm_avail_update"); - psnd_pcm_state = dlsym(alsasharedobject, "snd_pcm_state"); - psnd_pcm_start = dlsym(alsasharedobject, "snd_pcm_start"); - psnd_pcm_recover = dlsym(alsasharedobject, "snd_pcm_recover"); - psnd_pcm_set_params = dlsym(alsasharedobject, "snd_pcm_set_params"); - psnd_pcm_hw_params_sizeof = dlsym(alsasharedobject, "snd_pcm_hw_params_sizeof"); - psnd_pcm_sw_params_sizeof = dlsym(alsasharedobject, "snd_pcm_sw_params_sizeof"); + psnd_pcm_sw_params = dlsym(alsasharedobject, "snd_pcm_sw_params"); + psnd_pcm_hw_params_get_buffer_size = dlsym(alsasharedobject, "snd_pcm_hw_params_get_buffer_size"); + psnd_pcm_avail_update = dlsym(alsasharedobject, "snd_pcm_avail_update"); + psnd_pcm_state = dlsym(alsasharedobject, "snd_pcm_state"); + psnd_pcm_start = dlsym(alsasharedobject, "snd_pcm_start"); + psnd_pcm_recover = dlsym(alsasharedobject, "snd_pcm_recover"); + psnd_pcm_set_params = dlsym(alsasharedobject, "snd_pcm_set_params"); + psnd_pcm_hw_params_sizeof = dlsym(alsasharedobject, "snd_pcm_hw_params_sizeof"); + psnd_pcm_sw_params_sizeof = dlsym(alsasharedobject, "snd_pcm_sw_params_sizeof"); psnd_pcm_hw_params_set_buffer_size_near = dlsym(alsasharedobject, "snd_pcm_hw_params_set_buffer_size_near"); - psnd_pcm_mmap_begin = dlsym(alsasharedobject, "snd_pcm_mmap_begin"); - psnd_pcm_mmap_commit = dlsym(alsasharedobject, "snd_pcm_mmap_commit"); + psnd_pcm_mmap_begin = dlsym(alsasharedobject, "snd_pcm_mmap_begin"); + psnd_pcm_mmap_commit = dlsym(alsasharedobject, "snd_pcm_mmap_commit"); - psnd_pcm_writei = dlsym(alsasharedobject, "snd_pcm_writei"); - psnd_pcm_prepare = dlsym(alsasharedobject, "snd_pcm_prepare"); + psnd_pcm_writei = dlsym(alsasharedobject, "snd_pcm_writei"); + psnd_pcm_prepare = dlsym(alsasharedobject, "snd_pcm_prepare"); + + psnd_device_name_hint = dlsym(alsasharedobject, "snd_device_name_hint"); + psnd_device_name_get_hint = dlsym(alsasharedobject, "snd_device_name_get_hint"); + psnd_device_name_free_hint = dlsym(alsasharedobject, "snd_device_name_free_hint"); alsaworks = psnd_pcm_open && psnd_pcm_close @@ -267,20 +277,17 @@ static qboolean Alsa_InitAlsa(void) && psnd_pcm_mmap_begin && psnd_pcm_mmap_commit && psnd_pcm_writei && psnd_pcm_prepare + && psnd_device_name_hint && psnd_device_name_get_hint && psnd_device_name_free_hint ; return alsaworks; } -static int ALSA_InitCard (soundcardinfo_t *sc, int cardnum) +static qboolean QDECL ALSA_InitCard (soundcardinfo_t *sc, const char *pcmname) { snd_pcm_t *pcm; snd_pcm_uframes_t buffer_size; - soundcardinfo_t *ec; //existing card - char *pcmname; - cvar_t *devname; - int err; snd_pcm_hw_params_t *hw; snd_pcm_sw_params_t *sw; @@ -294,7 +301,7 @@ static int ALSA_InitCard (soundcardinfo_t *sc, int cardnum) if (!Alsa_InitAlsa()) { Con_Printf(CON_ERROR "Alsa does not appear to be installed or compatible\n"); - return 2; + return false; } hw = alloca(psnd_pcm_hw_params_sizeof()); @@ -303,17 +310,8 @@ static int ALSA_InitCard (soundcardinfo_t *sc, int cardnum) memset(hw, 0, psnd_pcm_hw_params_sizeof()); //WARNING: 'default' as the default sucks arse. it adds about a second's worth of lag. - devname = Cvar_Get(va("snd_alsadevice%i", cardnum+1), (cardnum==0?"hw":(cardnum==1?"default":"")), 0, "Sound controls"); - pcmname = devname->string; - - if (!*pcmname) - return 2; - - for (ec = sndcardinfo; ec; ec = ec->next) - if (!strcmp(ec->name, pcmname)) - break; - if (ec) - return 2; //no more + if (!pcmname) + pcmname = "default"; sc->inactive_sound = true; //linux sound devices always play sound, even when we're not the active app... @@ -323,7 +321,7 @@ static int ALSA_InitCard (soundcardinfo_t *sc, int cardnum) SND_PCM_NONBLOCK); if (0 > err) { - Con_Printf (CON_ERROR "Error: open error: %s\n", psnd_strerror (err)); + Con_Printf (CON_ERROR "ALSA Error: open error (%s): %s\n", pcmname, psnd_strerror (err)); return 0; } Con_Printf ("ALSA: Using PCM %s.\n", pcmname); @@ -332,8 +330,7 @@ static int ALSA_InitCard (soundcardinfo_t *sc, int cardnum) err = psnd_pcm_set_params(pcm, ((sc->sn.samplebits==8)?SND_PCM_FORMAT_U8:SND_PCM_FORMAT_S16), (mmap?SND_PCM_ACCESS_MMAP_INTERLEAVED:SND_PCM_ACCESS_RW_INTERLEAVED), sc->sn.numchannels, sc->sn.speed, true, 0.04*1000000); if (0 > err) { - Con_Printf (CON_ERROR "ALSA: error setting params. %s\n", - psnd_strerror (err)); + Con_Printf (CON_ERROR "ALSA: error setting params. %s\n", psnd_strerror (err)); goto error; } @@ -346,16 +343,14 @@ static int ALSA_InitCard (soundcardinfo_t *sc, int cardnum) err = psnd_pcm_hw_params_any (pcm, hw); if (0 > err) { - Con_Printf (CON_ERROR "ALSA: error setting hw_params_any. %s\n", - psnd_strerror (err)); + Con_Printf (CON_ERROR "ALSA: error setting hw_params_any. %s\n", psnd_strerror (err)); goto error; } err = psnd_pcm_hw_params_set_access (pcm, hw, mmap?SND_PCM_ACCESS_MMAP_INTERLEAVED:SND_PCM_ACCESS_RW_INTERLEAVED); if (0 > err) { - Con_Printf (CON_ERROR "ALSA: Failure to set interleaved PCM access. %s\n", - psnd_strerror (err)); + Con_Printf (CON_ERROR "ALSA: Failure to set interleaved PCM access. %s\n", psnd_strerror (err)); goto error; } @@ -433,8 +428,7 @@ static int ALSA_InitCard (soundcardinfo_t *sc, int cardnum) err = psnd_pcm_hw_params_set_period_size_near (pcm, hw, &frag_size, 0); if (0 > err) { - Con_Printf (CON_ERROR "ALSA: unable to set period size near %i. %s\n", - (int) frag_size, psnd_strerror (err)); + Con_Printf (CON_ERROR "ALSA: unable to set period size near %i. %s\n", (int) frag_size, psnd_strerror (err)); goto error; } err = psnd_pcm_hw_params (pcm, hw); @@ -445,26 +439,22 @@ static int ALSA_InitCard (soundcardinfo_t *sc, int cardnum) } err = psnd_pcm_sw_params_current (pcm, sw); if (0 > err) { - Con_Printf (CON_ERROR "ALSA: unable to determine current sw params. %s\n", - psnd_strerror (err)); + Con_Printf (CON_ERROR "ALSA: unable to determine current sw params. %s\n", psnd_strerror (err)); goto error; } err = psnd_pcm_sw_params_set_start_threshold (pcm, sw, ~0U); if (0 > err) { - Con_Printf (CON_ERROR "ALSA: unable to set playback threshold. %s\n", - psnd_strerror (err)); + Con_Printf (CON_ERROR "ALSA: unable to set playback threshold. %s\n", psnd_strerror (err)); goto error; } err = psnd_pcm_sw_params_set_stop_threshold (pcm, sw, ~0U); if (0 > err) { - Con_Printf (CON_ERROR "ALSA: unable to set playback stop threshold. %s\n", - psnd_strerror (err)); + Con_Printf (CON_ERROR "ALSA: unable to set playback stop threshold. %s\n", psnd_strerror (err)); goto error; } err = psnd_pcm_sw_params (pcm, sw); if (0 > err) { - Con_Printf (CON_ERROR "ALSA: unable to install sw params. %s\n", - psnd_strerror (err)); + Con_Printf (CON_ERROR "ALSA: unable to install sw params. %s\n", psnd_strerror (err)); goto error; } @@ -485,8 +475,7 @@ static int ALSA_InitCard (soundcardinfo_t *sc, int cardnum) err = psnd_pcm_hw_params_get_buffer_size (hw, &buffer_size); if (0 > err) { - Con_Printf (CON_ERROR "ALSA: unable to get buffer size. %s\n", - psnd_strerror (err)); + Con_Printf (CON_ERROR "ALSA: unable to get buffer size. %s\n", psnd_strerror (err)); goto error; } sc->sn.speed = rate; @@ -530,8 +519,7 @@ static int ALSA_InitCard (soundcardinfo_t *sc, int cardnum) err = psnd_pcm_prepare(pcm); if (0 > err) { - Con_Printf (CON_ERROR "ALSA: unable to prepare for use. %s\n", - psnd_strerror (err)); + Con_Printf (CON_ERROR "ALSA: unable to prepare for use. %s\n", psnd_strerror (err)); goto error; } } @@ -542,7 +530,45 @@ error: psnd_pcm_close (pcm); return false; } +#define SDRVNAME "ALSA" +static qboolean QDECL ALSA_Enumerate(void (QDECL *cb) (const char *drivername, const char *devicecode, const char *readablename)) +{ + size_t i; + void **hints; -int (*pALSA_InitCard) (soundcardinfo_t *sc, int cardnum) = &ALSA_InitCard; - - + if (Alsa_InitAlsa()) + { + if (!psnd_device_name_hint(-1, "pcm", &hints)) + { + for (i = 0; hints[i]; i++) + { + char *n = psnd_device_name_get_hint(hints[i], "NAME"); + if (n) + { + char *t = psnd_device_name_get_hint(hints[i], "IOID"); + if (!t || strcasecmp(t, "Input")) + { + char *d = psnd_device_name_get_hint(hints[i], "DESC"); + if (d) + cb(SDRVNAME, n, va("ALSA (%s)", d)); + else + cb(SDRVNAME, n, n); + free(d); + } + free(t); + free(n); //dangerous to free things across boundaries. + } + } + psnd_device_name_free_hint(hints); + } + else + return false; + } + return true; +} +sounddriver_t ALSA_Output = +{ + SDRVNAME, + ALSA_InitCard, + ALSA_Enumerate +}; diff --git a/engine/client/snd_dma.c b/engine/client/snd_dma.c index aa22756f3..d2a1e9b56 100644 --- a/engine/client/snd_dma.c +++ b/engine/client/snd_dma.c @@ -112,8 +112,8 @@ cvar_t snd_linearresample_stream = CVARAF( "s_linearresample_stream", "0", cvar_t snd_mixerthread = CVARAD( "s_mixerthread", "1", "snd_mixerthread", "When enabled sound mixing will be run on a separate thread. Currently supported only by directsound. Other drivers may unconditionally thread audio. Set to 0 only if you have issues."); -cvar_t snd_device = CVARAF( "s_device", "", - "snd_device", CVAR_ARCHIVE); +cvar_t snd_device = CVARAFD( "s_device", "", + "snd_device", CVAR_ARCHIVE, "This is the sound device(s) to use, in the form of driver:device. If desired, multiple devices can be listed in space-seperated (quoted) tokens. _s_device_opts contains any enumerated options. In all seriousness, use the menu to set this if you wish to keep your hair."); cvar_t snd_device_opts = CVARFD( "_s_device_opts", "", CVAR_NOSET, "The possible audio output devices, in \"value\" \"description\" pairs, for gamecode to read."); #ifdef VOICECHAT @@ -1484,11 +1484,13 @@ void S_DefaultSpeakerConfiguration(soundcardinfo_t *sc) sounddriver_t DSOUND_Output; +sounddriver_t SDL_Output; +sounddriver_t ALSA_Output; +sounddriver_t OSS_Output; #ifdef AVAIL_OPENAL extern sounddriver_t OPENAL_Output; #endif -sounddriver pALSA_InitCard; sounddriver pSNDIO_InitCard; sounddriver pOSS_InitCard; sounddriver pMacOS_InitCard; @@ -1506,7 +1508,15 @@ sounddriver_t *outputdrivers[] = #ifdef AVAIL_OPENAL &OPENAL_Output, #endif +#ifdef _WIN32 &DSOUND_Output, +#endif + + &SDL_Output, //prefered on linux +#ifdef __linux__ + &ALSA_Output, //pure shite +#endif + &OSS_Output, //good, but not likely to work any more NULL }; typedef struct { @@ -1523,10 +1533,6 @@ sdriver_t olddrivers[] = { #endif {"SNDIO", &pSNDIO_InitCard}, //prefered on OpenBSD - {"SDL", &pSDL_InitCard}, //prefered on linux - {"ALSA", &pALSA_InitCard}, //pure shite - {"OSS", &pOSS_InitCard}, //good, but not likely to work any more - {"WaveOut", &pWAV_InitCard}, //doesn't work properly in vista, etc. {NULL, NULL} }; @@ -1586,7 +1592,7 @@ static soundcardinfo_t *SNDDMA_Init(char *driver, char *device) for (i = 0; outputdrivers[i]; i++) { sd = outputdrivers[i]; - if (sd && (!driver || !Q_strcasecmp(sd->name, driver))) + if (sd && sd->name && (!driver || !Q_strcasecmp(sd->name, driver))) { //skip drivers which are not present. if (!sd->InitCard) diff --git a/engine/client/snd_linux.c b/engine/client/snd_linux.c index 957b29b71..a42d179c7 100644 --- a/engine/client/snd_linux.c +++ b/engine/client/snd_linux.c @@ -82,7 +82,7 @@ static void OSS_Alsa_Submit(soundcardinfo_t *sc, int start, int end) { if (result >= 0) sc->snd_sent += result; - printf("full?\n"); +// printf("full?\n"); return; } sc->snd_sent += chunk; @@ -119,7 +119,7 @@ static void OSS_Unlock(soundcardinfo_t *sc, void *buffer) { } -static int OSS_InitCard(soundcardinfo_t *sc, int cardnum) +static qboolean OSS_InitCard(soundcardinfo_t *sc, const char *snddev) { //FIXME: implement snd_multipledevices somehow. int rc; int fmt; @@ -127,8 +127,6 @@ static int OSS_InitCard(soundcardinfo_t *sc, int cardnum) int i; struct audio_buf_info info; int caps; - char *snddev = NULL; - cvar_t *devname; qboolean alsadetected = false; #ifdef __linux__ @@ -137,11 +135,13 @@ static int OSS_InitCard(soundcardinfo_t *sc, int cardnum) alsadetected = true; #endif - devname = Cvar_Get(va("snd_devicename%i", cardnum+1), cardnum?"":"/dev/dsp", 0, "Sound controls"); - snddev = devname->string; - - if (!*snddev) - return 2; + if (!snddev || !*snddev) + snddev = "/dev/dsp"; + else if (strncmp(snddev, "/dev/dsp", 8)) + { + Con_Printf("Refusing to use non-dsp device\n"); + return false; + } sc->inactive_sound = true; //linux sound devices always play sound, even when we're not the active app... @@ -165,7 +165,7 @@ static int OSS_InitCard(soundcardinfo_t *sc, int cardnum) perror(snddev); Con_Printf(CON_ERROR "OSS: Could not open %s\n", snddev); OSS_Shutdown(sc); - return 0; + return false; } Q_strncpyz(sc->name, snddev, sizeof(sc->name)); @@ -176,7 +176,7 @@ static int OSS_InitCard(soundcardinfo_t *sc, int cardnum) perror(snddev); Con_Printf(CON_ERROR "OSS: Could not reset %s\n", snddev); OSS_Shutdown(sc); - return 0; + return false; } //check its general capabilities, we need trigger+mmap @@ -185,7 +185,7 @@ static int OSS_InitCard(soundcardinfo_t *sc, int cardnum) perror(snddev); Con_Printf(CON_ERROR "OSS: Sound driver too old\n"); OSS_Shutdown(sc); - return 0; + return false; } //choose channels @@ -197,7 +197,7 @@ static int OSS_InitCard(soundcardinfo_t *sc, int cardnum) perror(snddev); Con_Printf(CON_ERROR "OSS: Could not set %s to channels=%d\n", snddev, sc->sn.numchannels); OSS_Shutdown(sc); - return 0; + return false; } sc->sn.numchannels = tmp; #else @@ -210,7 +210,7 @@ static int OSS_InitCard(soundcardinfo_t *sc, int cardnum) perror(snddev); Con_Printf(CON_ERROR "OSS: Could not set %s to stereo=%d\n", snddev, sc->sn.numchannels); OSS_Shutdown(sc); - return 0; + return false; } if (tmp) sc->sn.numchannels = 2; @@ -227,7 +227,7 @@ static int OSS_InitCard(soundcardinfo_t *sc, int cardnum) { //their card doesn't support 8bit which we're trying to use. Con_Printf(CON_ERROR "OSS: No needed sample formats supported\n"); OSS_Shutdown(sc); - return 0; + return false; } if (sc->sn.samplebits == 16) { @@ -238,7 +238,7 @@ static int OSS_InitCard(soundcardinfo_t *sc, int cardnum) perror(snddev); Con_Printf(CON_ERROR "OSS: Could not support 16-bit data. Try 8-bit.\n"); OSS_Shutdown(sc); - return 0; + return false; } } else if (sc->sn.samplebits == 8) @@ -250,7 +250,7 @@ static int OSS_InitCard(soundcardinfo_t *sc, int cardnum) perror(snddev); Con_Printf(CON_ERROR "OSS: Could not support 8-bit data.\n"); OSS_Shutdown(sc); - return 0; + return false; } } else @@ -258,7 +258,7 @@ static int OSS_InitCard(soundcardinfo_t *sc, int cardnum) perror(snddev); Con_Printf(CON_ERROR "OSS: %d-bit sound not supported.\n", sc->sn.samplebits); OSS_Shutdown(sc); - return 0; + return false; } //choose speed @@ -276,7 +276,7 @@ static int OSS_InitCard(soundcardinfo_t *sc, int cardnum) perror(snddev); Con_Printf(CON_ERROR "OSS: Failed to obtain a suitable rate\n"); OSS_Shutdown(sc); - return 0; + return false; } } sc->sn.speed = tmp; @@ -287,7 +287,7 @@ static int OSS_InitCard(soundcardinfo_t *sc, int cardnum) perror("GETOSPACE"); Con_Printf(CON_ERROR "OSS: Um, can't do GETOSPACE?\n"); OSS_Shutdown(sc); - return 0; + return false; } sc->sn.samples = info.fragstotal * info.fragsize; sc->sn.samples /= (sc->sn.samplebits/8); @@ -297,7 +297,7 @@ static int OSS_InitCard(soundcardinfo_t *sc, int cardnum) sc->sn.buffer = MAP_FAILED; if (alsadetected) { - Con_Printf("Alsa detected. Refusing to mmap.\n"); + Con_Printf("Refusing to mmap oss device in case alsa's oss emulation crashes.\n"); } else if ((caps & DSP_CAP_TRIGGER) && (caps & DSP_CAP_MMAP)) { @@ -335,7 +335,7 @@ static int OSS_InitCard(soundcardinfo_t *sc, int cardnum) perror(snddev); Con_Printf(CON_ERROR "OSS: Could not toggle.\n"); OSS_Shutdown(sc); - return 0; + return false; } tmp = PCM_ENABLE_OUTPUT; rc = ioctl(sc->audio_fd, SNDCTL_DSP_SETTRIGGER, &tmp); @@ -344,7 +344,7 @@ static int OSS_InitCard(soundcardinfo_t *sc, int cardnum) perror(snddev); Con_Printf(CON_ERROR "OSS: Could not toggle.\n"); OSS_Shutdown(sc); - return 0; + return false; } sc->Submit = OSS_MMap_Submit; sc->GetDMAPos = OSS_MMap_GetDMAPos; @@ -357,10 +357,103 @@ static int OSS_InitCard(soundcardinfo_t *sc, int cardnum) sc->SetWaterDistortion = OSS_SetUnderWater; sc->Shutdown = OSS_Shutdown; - return 1; + return true; } -int (*pOSS_InitCard) (soundcardinfo_t *sc, int cardnum) = &OSS_InitCard; +#define SDRVNAME "OSS" +typedef struct oss_sysinfo { + char product[32]; /* E.g. SunOS Audio */ + char version[32]; /* E.g. 4.0a */ + int versionnum; /* See OSS_GETVERSION */ + char options[128]; /* NOT SUPPORTED */ + int numaudios; /* # of audio/dsp devices */ + int openedaudio[8]; /* Reserved, always 0 */ + int numsynths; /* NOT SUPPORTED, always 0 */ + int nummidis; /* NOT SUPPORTED, always 0 */ + int numtimers; /* NOT SUPPORTED, always 0 */ + int nummixers; /* # of mixer devices */ + int openedmidi[8]; /* Mask of midi devices are busy */ + int numcards; /* Number of sound cards in the system */ + int numaudioengines; /* Number of audio engines in the system */ + char license[16]; /* E.g. "GPL" or "CDDL" */ + char revision_info[256]; /* Reserved */ + int filler[172]; /* Reserved */ +} oss_sysinfo; +#define SNDCTL_SYSINFO _IOR ('X', 1, oss_sysinfo) + +typedef struct oss_audioinfo { + int dev; /* Device to query */ + char name[64]; /* Human readable name */ + int busy; /* reserved */ + int pid; /* reserved */ + int caps; /* PCM_CAP_INPUT, PCM_CAP_OUTPUT */ + int iformats; /* Supported input formats */ + int oformats; /* Supported output formats */ + int magic; /* reserved */ + char cmd[64]; /* reserved */ + int card_number; + int port_number; /* reserved */ + int mixer_dev; + int legacy_device; /* Obsolete field. Replaced by devnode */ + int enabled; /* reserved */ + int flags; /* reserved */ + int min_rate; /* Minimum sample rate */ + int max_rate; /* Maximum sample rate */ + int min_channels; /* Minimum number of channels */ + int max_channels; /* Maximum number of channels */ + int binding; /* reserved */ + int rate_source; /* reserved */ + char handle[32]; /* reserved */ + unsigned int nrates; /* reserved */ + unsigned int rates[20]; /* reserved */ + char song_name[64]; /* reserved */ + char label[16]; /* reserved */ + int latency; /* reserved */ + char devnode[32]; /* Device special file name (absolute path) */ + int next_play_engine; /* reserved */ + int next_rec_engine; /* reserved */ + int filler[184]; /* reserved */ +} oss_audioinfo; +#define SNDCTL_AUDIOINFO _IOWR('X', 7, oss_audioinfo) + +static qboolean QDECL OSS_Enumerate(void (QDECL *cb) (const char *drivername, const char *devicecode, const char *readablename)) +{ + int i; + int fd = open("/dev/mixer", O_RDWR, 0); + oss_sysinfo si; + if (fd == -1) + return true; //oss not supported. don't list any devices. + + if (ioctl(fd, SNDCTL_SYSINFO, &si) != -1) + { + if ((si.versionnum>>16) >= 4) + { //only trust all the fields if its recent enough + for(i = 0; i < si.numaudios; i++) + { + oss_audioinfo ai; + ai.dev = i; + if (ioctl(fd, SNDCTL_AUDIOINFO, &ai) != -1) + cb(SDRVNAME, ai.devnode, ai.name); + } + close(fd); + return true; + } + else + printf("Not enumerating OSS %u.%u.%u devices.\n", (si.versionnum>>16)&0xffff, (si.versionnum>>8)&0xff, si.versionnum&0xff); + } + else + printf("OSS driver is too old to support device enumeration.\n"); + close(fd); + return false; //enumeration failed. +} + +sounddriver_t OSS_Output = +{ + SDRVNAME, + OSS_InitCard, + OSS_Enumerate +}; + diff --git a/engine/client/snd_sdl.c b/engine/client/snd_sdl.c index e5e1d8499..9c28a0cd1 100644 --- a/engine/client/snd_sdl.c +++ b/engine/client/snd_sdl.c @@ -1,24 +1,117 @@ #include "quakedef.h" #include "winquake.h" +#ifdef DYNAMIC_SDL +#define SDL_MAJOR_VERSION 2 +//if we're not an sdl build, we probably want to link to sdl libraries dynamically or something. +#include +#define SDL_AudioDeviceID uint32_t +#define SDL_INIT_AUDIO 0x00000010 +#define SDL_INIT_NOPARACHUTE 0x00100000 +#define SDL_AUDIO_ALLOW_FREQUENCY_CHANGE 0x00000001 +#define SDL_AUDIO_ALLOW_FORMAT_CHANGE 0x00000002 +#define SDL_AUDIO_ALLOW_CHANNELS_CHANGE 0x00000004 +#define AUDIO_S16LSB 0x8010 +#define AUDIO_S16MSB 0x9010 +#if __BYTE_ORDER == __BIG_ENDIAN +#define AUDIO_S16SYS AUDIO_S16MSB +#else +#define AUDIO_S16SYS AUDIO_S16LSB +#endif + +typedef uint16_t SDL_AudioFormat; +typedef void VARGS (*SDL_AudioCallback)(void *userdata, uint8_t *stream, int len); + +typedef struct SDL_AudioSpec +{ + int freq; + SDL_AudioFormat format; + uint8_t channels; + uint8_t silence; + uint16_t samples; + uint16_t padding; + uint32_t size; + SDL_AudioCallback callback; + void *userdata; +} SDL_AudioSpec; + +static int (*SDL_Init) (uint32_t flags); +static int (*SDL_InitSubSystem) (uint32_t flags); +static SDL_AudioDeviceID (*SDL_OpenAudioDevice) (const char *dev, int iscapture, const SDL_AudioSpec *desired, SDL_AudioSpec *obtained, int allowed_changes); +static void (*SDL_PauseAudioDevice) (SDL_AudioDeviceID fd, int pausestate); +static void (*SDL_LockAudioDevice) (SDL_AudioDeviceID fd); +static void (*SDL_UnlockAudioDevice) (SDL_AudioDeviceID fd); +static int (*SDL_CloseAudioDevice) (SDL_AudioDeviceID fd); +static int (*SDL_GetNumAudioDevices) (int iscapture); +static const char *(*SDL_GetAudioDeviceName) (int index, int iscapture); +static const char *(*SDL_GetError) (void); +#else #include +#endif #define SELFPAINT //SDL calls a callback each time it needs to repaint the 'hardware' buffers -//This results in extra latency. -//SDL runs does this multithreaded. +//This results in extra latency due it needing to buffer that much data. //So we tell it a fairly pathetically sized buffer and try and get it to copy often //hopefully this lowers sound latency, and has no suddenly starting sounds and stuff. //It still has greater latency than direct access, of course. +//On the plus side, SDL calls the callback from another thread. this means we can set up some tiny buffer size, and if we're mixing inside the callback then you can actually get lower latency than waiting for an entire frame (yay rtlights) + +static qboolean SSDL_InitAudio(void) +{ + static qboolean inited = false; +#ifdef DYNAMIC_SDL + static dllfunction_t funcs[] = + { + {(void*)&SDL_Init, "SDL_Init"}, + {(void*)&SDL_InitSubSystem, "SDL_InitSubSystem"}, + {(void*)&SDL_OpenAudioDevice, "SDL_OpenAudioDevice"}, + {(void*)&SDL_PauseAudioDevice, "SDL_PauseAudioDevice"}, + {(void*)&SDL_LockAudioDevice, "SDL_LockAudioDevice"}, + {(void*)&SDL_UnlockAudioDevice, "SDL_UnlockAudioDevice"}, + {(void*)&SDL_CloseAudioDevice, "SDL_CloseAudioDevice"}, + {(void*)&SDL_GetNumAudioDevices, "SDL_GetNumAudioDevices"}, + {(void*)&SDL_GetAudioDeviceName, "SDL_GetAudioDeviceName"}, + {(void*)&SDL_GetError, "SDL_GetError"}, + {NULL, NULL} + }; + static dllhandle_t *libsdl; + if (!libsdl) + { + libsdl = Sys_LoadLibrary("libSDL2.so", funcs); + if (libsdl) + SDL_Init(SDL_INIT_NOPARACHUTE); + else + { + Con_Printf("Unable to load libSDL2 library\n"); + return false; + } + } +#endif + + if (!inited) + if(SDL_InitSubSystem(SDL_INIT_AUDIO | SDL_INIT_NOPARACHUTE)) + { + Con_Printf("Couldn't initialize SDL audio subsystem (%s)\n", SDL_GetError()); + return false; + } + inited = true; + + return true; +} -//FIXME: One thing I saw in quakeforge was that quakeforge basically leaves the audio locked except for a really short period of time. -//An interesting idea, which ensures the driver can only paint in a small time-frame. this would possibly allow lower latency painting. static void SSDL_Shutdown(soundcardinfo_t *sc) { Con_DPrintf("Shutdown SDL sound\n"); + +#if SDL_MAJOR_VERSION >= 2 + SDL_PauseAudioDevice(sc->audio_fd, 1); + SDL_CloseAudioDevice(sc->audio_fd); +#else SDL_CloseAudio(); +#endif #ifndef SELFPAINT if (sc->sn.buffer) free(sc->sn.buffer); @@ -67,14 +160,22 @@ static void VARGS SSDL_Paint(void *userdata, qbyte *stream, int len) static void *SSDL_LockBuffer(soundcardinfo_t *sc, unsigned int *sampidx) { +#if SDL_MAJOR_VERSION >= 2 + SDL_LockAudioDevice(sc->audio_fd); +#else SDL_LockAudio(); +#endif return sc->sn.buffer; } static void SSDL_UnlockBuffer(soundcardinfo_t *sc, void *buffer) { +#if SDL_MAJOR_VERSION >= 2 + SDL_UnlockAudioDevice(sc->audio_fd); +#else SDL_UnlockAudio(); +#endif } static void SSDL_SetUnderWater(soundcardinfo_t *sc, qboolean uw) @@ -87,18 +188,11 @@ static void SSDL_Submit(soundcardinfo_t *sc, int start, int end) //SDL will call SSDL_Paint to paint when it's time, and the sound buffer is always there... } -static int SDL_InitCard(soundcardinfo_t *sc, int cardnum) +static qboolean SDL_InitCard(soundcardinfo_t *sc, const char *devicename) { SDL_AudioSpec desired, obtained; - if (cardnum) - { //our init code actually calls this function multiple times, in the case that the user has multiple sound cards - return 2; //erm. SDL won't allow multiple sound cards anyway. - } - - Con_Printf("Initing SDL audio.\n"); - - if(SDL_InitSubSystem(SDL_INIT_AUDIO | SDL_INIT_NOPARACHUTE)) + if(!SSDL_InitAudio()) { Con_Printf("Couldn't initialize SDL audio subsystem\n"); return false; @@ -114,19 +208,26 @@ static int SDL_InitCard(soundcardinfo_t *sc, int cardnum) desired.userdata = sc; memcpy(&obtained, &desired, sizeof(obtained)); -#ifdef FTE_TARGET_WEB - if ( SDL_OpenAudio(&desired, NULL) < 0 ) +#if SDL_MAJOR_VERSION >= 2 + sc->audio_fd = SDL_OpenAudioDevice(devicename, false, &desired, &obtained, (sndcardinfo?0:SDL_AUDIO_ALLOW_FREQUENCY_CHANGE) | SDL_AUDIO_ALLOW_CHANNELS_CHANGE); + if (!sc->audio_fd) { - Con_Printf("SDL: SNDDMA_Init: couldn't open sound device (%s).\n", SDL_GetError()); + Con_Printf("SDL_OpenAudioDevice(%s) failed: couldn't open sound device (%s).\n", devicename?devicename:"default", SDL_GetError()); return false; } - obtained = desired; + if (devicename) + Con_Printf("Initing SDL audio device '%s'.\n", devicename); + else + Con_Printf("Initing default SDL audio device.\n"); #else + if (sndcardinfo) + return false; //SDL1 only supports opening one audio device at a time. the existing one might not be sdl, but I don't care. if ( SDL_OpenAudio(&desired, &obtained) < 0 ) { - Con_Printf("SDL: SNDDMA_Init: couldn't open sound device (%s).\n", SDL_GetError()); + Con_Printf("SDL_OpenAudio failed: couldn't open sound device (%s).\n", SDL_GetError()); return false; } + Con_Printf("Initing default SDL audio device.\n"); #endif sc->sn.numchannels = obtained.channels; sc->sn.speed = obtained.freq; @@ -155,10 +256,41 @@ static int SDL_InitCard(soundcardinfo_t *sc, int cardnum) sc->Shutdown = SSDL_Shutdown; sc->GetDMAPos = SSDL_GetDMAPos; +#if SDL_MAJOR_VERSION >= 2 + SDL_PauseAudioDevice(sc->audio_fd, 0); +#else SDL_PauseAudio(0); +#endif return true; } -sounddriver pSDL_InitCard = &SDL_InitCard; +#define SDRVNAME "SDL" +static qboolean QDECL SDL_Enumerate(void (QDECL *cb) (const char *drivername, const char *devicecode, const char *readablename)) +{ +#if SDL_MAJOR_VERSION >= 2 + int max, i; + if(SSDL_InitAudio()) + { + max = SDL_GetNumAudioDevices(false); + for (i = 0; i < max; i++) + { + const char *devname = SDL_GetAudioDeviceName(i, false); + if (devname) + cb(SDRVNAME, devname, va("SDL (%s)", devname)); + } + } + return true; +#else + return false; +#endif +} + +sounddriver_t SDL_Output = +{ + SDRVNAME, + SDL_InitCard, + SDL_Enumerate +}; + diff --git a/engine/client/sys_plugfte.c b/engine/client/sys_plugfte.c index cdd1adb52..29659906b 100644 --- a/engine/client/sys_plugfte.c +++ b/engine/client/sys_plugfte.c @@ -578,7 +578,7 @@ vfsfile_t *VFSPIPE_Open(void) #endif #ifdef _WIN32 -qboolean MyRegGetStringValue(HKEY base, char *keyname, char *valuename, void *data, DWORD datalen) +qboolean MyRegGetStringValue(HKEY base, const char *keyname, const char *valuename, void *data, size_t datalen) { qboolean result = false; HKEY subkey; diff --git a/engine/client/sys_win.c b/engine/client/sys_win.c index 249cc5839..8b5e0d77d 100644 --- a/engine/client/sys_win.c +++ b/engine/client/sys_win.c @@ -43,10 +43,6 @@ __declspec(dllexport) DWORD NvOptimusEnablement = 0x00000001; __declspec(dllexport) int AmdPowerXpressRequestHighPerformance = 1; //13.35+ -wchar_t *widen(wchar_t *out, size_t outlen, const char *utf8); -char *narrowen(char *out, size_t outlen, wchar_t *wide); - - #ifdef WINRT //you're going to need a different sys_ port. qboolean isDedicated = false; qboolean ActiveApp; @@ -368,15 +364,20 @@ dllhandle_t *Sys_LoadLibrary(const char *name, dllfunction_t *funcs) { int i; HMODULE lib; + wchar_t wide[MAX_OSPATH]; - lib = LoadLibrary(name); + widen(wide, sizeof(wide), name); + lib = LoadLibraryW(wide); if (!lib) { + if (!strstr(COM_SkipPath(name), ".dll")) + { //.dll implies that it is a system dll, or something that is otherwise windows-specific already. #ifdef _WIN64 - lib = LoadLibrary(va("%s_64", name)); + lib = LoadLibrary(va("%s_64", name)); #elif defined(_WIN32) - lib = LoadLibrary(va("%s_32", name)); + lib = LoadLibrary(va("%s_32", name)); #endif + } if (!lib) return NULL; } @@ -763,7 +764,7 @@ DWORD CrashExceptionHandler (qboolean iswatchdog, DWORD exceptionCode, LPEXCEPTI //generate a minidump, but only if we were compiled by something that used usable debugging info. its a bit pointless otherwise. #ifdef _MSC_VER - hDbgHelp = LoadLibrary ("DBGHELP"); + hDbgHelp = LoadLibraryA ("DBGHELP"); if (hDbgHelp) fnMiniDumpWriteDump = (MINIDUMPWRITEDUMP)GetProcAddress (hDbgHelp, "MiniDumpWriteDump"); else @@ -790,9 +791,9 @@ DWORD CrashExceptionHandler (qboolean iswatchdog, DWORD exceptionCode, LPEXCEPTI else if (*com_gamepath) Q_strncpyz(dumpPath, com_gamepath, sizeof(dumpPath)); else - GetTempPath (sizeof(dumpPath)-16, dumpPath); + GetTempPathA (sizeof(dumpPath)-16, dumpPath); Q_strncatz(dumpPath, DISTRIBUTION"CrashDump.dmp", sizeof(dumpPath)); - dumpfile = CreateFile (dumpPath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + dumpfile = CreateFileA (dumpPath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (dumpfile) { MINIDUMP_EXCEPTION_INFORMATION crashinfo; @@ -803,19 +804,19 @@ DWORD CrashExceptionHandler (qboolean iswatchdog, DWORD exceptionCode, LPEXCEPTI { CloseHandle(dumpfile); Q_snprintfz(msg, sizeof(msg), "You can find the crashdump at:\n%s\nPlease send this file to someone.\n\nWarning: sensitive information (like your current user name) might be present in the dump.\nYou will probably want to compress it.", dumpPath); - MessageBox(NULL, msg, DISTRIBUTION " Sucks", 0); + MessageBoxA(NULL, msg, DISTRIBUTION " Sucks", 0); } else - MessageBox(NULL, "MiniDumpWriteDump failed", "oh noes", 0); + MessageBoxA(NULL, "MiniDumpWriteDump failed", "oh noes", 0); } else { Q_snprintfz(msg, sizeof(msg), "unable to open %s\nno dump created.", dumpPath); - MessageBox(NULL, msg, "oh noes", 0); + MessageBoxA(NULL, msg, "oh noes", 0); } } else - MessageBox(NULL, "Kaboom! Sorry. No MiniDumpWriteDump function.", DISTRIBUTION " Sucks", 0); + MessageBoxA(NULL, "Kaboom! Sorry. No MiniDumpWriteDump function.", DISTRIBUTION " Sucks", 0); #endif return EXCEPTION_EXECUTE_HANDLER; } @@ -1071,7 +1072,7 @@ static int Sys_EnumerateFiles2 (const char *match, int matchstart, int neststart memcpy(tmproot, match, neststart); strcpy(tmproot+neststart, "*.*"); - r = FindFirstFile(tmproot, &fd); + r = FindFirstFileA(tmproot, &fd); strcpy(tmproot+neststart, ""); if (r==(HANDLE)-1) return 1; @@ -1093,7 +1094,7 @@ static int Sys_EnumerateFiles2 (const char *match, int matchstart, int neststart } } } - } while(FindNextFile(r, &fd) && go); + } while(FindNextFileA(r, &fd) && go); FindClose(r); } else @@ -1107,7 +1108,7 @@ static int Sys_EnumerateFiles2 (const char *match, int matchstart, int neststart memcpy(tmproot, match, neststart); strcpy(tmproot+neststart, "*.*"); - r = FindFirstFile(tmproot, &fd); + r = FindFirstFileA(tmproot, &fd); strcpy(tmproot+neststart, ""); if (r==(HANDLE)-1) return 1; @@ -1138,7 +1139,7 @@ static int Sys_EnumerateFiles2 (const char *match, int matchstart, int neststart } } } - } while(FindNextFile(r, &fd) && go); + } while(FindNextFileA(r, &fd) && go); FindClose(r); } } @@ -1458,7 +1459,6 @@ void VARGS Sys_Error (const char *error, ...) { va_list argptr; char text[1024]; - //, text2[1024]; // DWORD dummy; va_start (argptr, error); @@ -1474,7 +1474,11 @@ void VARGS Sys_Error (const char *error, ...) SV_Shutdown(); #endif - MessageBox(NULL, text, "Error", 0); + { + wchar_t wtext[1024]; + widen(wtext, sizeof(wtext), text); + MessageBoxW(NULL, wtext, L"Error", 0); + } #ifndef SERVERONLY CloseHandle (qwclsemaphore); @@ -1991,11 +1995,11 @@ qboolean Sys_InitTerminal (void) SetConsoleCtrlHandler (HandlerRoutine, TRUE); SetConsoleCP(CP_UTF8); SetConsoleOutputCP(CP_UTF8); - SetConsoleTitle (FULLENGINENAME " dedicated server"); + SetConsoleTitleW (_L(FULLENGINENAME) L" dedicated server"); if (isPlugin) { - hinput = CreateFile("CONIN$",GENERIC_READ|GENERIC_WRITE,FILE_SHARE_READ,0,OPEN_EXISTING,0,0); - houtput = CreateFile("CONOUT$",GENERIC_READ|GENERIC_WRITE,FILE_SHARE_READ,0,OPEN_EXISTING,0,0); + hinput = CreateFileA("CONIN$",GENERIC_READ|GENERIC_WRITE,FILE_SHARE_READ,0,OPEN_EXISTING,0,0); + houtput = CreateFileA("CONOUT$",GENERIC_READ|GENERIC_WRITE,FILE_SHARE_READ,0,OPEN_EXISTING,0,0); } else { @@ -2415,7 +2419,7 @@ void Win7_Init(void) HRESULT (WINAPI *pSetCurrentProcessExplicitAppUserModelID)(PCWSTR AppID); - h = LoadLibrary("shell32.dll"); + h = LoadLibraryW(L"shell32.dll"); if (h) { pSHOpenWithDialog = (void*)GetProcAddress(h, "SHOpenWithDialog"); @@ -2549,29 +2553,35 @@ int MyRegGetIntValue(HKEY base, char *keyname, char *valuename, int defaultval) DWORD datalen = sizeof(result); HKEY subkey; DWORD type = REG_NONE; - if (RegOpenKeyEx(base, keyname, 0, KEY_READ, &subkey) == ERROR_SUCCESS) + wchar_t wide[MAX_PATH]; + if (RegOpenKeyExW(base, widen(wide, sizeof(wide), keyname), 0, KEY_READ, &subkey) == ERROR_SUCCESS) { - if (ERROR_SUCCESS != RegQueryValueEx(subkey, valuename, NULL, &type, (void*)&result, &datalen) || type != REG_DWORD) + if (ERROR_SUCCESS != RegQueryValueExW(subkey, widen(wide, sizeof(wide), valuename), NULL, &type, (void*)&result, &datalen) || type != REG_DWORD) result = defaultval; RegCloseKey (subkey); } return result; } -qboolean MyRegGetStringValue(HKEY base, char *keyname, char *valuename, void *data, int datalen) +//result is utf-8 +qboolean MyRegGetStringValue(HKEY base, const char *keyname, const char *valuename, void *data, size_t datalen) { qboolean result = false; HKEY subkey; DWORD type = REG_NONE; - if (RegOpenKeyEx(base, keyname, 0, KEY_READ, &subkey) == ERROR_SUCCESS) + wchar_t wide[MAX_PATH]; + wchar_t wdata[MAX_PATH]; + DWORD dwlen = sizeof(wdata) - sizeof(wdata[0]); + if (RegOpenKeyExW(base, widen(wide, sizeof(wide), keyname), 0, KEY_READ, &subkey) == ERROR_SUCCESS) { - DWORD dwlen = datalen; - result = ERROR_SUCCESS == RegQueryValueEx(subkey, valuename, NULL, &type, data, &dwlen); - datalen = dwlen; + result = ERROR_SUCCESS == RegQueryValueExW(subkey, widen(wide, sizeof(wide), valuename), NULL, &type, (BYTE*)wdata, &dwlen); RegCloseKey (subkey); } if (result && (type == REG_SZ || type == REG_EXPAND_SZ)) - ((char*)data)[datalen] = 0; + { + wdata[dwlen/sizeof(wchar_t)] = 0; + narrowen(data, datalen, wdata); + } else ((char*)data)[0] = 0; return result; @@ -3196,9 +3206,9 @@ static BOOL microsoft_access(LPCSTR pszFolder, DWORD dwAccessDesired) DWORD dwNeeded; wchar_t wpath[MAX_OSPATH]; widen(wpath, sizeof(wpath), pszFolder); - GetFileSecurity(pszFolder,si,NULL,0,&dwNeeded); + GetFileSecurityW(wpath,si,NULL,0,&dwNeeded); psdSD = malloc(dwNeeded); - GetFileSecurity(pszFolder,si,psdSD,dwNeeded,&dwNeeded); + GetFileSecurityW(wpath,si,psdSD,dwNeeded,&dwNeeded); ImpersonateSelf(SecurityImpersonation); OpenThreadToken(GetCurrentThread(), TOKEN_ALL_ACCESS, TRUE, &hToken); memset(&GenericMapping, 0xff, sizeof(GENERIC_MAPPING)); @@ -3275,7 +3285,7 @@ static LRESULT CALLBACK stoopidstoopidstoopid(HWND w, UINT m, WPARAM wp, LPARAM struct egadsthisisretarded { - char title[MAX_OSPATH]; + wchar_t title[MAX_OSPATH]; char subdir[MAX_OSPATH]; char parentdir[MAX_OSPATH]; char statustext[MAX_OSPATH]; @@ -3294,13 +3304,13 @@ static INT CALLBACK StupidBrowseCallbackProc(HWND hwnd, UINT uMsg, LPARAM lp, LP switch(uMsg) { case BFFM_INITIALIZED: - OutputDebugString("initialised\n"); + OutputDebugStringA("initialised\n"); //combat windows putting new windows behind everything else if it takes a while for UAC prompts to go away SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE); //combat windows bug where renaming something doesn't update the dialog's path - list = FindWindowEx(hwnd, NULL, "SHBROWSEFORFOLDER SHELLNAMESPACE CONTROL", NULL); + list = FindWindowExW(hwnd, NULL, L"SHBROWSEFORFOLDER SHELLNAMESPACE CONTROL", NULL); if (list) omgwtfwhyohwhy = (WNDPROC)SetWindowLongPtr(list, GWLP_WNDPROC, (LONG_PTR)stoopidstoopidstoopid); @@ -3317,7 +3327,7 @@ static INT CALLBACK StupidBrowseCallbackProc(HWND hwnd, UINT uMsg, LPARAM lp, LP ; else #endif - if (GetCurrentDirectory(sizeof(szDir)/sizeof(TCHAR), szDir) && microsoft_access(szDir, ACCESS_READ | ACCESS_WRITE)) + if (GetCurrentDirectory(sizeof(szDir)/sizeof(TCHAR), szDir))// && microsoft_access(szDir, ACCESS_READ | ACCESS_WRITE)) ; SendMessage(hwnd, BFFM_SETSELECTION, TRUE, (LPARAM)szDir); // SendMessage(hwnd, BFFM_SETEXPANDED, TRUE, (LPARAM)szDir); @@ -3336,7 +3346,7 @@ static INT CALLBACK StupidBrowseCallbackProc(HWND hwnd, UINT uMsg, LPARAM lp, LP case BFFM_VALIDATEFAILEDW: return 1;//!microsoft_access("C:\\Games\\", ACCESS_READ | ACCESS_WRITE)) case BFFM_SELCHANGED: - OutputDebugString("selchanged\n"); + OutputDebugStringA("selchanged\n"); if (SHGetPathFromIDList((LPITEMIDLIST)lp, pData->parentdir)) { // OutputDebugString(va("selchanged: %s\n", szDir)); @@ -3345,7 +3355,8 @@ static INT CALLBACK StupidBrowseCallbackProc(HWND hwnd, UINT uMsg, LPARAM lp, LP //fixme: verify that id1 is a subdir perhaps? if (edit) { - SetWindowText(edit, fs_gamename.string); + wchar_t wide[128]; + SetWindowTextW(edit, widen(wide, sizeof(wide), fs_gamename.string)); SendMessageA(hwnd, BFFM_SETSTATUSTEXT, 0, (LPARAM)va("%s", pData->parentdir)); } else @@ -3365,14 +3376,25 @@ LRESULT CALLBACK NoCloseWindowProc(HWND w, UINT m, WPARAM wp, LPARAM lp) return DefWindowProc(w, m, wp, lp); } +void FS_Directorize(char *fname, size_t fnamesize) +{ + size_t l = strlen(fname); + if (!l) //technically already a directory + return; + if (fname[l-1] == '\\' || fname[l-1] == '//') + return; //already a directory + Q_strncatz(fname, "/", fnamesize); +} + void FS_CreateBasedir(const char *path); qboolean Sys_DoInstall(void) { extern ftemanifest_t *fs_manifest; char exepath[MAX_OSPATH]; char newexepath[MAX_OSPATH]; - char resultpath[MAX_PATH]; - BROWSEINFO bi; + wchar_t wide[MAX_PATH]; + char resultpath[MAX_OSPATH]; + BROWSEINFOW bi; LPITEMIDLIST il; struct egadsthisisretarded diediedie; @@ -3385,9 +3407,9 @@ qboolean Sys_DoInstall(void) memset(&bi, 0, sizeof(bi)); bi.hwndOwner = mainwindow; //note that this is usually still null bi.pidlRoot = NULL; - GetCurrentDirectory(sizeof(resultpath)-1, resultpath); - bi.pszDisplayName = resultpath; - Q_snprintfz(diediedie.title, sizeof(diediedie.title), "Where would you like to install %s to?", fs_gamename.string); + _snwprintf(diediedie.title, countof(diediedie.title), L"Where would you like to install %s to?", widen(wide, sizeof(wide), fs_gamename.string)); + GetCurrentDirectoryW(countof(wide)-1, wide); + bi.pszDisplayName = wide; bi.lpszTitle = diediedie.title; bi.ulFlags = BIF_RETURNONLYFSDIRS|BIF_STATUSTEXT | BIF_EDITBOX|BIF_NEWDIALOGSTYLE|BIF_VALIDATE; bi.lpfn = StupidBrowseCallbackProc; @@ -3396,20 +3418,21 @@ qboolean Sys_DoInstall(void) Q_strncpyz(diediedie.subdir, fs_gamename.string, sizeof(diediedie.subdir)); - il = SHBrowseForFolder(&bi); + il = SHBrowseForFolderW(&bi); if (il) { - SHGetPathFromIDList(il, resultpath); + SHGetPathFromIDListW(il, wide); CoTaskMemFree(il); } else return true; + narrowen(resultpath, sizeof(resultpath), wide); - Q_strncatz(resultpath, "/", sizeof(resultpath)); + FS_Directorize(resultpath, sizeof(resultpath)); if (*diediedie.subdir) { Q_strncatz(resultpath, diediedie.subdir, sizeof(resultpath)); - Q_strncatz(resultpath, "/", sizeof(resultpath)); + FS_Directorize(resultpath, sizeof(resultpath)); } FS_CreateBasedir(resultpath); @@ -3836,7 +3859,7 @@ int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLin #endif #ifdef CATCHCRASH - LoadLibrary ("DBGHELP"); //heap corruption can prevent loadlibrary from working properly, so do this in advance. + LoadLibraryA ("DBGHELP"); //heap corruption can prevent loadlibrary from working properly, so do this in advance. #ifdef _MSC_VER __try #else @@ -3966,11 +3989,11 @@ int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLin HWND old; qtvfile = parms.argv[1]; - old = FindWindow("FTEGLQuake", NULL); + old = FindWindowW(L"FTEGLQuake", NULL); if (!old) - old = FindWindow("FTED3D11QUAKE", NULL); + old = FindWindowW(L"FTED3D11QUAKE", NULL); if (!old) - old = FindWindow("FTED3D9QUAKE", NULL); + old = FindWindowW(L"FTED3D9QUAKE", NULL); if (old) { COPYDATASTRUCT cds; diff --git a/engine/client/vid_headless.c b/engine/client/vid_headless.c index cb14309c7..69b83d11b 100644 --- a/engine/client/vid_headless.c +++ b/engine/client/vid_headless.c @@ -79,8 +79,8 @@ static qboolean Headless_VID_Init (rendererstate_t *info, unsigned char *pale //tray icon crap, so the user can still restore the game. extern HWND mainwindow; extern HINSTANCE global_hInstance; - WNDCLASSA wc; - NOTIFYICONDATA data; + WNDCLASSW wc; + NOTIFYICONDATAW data; //Shell_NotifyIcon requires a window to provide events etc. wc.style = 0; @@ -92,18 +92,18 @@ static qboolean Headless_VID_Init (rendererstate_t *info, unsigned char *pale wc.hCursor = LoadCursor (NULL,IDC_ARROW); wc.hbrBackground = NULL; wc.lpszMenuName = 0; - wc.lpszClassName = "FTEHeadlessClass"; - RegisterClassA(&wc); + wc.lpszClassName = L"FTEHeadlessClass"; + RegisterClassW(&wc); - mainwindow = CreateWindowExA(0L, wc.lpszClassName, "FTE QuakeWorld", 0, 0, 0, 0, 0, NULL, NULL, global_hInstance, NULL); + mainwindow = CreateWindowExW(0L, wc.lpszClassName, L"FTE QuakeWorld", 0, 0, 0, 0, 0, NULL, NULL, global_hInstance, NULL); data.cbSize = sizeof(data); data.hWnd = mainwindow; data.uID = 0; data.uFlags = NIF_MESSAGE | NIF_ICON | NIF_TIP; data.uCallbackMessage = WM_USER; data.hIcon = wc.hIcon; - strcpy(data.szTip, "Right-click to restore"); - Shell_NotifyIcon(NIM_ADD, &data); + wcscpy(data.szTip, L"Right-click to restore"); + Shell_NotifyIconW(NIM_ADD, &data); #endif return true; } diff --git a/engine/common/bothdefs.h b/engine/common/bothdefs.h index 02fbebee1..a269f45bb 100644 --- a/engine/common/bothdefs.h +++ b/engine/common/bothdefs.h @@ -612,7 +612,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #define MAX_QPATH 128 // max length of a quake game pathname -#define MAX_OSPATH 256 // max length of a filesystem pathname +#define MAX_OSPATH 1024 // max length of a filesystem pathname (260 on windows, but needs to be longer for utf8) #define ON_EPSILON 0.1 // point on plane side epsilon diff --git a/engine/common/common.h b/engine/common/common.h index 95d0e4403..82dd3543b 100644 --- a/engine/common/common.h +++ b/engine/common/common.h @@ -458,6 +458,16 @@ vfsfile_t *FS_OpenVFS(const char *filename, const char *mode, enum fs_relative r vfsfile_t *FS_OpenTemp(void); vfsfile_t *FS_OpenTCP(const char *name, int defaultport); +#ifdef _WIN32 +//windows doesn't support utf-8. Which is a shame really, because that's the charset we expect from everything. +#define countof(array) (sizeof(array)/sizeof(array[0])) +char *narrowen(char *out, size_t outlen, wchar_t *wide); +wchar_t *widen(wchar_t *out, size_t outbytes, const char *utf8); +#define __L(x) L ## x +#define _L(x) __L(x) +qboolean MyRegGetStringValue(void *hkey_base, const char *keyname, const char *valuename, void *data, size_t datalen); +#endif + void FS_UnloadPackFiles(void); void FS_ReloadPackFiles(void); char *FSQ3_GenerateClientPacksList(char *buffer, int maxlen, int basechecksum); @@ -522,7 +532,12 @@ void COM_InitFilesystem (void); //does not set up any gamedirs. qboolean FS_DownloadingPackage(void); qboolean FS_ChangeGame(ftemanifest_t *newgame, qboolean allowreloadconfigs, qboolean allowbasedirchange); void FS_Shutdown(void); -void COM_Gamedir (const char *dir); +struct gamepacks +{ + char *path; + char *url; +}; +void COM_Gamedir (const char *dir, const struct gamepacks *packagespaths); char *FS_GetGamedir(qboolean publicpathonly); char *FS_GetBasedir(void); char *FS_GetManifestArgs(void); diff --git a/engine/common/fs.c b/engine/common/fs.c index fbde2df01..a48acb49d 100644 --- a/engine/common/fs.c +++ b/engine/common/fs.c @@ -179,7 +179,7 @@ int fs_hash_files; -static const char *FS_GetCleanPath(const char *pattern, char *outbuf, int outlen); +const char *FS_GetCleanPath(const char *pattern, char *outbuf, int outlen); void FS_RegisterDefaultFileSystems(void); static void COM_CreatePath (char *path); ftemanifest_t *FS_ReadDefaultManifest(char *newbasedir, size_t newbasedirsize, qboolean fixedbasedir); @@ -1232,7 +1232,7 @@ void FS_ReferenceControl(unsigned int refflag, unsigned int resetflags) } //outbuf might not be written into -static const char *FS_GetCleanPath(const char *pattern, char *outbuf, int outlen) +const char *FS_GetCleanPath(const char *pattern, char *outbuf, int outlen) { const char *s; char *o; @@ -1265,6 +1265,11 @@ static const char *FS_GetCleanPath(const char *pattern, char *outbuf, int outlen Con_Printf("Error: absolute path in filename %s\n", pattern); return NULL; } + if (!*s) + { + *o++ = '\0'; + break; + } Con_Printf("Error: empty directory name (%s)\n", pattern); s++; continue; @@ -1958,6 +1963,105 @@ searchpathfuncs_t *FS_OpenPackByExtension(vfsfile_t *f, const char *pakname) return NULL; } +static void FS_AddManifestPackages(searchpath_t **oldpaths, const char *purepath, const char *logicalpaths, searchpath_t *search, const char *extension, searchpathfuncs_t *(QDECL *OpenNew)(vfsfile_t *file, const char *desc)) +{ + int i; + searchpathfuncs_t *handle; + unsigned int keptflags; + vfsfile_t *vfs; + flocation_t loc; + + int ptlen, palen; + ptlen = strlen(purepath); + for (i = 0; i < sizeof(fs_manifest->package) / sizeof(fs_manifest->package[0]); i++) + { + char ext[8]; + if (fs_manifest->package[i].path && !strcmp(COM_FileExtension(fs_manifest->package[i].path, ext, sizeof(ext)), extension)) + { + palen = strlen(fs_manifest->package[i].path); + if (palen > ptlen && (fs_manifest->package[i].path[ptlen] == '/' || fs_manifest->package[i].path[ptlen] == '\\' )&& !strncmp(purepath, fs_manifest->package[i].path, ptlen)) + { + searchpath_t *oldp; + char pname[MAX_OSPATH]; + char lname[MAX_OSPATH]; + char lname2[MAX_OSPATH]; + if (fs_manifest->package[i].crcknown) + snprintf(lname, sizeof(lname), "%#x", fs_manifest->package[i].crc); + else + snprintf(lname, sizeof(lname), ""); + if (!FS_GenCachedPakName(fs_manifest->package[i].path, lname, pname, sizeof(pname))) + continue; + snprintf (lname, sizeof(lname), "%s%s", logicalpaths, pname+ptlen+1); + snprintf (lname2, sizeof(lname), "%s%s", logicalpaths, fs_manifest->package[i].path+ptlen+1); + + for (oldp = com_searchpaths; oldp; oldp = oldp->next) + { + if (!Q_strcasecmp(oldp->purepath, fs_manifest->package[i].path)) + break; + if (!Q_strcasecmp(oldp->logicalpath, lname)) + break; + if (!Q_strcasecmp(oldp->logicalpath, lname2)) + break; + } + if (!oldp) + { + handle = FS_GetOldPath(oldpaths, lname2, &keptflags); + if (!handle) + handle = FS_GetOldPath(oldpaths, lname, &keptflags); + if (!handle) + { + vfs = NULL; + if (search) + { + if (search->handle->FindFile(search->handle, &loc, pname+ptlen+1, NULL)) + vfs = search->handle->OpenVFS(search->handle, &loc, "r"); + } + else + { + vfs = FS_OpenVFS(fs_manifest->package[i].path, "rb", FS_ROOT); + if (vfs) + snprintf (lname, sizeof(lname), "%s", lname2); + else + vfs = FS_OpenVFS(pname, "rb", FS_ROOT); + } + + if (vfs) + handle = OpenNew (vfs, lname); + } + if (handle && fs_manifest->package[i].crcknown) + { + int truecrc = handle->GeneratePureCRC(handle, 0, false); + if (truecrc != fs_manifest->package[i].crc) + { + Con_Printf(CON_ERROR "File \"%s\" has hash %#x (required: %#x). Please delete it or move it away\n", lname, truecrc, fs_manifest->package[i].crc); + handle->ClosePath(handle); + handle = NULL; + } + } + if (handle) + FS_AddPathHandle(oldpaths, fs_manifest->package[i].path, lname, handle, SPF_COPYPROTECTED|SPF_UNTRUSTED|keptflags, (unsigned int)-1); + } + } + } + } +} + +static void FS_AddDownloadManifestPackages(searchpath_t **oldpaths, unsigned int loadstuff)//, const char *purepath, searchpath_t *search, const char *extension, searchpathfuncs_t *(QDECL *OpenNew)(vfsfile_t *file, const char *desc)) +{ + int i; + char logicalroot[MAX_OSPATH]; + FS_NativePath("downloads/", FS_ROOT, logicalroot, sizeof(logicalroot)); + for (i = 0; i < sizeof(searchpathformats)/sizeof(searchpathformats[0]); i++) + { + if (!searchpathformats[i].extension || !searchpathformats[i].OpenNew)// || !searchpathformats[i].loadscan) + continue; + if (loadstuff & (1<handle->EnumerateFiles(search->handle, pakfile, FS_AddWildDataFiles, &wp); - - //and load any named in the manifest (this happens when they're crced or whatever) - { - int ptlen, palen; - ptlen = strlen(purepath); - for (i = 0; i < sizeof(fs_manifest->package) / sizeof(fs_manifest->package[0]); i++) - { - char ext[8]; - if (fs_manifest->package[i].path && !strcmp(COM_FileExtension(fs_manifest->package[i].path, ext, sizeof(ext)), extension)) - { - palen = strlen(fs_manifest->package[i].path); - if (palen > ptlen && (fs_manifest->package[i].path[ptlen] == '/' || fs_manifest->package[i].path[ptlen] == '\\' )&& !strncmp(purepath, fs_manifest->package[i].path, ptlen)) - { - searchpath_t *oldp; - char pname[MAX_OSPATH]; - char lname[MAX_OSPATH]; - if (fs_manifest->package[i].crcknown) - snprintf(lname, sizeof(lname), "%#x", fs_manifest->package[i].crc); - else - snprintf(lname, sizeof(lname), ""); - if (!FS_GenCachedPakName(fs_manifest->package[i].path, lname, pname, sizeof(pname))) - continue; - snprintf (lname, sizeof(lname), "%s%s", logicalpaths, pname+ptlen+1); - - for (oldp = com_searchpaths; oldp; oldp = oldp->next) - { - if (!Q_strcasecmp(oldp->purepath, fs_manifest->package[i].path)) - break; - if (!Q_strcasecmp(oldp->logicalpath, lname)) - break; - } - if (!oldp) - { - handle = FS_GetOldPath(oldpaths, lname, &keptflags); - if (!handle) - { - if (search->handle->FindFile(search->handle, &loc, pname+ptlen+1, NULL)) - { - vfs = search->handle->OpenVFS(search->handle, &loc, "r"); - if (vfs) - handle = OpenNew (vfs, lname); - } - } - if (handle && fs_manifest->package[i].crcknown) - { - int truecrc = handle->GeneratePureCRC(handle, 0, false); - if (truecrc != fs_manifest->package[i].crc) - { - Con_Printf(CON_ERROR "File \"%s\" has hash %#x (required: %#x). Please delete it or move it away\n", lname, truecrc, fs_manifest->package[i].crc); - handle->ClosePath(handle); - handle = NULL; - } - } - if (handle) - FS_AddPathHandle(oldpaths, fs_manifest->package[i].path, lname, handle, SPF_COPYPROTECTED|SPF_UNTRUSTED|keptflags, (unsigned int)-1); - } - } - } - } - } + FS_AddManifestPackages(oldpaths, purepath, logicalpaths, search, extension, OpenNew); } static searchpath_t *FS_AddPathHandle(searchpath_t **oldpaths, const char *purepath, const char *logicalpath, searchpathfuncs_t *handle, unsigned int flags, unsigned int loadstuff) @@ -2308,6 +2353,43 @@ void FS_ExtractDir(char *in, char *out, int outlen) *out = 0; } +qboolean FS_PathURLCache(const char *url, char *path, size_t pathsize) +{ + const char *FS_GetCleanPath(const char *pattern, char *outbuf, int outlen); + char tmp[MAX_QPATH]; + char *o = tmp, *e = o + sizeof(tmp)-1; + const char *i = url; + strcpy(o, "downloads/"); + o += strlen(o); + while(*i) + { + if (*i == ':' || *i == '?' || *i == '*' || *i == '&') + { + if (i[0] == ':' && i[1] == '/' && i[2] == '/') + { + i+=2; + continue; + } + *o++ = '_'; + i++; + continue; + } + if (*i == '\\') + { + *o++ = '/'; + i++; + continue; + } + *o++ = *i++; + } + *o = 0; + + if (!FS_GetCleanPath(tmp, path, pathsize)) + return false; + + return true; +} + /* ================ COM_Gamedir @@ -2315,7 +2397,7 @@ COM_Gamedir Sets the gamedir and path to a different directory. ================ */ -void COM_Gamedir (const char *dir) +void COM_Gamedir (const char *dir, const struct gamepacks *packagespaths) { ftemanifest_t *man; if (!fs_manifest) @@ -2323,7 +2405,7 @@ void COM_Gamedir (const char *dir) //don't allow leading dots, hidden files are evil. //don't allow complex paths. those are evil too. - if (!*dir || *dir == '.' || !strcmp(dir, ".") || strstr(dir, "..") || strstr(dir, "/") + if (*dir == '.' || !strcmp(dir, ".") || strstr(dir, "..") || strstr(dir, "/") || strstr(dir, "\\") || strstr(dir, ":") ) { Con_Printf ("Gamedir should be a single filename, not a path\n"); @@ -2333,7 +2415,7 @@ void COM_Gamedir (const char *dir) man = NULL; if (!man) { - vfsfile_t *f = VFSOS_Open(va("%s%s.fmf", com_gamepath, dir), "rb"); + vfsfile_t *f = *dir?VFSOS_Open(va("%s%s.fmf", com_gamepath, dir), "rb"):NULL; if (f) { size_t len = VFS_GETLEN(f); @@ -2363,7 +2445,7 @@ void COM_Gamedir (const char *dir) FS_Manifest_PurgeGamedirs(man); if (*dir) { - char token[MAX_QPATH]; + char token[MAX_QPATH], quot[MAX_QPATH]; char *dup = Z_StrDup(dir); //FIXME: is this really needed? dir = dup; while ((dir = COM_ParseStringSet(dir, token, sizeof(token)))) @@ -2373,11 +2455,19 @@ void COM_Gamedir (const char *dir) if (!*token) continue; - Cmd_TokenizeString(va("gamedir \"%s\"", token), false, false); + Cmd_TokenizeString(va("gamedir %s", COM_QuotedString(token, quot, sizeof(quot), false)), false, false); FS_Manifest_ParseTokens(man); } Z_Free(dup); } + while(packagespaths && packagespaths->path) + { + char quot[MAX_QPATH]; + char quot2[MAX_OSPATH]; + Cmd_TokenizeString(va("package %s - %s", COM_QuotedString(packagespaths->path, quot, sizeof(quot), false), COM_QuotedString(packagespaths->url, quot2, sizeof(quot2), false)), false, false); + FS_Manifest_ParseTokens(man); + packagespaths++; + } } FS_ChangeGame(man, cfg_reload_on_gamedir.ival, false); } @@ -2482,7 +2572,15 @@ qboolean FS_GenCachedPakName(char *pname, char *crc, char *local, int llen) return false; } - fn = COM_SkipPath(pname); + for (fn = pname; *fn; fn++) + { + if (*fn == '\\' || *fn == '/') + { + fn++; + break; + } + } +// fn = COM_SkipPath(pname); if (fn == pname) { //only allow it if it has some game path first. *local = 0; @@ -2504,12 +2602,14 @@ qboolean FS_GenCachedPakName(char *pname, char *crc, char *local, int llen) qboolean FS_LoadPackageFromFile(vfsfile_t *vfs, char *pname, char *localname, int *crc, unsigned int flags) { int i; - char *ext = COM_FileExtension(pname); + char *ext = "zip";//(pname); searchpathfuncs_t *handle; searchpath_t *oldlist = NULL; searchpath_t *sp; + com_fschanged = true; + for (i = 0; i < sizeof(searchpathformats)/sizeof(searchpathformats[0]); i++) { if (!searchpathformats[i].extension || !searchpathformats[i].OpenNew) @@ -2536,7 +2636,7 @@ qboolean FS_LoadPackageFromFile(vfsfile_t *vfs, char *pname, char *localname, in if (sp) { - FS_FlushFSHashReally(); + com_fschanged = true; return true; } } @@ -2828,6 +2928,8 @@ void FS_ReloadPackFilesFlags(unsigned int reloadflags) } } + FS_AddDownloadManifestPackages(&oldpaths, reloadflags); + /*sv_pure: Reload pure paths*/ if (fs_purenames && fs_purecrcs) { @@ -3067,11 +3169,13 @@ static qboolean Sys_SteamHasFile(char *basepath, int basepathlen, char *steamdir DWORD resultlen; HKEY key = NULL; - if (RegOpenKeyEx(HKEY_CURRENT_USER, "SOFTWARE\\Valve\\Steam", 0, STANDARD_RIGHTS_READ|KEY_QUERY_VALUE, &key) == ERROR_SUCCESS) + if (RegOpenKeyExW(HKEY_CURRENT_USER, L"SOFTWARE\\Valve\\Steam", 0, STANDARD_RIGHTS_READ|KEY_QUERY_VALUE, &key) == ERROR_SUCCESS) { - resultlen = basepathlen; - RegQueryValueEx(key, "SteamPath", NULL, NULL, basepath, &resultlen); + wchar_t suckysucksuck[MAX_OSPATH]; + resultlen = sizeof(suckysucksuck); + RegQueryValueExW(key, L"SteamPath", NULL, NULL, (void*)suckysucksuck, &resultlen); RegCloseKey(key); + narrowen(basepath, basepathlen, suckysucksuck); Q_strncatz(basepath, va("/SteamApps/common/%s", steamdir), basepathlen); if ((f = fopen(va("%s/%s", basepath, fname), "rb"))) { @@ -3086,12 +3190,12 @@ static qboolean Sys_SteamHasFile(char *basepath, int basepathlen, char *steamdir static INT CALLBACK StupidBrowseCallbackProc(HWND hwnd, UINT uMsg, LPARAM lp, LPARAM pData) { //'stolen' from microsoft's knowledge base. //required to work around microsoft being annoying. - TCHAR szDir[MAX_PATH]; - char *foo; + wchar_t szDir[MAX_PATH]; + wchar_t *foo; switch(uMsg) { case BFFM_INITIALIZED: - if (GetCurrentDirectory(sizeof(szDir)/sizeof(TCHAR), szDir)) + if (GetCurrentDirectoryW(sizeof(szDir)/sizeof(TCHAR), szDir)) { // foo = strrchr(szDir, '\\'); // if (foo) @@ -3099,16 +3203,23 @@ static INT CALLBACK StupidBrowseCallbackProc(HWND hwnd, UINT uMsg, LPARAM lp, LP // foo = strrchr(szDir, '\\'); // if (foo) // *foo = 0; - SendMessage(hwnd, BFFM_SETSELECTION, TRUE, (LPARAM)szDir); + SendMessageW(hwnd, BFFM_SETSELECTION, TRUE, (LPARAM)szDir); } break; + case BFFM_VALIDATEFAILEDW: + break; //FIXME: validate that the gamedir contains what its meant to case BFFM_SELCHANGED: - if (SHGetPathFromIDList((LPITEMIDLIST) lp ,szDir)) + if (SHGetPathFromIDListW((LPITEMIDLIST) lp, szDir)) { - while(foo = strchr(szDir, '\\')) + wchar_t statustxt[MAX_OSPATH]; + while(foo = wcschr(szDir, '\\')) *foo = '/'; - //fixme: verify that id1 is a subdir perhaps? - SendMessage(hwnd,BFFM_SETSTATUSTEXT,0,pData?(LPARAM)va("%s/%s", szDir, pData):(LPARAM)szDir); + if (pData) + _snwprintf(statustxt, countof(statustxt), L"%s/%s", szDir, pData); + else + _snwprintf(statustxt, countof(statustxt), L"%s", szDir); + statustxt[countof(statustxt)-1] = 0; //ms really suck. + SendMessageW(hwnd,BFFM_SETSTATUSTEXT,0,(LPARAM)statustxt); } break; } @@ -3119,15 +3230,20 @@ static INT CALLBACK StupidBrowseCallbackProc(HWND hwnd, UINT uMsg, LPARAM lp, LP qboolean Sys_DoDirectoryPrompt(char *basepath, size_t basepathsize, const char *poshname, const char *savedname) { #ifndef SERVERONLY - char resultpath[MAX_PATH]; - BROWSEINFO bi; + wchar_t resultpath[MAX_OSPATH]; + wchar_t title[MAX_OSPATH]; + BROWSEINFOW bi; LPITEMIDLIST il; memset(&bi, 0, sizeof(bi)); bi.hwndOwner = mainwindow; //note that this is usually still null bi.pidlRoot = NULL; - GetCurrentDirectory(sizeof(resultpath)-1, resultpath); + GetCurrentDirectoryW(sizeof(resultpath)-1, resultpath); bi.pszDisplayName = resultpath; - bi.lpszTitle = va("Please locate your existing %s installation", poshname); + + widen(resultpath, sizeof(resultpath), poshname); + _snwprintf(title, countof(title), L"Please locate your existing %s installation", resultpath); + bi.lpszTitle = title; + bi.ulFlags = BIF_RETURNONLYFSDIRS|BIF_STATUSTEXT; bi.lpfn = StupidBrowseCallbackProc; bi.lParam = 0;//(LPARAM)poshname; @@ -3136,18 +3252,17 @@ qboolean Sys_DoDirectoryPrompt(char *basepath, size_t basepathsize, const char * //force mouse to deactivate, so that we can actually see it. INS_UpdateGrabs(false, false); - il = SHBrowseForFolder(&bi); + il = SHBrowseForFolderW(&bi); if (il) { - SHGetPathFromIDList(il, resultpath); + SHGetPathFromIDListW(il, resultpath); CoTaskMemFree(il); - Q_strncpyz(basepath, resultpath, basepathsize); - + narrowen(basepath, basepathsize, resultpath); if (savedname) { HKEY key = NULL; //and save it into the windows registry - if (RegCreateKeyEx(HKEY_CURRENT_USER, "SOFTWARE\\" FULLENGINENAME "\\GamePaths", + if (RegCreateKeyExW(HKEY_CURRENT_USER, L"SOFTWARE\\" _L(FULLENGINENAME) L"\\GamePaths", 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, @@ -3155,7 +3270,9 @@ qboolean Sys_DoDirectoryPrompt(char *basepath, size_t basepathsize, const char * &key, NULL) == ERROR_SUCCESS) { - RegSetValueEx(key, savedname, 0, REG_SZ, basepath, strlen(basepath)); + wchar_t wsavedname[MAX_OSPATH]; + widen(wsavedname, sizeof(wsavedname), savedname); + RegSetValueExW(key, wsavedname, 0, REG_SZ, (BYTE*)resultpath, sizeof(wchar_t)*wcslen(resultpath)); RegCloseKey(key); } @@ -3165,29 +3282,24 @@ qboolean Sys_DoDirectoryPrompt(char *basepath, size_t basepathsize, const char * #endif return false; } + +DWORD GetFileAttributesU(const char * lpFileName) +{ + wchar_t wide[MAX_OSPATH]; + widen(wide, sizeof(wide), lpFileName); + return GetFileAttributesW(wide); +} qboolean Sys_FindGameData(const char *poshname, const char *gamename, char *basepath, int basepathlen, qboolean allowprompts) { - DWORD resultlen; - HKEY key = NULL; - #ifndef INVALID_FILE_ATTRIBUTES #define INVALID_FILE_ATTRIBUTES ((DWORD)-1) #endif //first, try and find it in our game paths location - if (RegOpenKeyEx(HKEY_CURRENT_USER, "SOFTWARE\\" FULLENGINENAME "\\GamePaths", 0, STANDARD_RIGHTS_READ|KEY_QUERY_VALUE, &key) == ERROR_SUCCESS) + if (MyRegGetStringValue(HKEY_CURRENT_USER, "SOFTWARE\\" FULLENGINENAME "\\GamePaths", gamename, basepath, basepathlen)) { - resultlen = basepathlen; - if (!RegQueryValueEx(key, gamename, NULL, NULL, basepath, &resultlen)) - { - if (GetFileAttributes(basepath) != INVALID_FILE_ATTRIBUTES) - { - RegCloseKey(key); - return true; - } - } - - RegCloseKey(key); + if (GetFileAttributesU(basepath) != INVALID_FILE_ATTRIBUTES) + return true; } @@ -3197,8 +3309,10 @@ qboolean Sys_FindGameData(const char *poshname, const char *gamename, char *base { "c:/quake/", //quite a lot of people have it in c:\quake, as that's the default install location from the quake cd. "c:/games/quake/", //personally I use this + + "c:/nquake/", //nquake seems to have moved out of programfiles now. woo. #ifdef _WIN64 - //quite a few people have nquake installed. we need to an api function to read the directory for non-english-windows users. + //quite a few people have nquake installed. FIXME: we need to an api function to read the directory for non-english-windows users. va("%s/nQuake/", getenv("%ProgramFiles(x86)%")), //64bit builds should look in both places va("%s/nQuake/", getenv("%ProgramFiles%")), // #else @@ -3207,7 +3321,6 @@ qboolean Sys_FindGameData(const char *poshname, const char *gamename, char *base NULL }; int i; - FILE *f; //try and find it via steam //reads HKEY_LOCAL_MACHINE\SOFTWARE\Valve\Steam\InstallPath @@ -3222,9 +3335,14 @@ qboolean Sys_FindGameData(const char *poshname, const char *gamename, char *base { char syspath[MAX_OSPATH]; Q_snprintfz(syspath, sizeof(syspath), "%sid1/pak0.pak", prefix[i]); - if ((f = fopen("c:/quake/quake.exe", "rb"))) + if (GetFileAttributesU(syspath) != INVALID_FILE_ATTRIBUTES) + { + Q_strncpyz(basepath, prefix[i], sizeof(basepath)); + return true; + } + Q_snprintfz(syspath, sizeof(syspath), "%squake.exe", prefix[i]); + if (GetFileAttributesU(syspath) != INVALID_FILE_ATTRIBUTES) { - fclose(f); Q_strncpyz(basepath, prefix[i], sizeof(basepath)); return true; } @@ -3233,21 +3351,11 @@ qboolean Sys_FindGameData(const char *poshname, const char *gamename, char *base if (!strcmp(gamename, "quake2")) { - FILE *f; - DWORD resultlen; - HKEY key = NULL; - //look for HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\Quake2_exe\Path - if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\App Paths\\Quake2_exe", 0, STANDARD_RIGHTS_READ|KEY_QUERY_VALUE, &key) == ERROR_SUCCESS) + if (MyRegGetStringValue(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\App Paths\\Quake2_exe", "Path", basepath, basepathlen)) { - resultlen = basepathlen; - RegQueryValueEx(key, "Path", NULL, NULL, basepath, &resultlen); - RegCloseKey(key); - if ((f = fopen(va("%s/quake2.exe", basepath), "rb"))) - { - fclose(f); + if (GetFileAttributesU(va("%s/quake2.exe", basepath)) != INVALID_FILE_ATTRIBUTES) return true; - } } if (Sys_SteamHasFile(basepath, basepathlen, "quake 2", "quake2.exe")) @@ -3256,43 +3364,22 @@ qboolean Sys_FindGameData(const char *poshname, const char *gamename, char *base if (!strcmp(gamename, "et")) { - FILE *f; - DWORD resultlen; - HKEY key = NULL; //reads HKEY_LOCAL_MACHINE\SOFTWARE\Activision\Wolfenstein - Enemy Territory - if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\Activision\\Wolfenstein - Enemy Territory", 0, STANDARD_RIGHTS_READ|KEY_QUERY_VALUE, &key) == ERROR_SUCCESS) + if (MyRegGetStringValue(HKEY_LOCAL_MACHINE, "SOFTWARE\\Activision\\Wolfenstein - Enemy Territory", "InstallPath", basepath, basepathlen)) { - resultlen = basepathlen; - RegQueryValueEx(key, "InstallPath", NULL, NULL, basepath, &resultlen); - RegCloseKey(key); - - if ((f = fopen(va("%s/ET.exe", basepath), "rb"))) - { - fclose(f); - return true; - } +// if (GetFileAttributesU(va("%s/ET.exe", basepath) != INVALID_FILE_ATTRIBUTES) +// return true; return true; } } if (!strcmp(gamename, "quake3")) { - FILE *f; - DWORD resultlen; - HKEY key = NULL; - //reads HKEY_LOCAL_MACHINE\SOFTWARE\id\Quake III Arena\InstallPath - if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\id\\Quake III Arena", 0, STANDARD_RIGHTS_READ|KEY_QUERY_VALUE, &key) == ERROR_SUCCESS) + if (MyRegGetStringValue(HKEY_LOCAL_MACHINE, "SOFTWARE\\id\\Quake III Arena", "InstallPath", basepath, basepathlen)) { - resultlen = basepathlen; - RegQueryValueEx(key, "InstallPath", NULL, NULL, basepath, &resultlen); - RegCloseKey(key); - - if ((f = fopen(va("%s/quake3.exe", basepath), "rb"))) - { - fclose(f); + if (GetFileAttributesU(va("%s/quake3.exe", basepath)) != INVALID_FILE_ATTRIBUTES) return true; - } } if (Sys_SteamHasFile(basepath, basepathlen, "quake 3 arena", "quake3.exe")) @@ -3301,31 +3388,16 @@ qboolean Sys_FindGameData(const char *poshname, const char *gamename, char *base if (!strcmp(gamename, "wop")) { - DWORD resultlen; - HKEY key = NULL; - //reads HKEY_LOCAL_MACHINE\SOFTWARE\World Of Padman\Path - if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\World Of Padman", 0, STANDARD_RIGHTS_READ|KEY_QUERY_VALUE, &key) == ERROR_SUCCESS) - { - resultlen = basepathlen; - RegQueryValueEx(key, "Path", NULL, NULL, basepath, &resultlen); - RegCloseKey(key); + if (MyRegGetStringValue(HKEY_LOCAL_MACHINE, "SOFTWARE\\World Of Padman", "Path", basepath, basepathlen)) return true; - } } /* if (!strcmp(gamename, "d3")) { - DWORD resultlen; - HKEY key = NULL; //reads HKEY_LOCAL_MACHINE\SOFTWARE\id\Doom 3\InstallPath - if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\id\\Doom 3", 0, STANDARD_RIGHTS_READ|KEY_QUERY_VALUE, &key) == ERROR_SUCCESS) - { - resultlen = basepathlen; - RegQueryValueEx(key, "InstallPath", NULL, NULL, basepath, &resultlen); - RegCloseKey(key); + if (MyRegGetStringValue(HKEY_LOCAL_MACHINE, L"SOFTWARE\\id\\Doom 3", "InstallPath", basepath, basepathlen)) return true; - } } */ @@ -4668,7 +4740,7 @@ qboolean FS_FixupGamedirForExternalFile(char *input, char *filename, size_t fnam { Con_Printf("switching gamedir for %s\n", filename); *sep = 0; - COM_Gamedir(filename); + COM_Gamedir(filename, NULL); memmove(filename, sep+1, strlen(sep+1)+1); return true; } @@ -4767,22 +4839,28 @@ void COM_InitFilesystem (void) #if defined(_WIN32) && !defined(WINRT) { //win32 sucks. - HMODULE shfolder = LoadLibrary("shfolder.dll"); - DWORD winver = (DWORD)LOBYTE(LOWORD(GetVersion())); - - if (shfolder) + HRESULT (WINAPI *dSHGetFolderPathW) (HWND hwndOwner, int nFolder, HANDLE hToken, DWORD dwFlags, wchar_t *pszPath) = NULL; + dllfunction_t funcs[] = { - HRESULT (WINAPI *dSHGetFolderPath) (HWND hwndOwner, int nFolder, HANDLE hToken, DWORD dwFlags, LPTSTR pszPath); - dSHGetFolderPath = (void *)GetProcAddress(shfolder, "SHGetFolderPathA"); - if (dSHGetFolderPath) + {(void**)&dSHGetFolderPathW, "SHGetFolderPathW"}, + {NULL,NULL} + }; + DWORD winver = (DWORD)LOBYTE(LOWORD(GetVersion())); + /*HMODULE shfolder =*/ Sys_LoadLibrary("shfolder.dll", funcs); + + if (dSHGetFolderPathW) + { + wchar_t wfolder[MAX_PATH]; + char folder[MAX_PATH]; + // 0x5 == CSIDL_PERSONAL + if (dSHGetFolderPathW(NULL, 0x5, NULL, 0, wfolder) == S_OK) { - char folder[MAX_PATH]; - // 0x5 == CSIDL_PERSONAL - if (dSHGetFolderPath(NULL, 0x5, NULL, 0, folder) == S_OK) - Q_snprintfz(com_homepath, sizeof(com_homepath), "%s/My Games/%s/", folder, FULLENGINENAME); + narrowen(folder, sizeof(folder), wfolder); + Q_snprintfz(com_homepath, sizeof(com_homepath), "%s/My Games/%s/", folder, FULLENGINENAME); } -// FreeLibrary(shfolder); } +// if (shfolder) +// FreeLibrary(shfolder); if (!*com_homepath) { @@ -4803,13 +4881,15 @@ void COM_InitFilesystem (void) else if (winver >= 0x5) // Windows 2000/XP/2003 { HMODULE advapi32; - advapi32 = LoadLibrary("advapi32.dll"); - + BOOL (WINAPI *dCheckTokenMembership) (HANDLE TokenHandle, PSID SidToCheck, PBOOL IsMember) = NULL; + dllfunction_t funcs[] = + { + {(void**)&dCheckTokenMembership, "CheckTokenMembership"}, + {NULL,NULL} + }; + advapi32 = Sys_LoadLibrary("advapi32.dll", funcs); if (advapi32) { - BOOL (WINAPI *dCheckTokenMembership) (HANDLE TokenHandle, PSID SidToCheck, PBOOL IsMember); - dCheckTokenMembership = (void *)GetProcAddress(advapi32, "CheckTokenMembership"); - if (dCheckTokenMembership) { // on XP systems, only use a home directory by default if we're a limited user or if we're on a network @@ -4843,7 +4923,7 @@ void COM_InitFilesystem (void) FreeSid(adminSID); } - FreeLibrary(advapi32); + Sys_CloseLibrary(advapi32); } } #endif diff --git a/engine/common/net_ssl_winsspi.c b/engine/common/net_ssl_winsspi.c index 0219d2de5..6d5088949 100644 --- a/engine/common/net_ssl_winsspi.c +++ b/engine/common/net_ssl_winsspi.c @@ -28,7 +28,7 @@ static struct BOOL (WINAPI *pCertGetCertificateChain) (HCERTCHAINENGINE,PCCERT_CONTEXT,LPFILETIME,HCERTSTORE,PCERT_CHAIN_PARA,DWORD,LPVOID,PCCERT_CHAIN_CONTEXT*); BOOL (WINAPI *pCertVerifyCertificateChainPolicy) (LPCSTR,PCCERT_CHAIN_CONTEXT,PCERT_CHAIN_POLICY_PARA,PCERT_CHAIN_POLICY_STATUS); void (WINAPI *pCertFreeCertificateChain) (PCCERT_CHAIN_CONTEXT); - DWORD (WINAPI *pCertNameToStrA) (DWORD dwCertEncodingType, PCERT_NAME_BLOB pName, DWORD dwStrType, LPTSTR psz, DWORD csz); + DWORD (WINAPI *pCertNameToStrA) (DWORD dwCertEncodingType, PCERT_NAME_BLOB pName, DWORD dwStrType, LPCSTR psz, DWORD csz); PCCERT_CONTEXT (WINAPI *pCertCreateSelfSignCertificate) (HCRYPTPROV,PCERT_NAME_BLOB,DWORD,PCRYPT_KEY_PROV_INFO,PCRYPT_ALGORITHM_IDENTIFIER,PSYSTEMTIME,PSYSTEMTIME,PCERT_EXTENSIONS); BOOL (WINAPI *pCertStrToNameA) (DWORD,LPCSTR,DWORD,void *,BYTE *,DWORD *,LPCSTR *); @@ -112,15 +112,6 @@ typedef struct { char headerdata[1024], footerdata[1024]; } sslfile_t; -static int SSPI_CopyIntoBuffer(struct sslbuf *buf, const void *data, unsigned int bytes) -{ - if (bytes > buf->datasize - buf->avail) - bytes = buf->datasize - buf->avail; - memcpy(buf->data + buf->avail, data, bytes); - buf->avail += bytes; - - return bytes; -} static int SSPI_ExpandBuffer(struct sslbuf *buf, size_t bytes) { if (bytes < buf->datasize) @@ -129,6 +120,19 @@ static int SSPI_ExpandBuffer(struct sslbuf *buf, size_t bytes) return bytes; } +static int SSPI_CopyIntoBuffer(struct sslbuf *buf, const void *data, unsigned int bytes, qboolean expand) +{ + if (bytes > buf->datasize - buf->avail) + { + if (!expand || SSPI_ExpandBuffer(buf, buf->avail + bytes + 1024) < buf->avail + bytes) + bytes = buf->datasize - buf->avail; + } + memcpy(buf->data + buf->avail, data, bytes); + buf->avail += bytes; + + return bytes; +} + static void SSPI_Error(sslfile_t *f, char *error) { f->handshaking = HS_ERROR; @@ -177,7 +181,6 @@ static void SSPI_Decode(sslfile_t *f) SecBufferDesc BuffDesc; SecBuffer SecBuff[4]; ULONG ulQop = 0; - SecBuffer *data = NULL; SecBuffer *extra = NULL; int i; @@ -216,16 +219,28 @@ static void SSPI_Decode(sslfile_t *f) for (i = 0; i < BuffDesc.cBuffers; i++) { - if (SecBuff[i].BufferType == SECBUFFER_DATA && !data) - data = &SecBuff[i]; - if (SecBuff[i].BufferType == SECBUFFER_EXTRA && !extra) + switch(SecBuff[i].BufferType) + { + case SECBUFFER_DATA: + if (SSPI_CopyIntoBuffer(&f->inraw, SecBuff[i].pvBuffer, SecBuff[i].cbBuffer, true) != SecBuff[i].cbBuffer) + SSPI_Error(f, "outraw buffer overflowed\n"); + break; + case SECBUFFER_EXTRA: + if (extra) + SSPI_Error(f, "multiple extra buffers\n"); extra = &SecBuff[i]; + break; + case SECBUFFER_EMPTY: + case SECBUFFER_MISSING: + case SECBUFFER_STREAM_TRAILER: + case SECBUFFER_STREAM_HEADER: + break; + default: + SSPI_Error(f, "got unexpected buffer type\n"); + break; + } } - //copy the data out to the result, yay. - if (data) - SSPI_CopyIntoBuffer(&f->inraw, data->pvBuffer, data->cbBuffer); - //retain the extra. if there's no extra then mark it so. if (extra) { @@ -288,17 +303,17 @@ static void SSPI_Encode(sslfile_t *f) f->outraw.avail = 0; //fixme: these should be made non-fatal. - if (SSPI_CopyIntoBuffer(&f->outcrypt, SecBuff[0].pvBuffer, SecBuff[0].cbBuffer) < SecBuff[0].cbBuffer) + if (SSPI_CopyIntoBuffer(&f->outcrypt, SecBuff[0].pvBuffer, SecBuff[0].cbBuffer, true) < SecBuff[0].cbBuffer) { SSPI_Error(f, "crypt buffer overflowed\n"); return; } - if (SSPI_CopyIntoBuffer(&f->outcrypt, SecBuff[1].pvBuffer, SecBuff[1].cbBuffer) < SecBuff[1].cbBuffer) + if (SSPI_CopyIntoBuffer(&f->outcrypt, SecBuff[1].pvBuffer, SecBuff[1].cbBuffer, true) < SecBuff[1].cbBuffer) { SSPI_Error(f, "crypt buffer overflowed\n"); return; } - if (SSPI_CopyIntoBuffer(&f->outcrypt, SecBuff[2].pvBuffer, SecBuff[2].cbBuffer) < SecBuff[2].cbBuffer) + if (SSPI_CopyIntoBuffer(&f->outcrypt, SecBuff[2].pvBuffer, SecBuff[2].cbBuffer, true) < SecBuff[2].cbBuffer) { SSPI_Error(f, "crypt buffer overflowed\n"); return; @@ -686,7 +701,7 @@ static void SSPI_Handshake (sslfile_t *f) } } - if (SSPI_CopyIntoBuffer(&f->outcrypt, OutSecBuff.pvBuffer, OutSecBuff.cbBuffer) < OutSecBuff.cbBuffer) + if (SSPI_CopyIntoBuffer(&f->outcrypt, OutSecBuff.pvBuffer, OutSecBuff.cbBuffer, true) < OutSecBuff.cbBuffer) { SSPI_Error(f, "crypt overflow\n"); return; @@ -765,7 +780,12 @@ static int QDECL SSPI_WriteBytes (struct vfsfile_s *file, const void *buffer, in { sslfile_t *f = (sslfile_t *)file; - bytestowrite = SSPI_CopyIntoBuffer(&f->outraw, buffer, bytestowrite); + //don't endlessly accept data faster than we can push it out. + //we'll buffer a little, but don't go overboard + if (f->outcrypt.avail > 8192) + return false; + + bytestowrite = SSPI_CopyIntoBuffer(&f->outraw, buffer, bytestowrite, false); if (f->handshaking) { diff --git a/engine/common/net_wins.c b/engine/common/net_wins.c index 1ae5e9e82..b230be922 100644 --- a/engine/common/net_wins.c +++ b/engine/common/net_wins.c @@ -5556,21 +5556,13 @@ void NET_Init (void) #if defined(_WIN32) && defined(HAVE_PACKET) int r; #ifdef IPPROTO_IPV6 - HMODULE ws2_32dll; - ws2_32dll = LoadLibrary("ws2_32.dll"); - if (ws2_32dll) + dllfunction_t fncs[] = { - pfreeaddrinfo = (void *)GetProcAddress(ws2_32dll, "freeaddrinfo"); - pgetaddrinfo = (void *)GetProcAddress(ws2_32dll, "getaddrinfo"); - if (!pgetaddrinfo || !pfreeaddrinfo) - { - pgetaddrinfo = NULL; - pfreeaddrinfo = NULL; - FreeLibrary(ws2_32dll); - } - } - else - pgetaddrinfo = NULL; + {(void**)&pfreeaddrinfo, "getaddrinfo"}, + {(void**)&pgetaddrinfo, "freeaddrinfo"}, + {NULL, NULL} + }; + Sys_LoadLibrary("ws2_32.dll", fncs); #endif r = WSAStartup (MAKEWORD(2, 2), &winsockdata); diff --git a/engine/common/pr_bgcmd.c b/engine/common/pr_bgcmd.c index 1a48b8b41..9f348f562 100644 --- a/engine/common/pr_bgcmd.c +++ b/engine/common/pr_bgcmd.c @@ -236,7 +236,7 @@ qboolean QCExternalDebuggerCommand(char *text) if (sv.state) Cbuf_AddText("restart\n", RESTRICT_LOCAL); #endif - Host_EndGame("Reloading QC"); +// Host_EndGame("Reloading QC"); } else if (!strncmp(text, "qcbreakpoint ", 13)) { diff --git a/engine/dotnet2005/ftequake.sln b/engine/dotnet2005/ftequake.sln index 3abda8a27..57c2d20f1 100644 --- a/engine/dotnet2005/ftequake.sln +++ b/engine/dotnet2005/ftequake.sln @@ -1,12 +1,5 @@ Microsoft Visual Studio Solution File, Format Version 9.00 # Visual Studio 2005 -Project("{54435603-DBB4-11D2-8724-00A0C9A8B90C}") = "FTEQuake", "..\setup\setup.vdproj", "{E0EE8B50-3A75-42A9-B80A-787675979B0C}" - ProjectSection(ProjectDependencies) = postProject - {72269FEE-293D-40BC-A7AE-E429F4496869} = {72269FEE-293D-40BC-A7AE-E429F4496869} - {9767E236-8454-44E9-8999-CD5BDAFBE9BA} = {9767E236-8454-44E9-8999-CD5BDAFBE9BA} - {82285268-9C3B-44AD-BBE7-40670F9D2628} = {82285268-9C3B-44AD-BBE7-40670F9D2628} - EndProjectSection -EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "botlib", "botlib.vcproj", "{0018E098-B12A-4E4D-9B22-6772DA287080}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "fteqcc", "..\qclib\dotnet2005\qcc.vcproj", "{2866F783-6B44-4655-A38D-D53874037454}" @@ -86,33 +79,6 @@ Global Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {E0EE8B50-3A75-42A9-B80A-787675979B0C}.D3DDebug|Win32.ActiveCfg = Release - {E0EE8B50-3A75-42A9-B80A-787675979B0C}.D3DDebug|x64.ActiveCfg = Release - {E0EE8B50-3A75-42A9-B80A-787675979B0C}.D3DRelease|Win32.ActiveCfg = Release - {E0EE8B50-3A75-42A9-B80A-787675979B0C}.D3DRelease|x64.ActiveCfg = Release - {E0EE8B50-3A75-42A9-B80A-787675979B0C}.D3DRelease|x64.Build.0 = Release - {E0EE8B50-3A75-42A9-B80A-787675979B0C}.Debug Dedicated Server|Win32.ActiveCfg = Debug - {E0EE8B50-3A75-42A9-B80A-787675979B0C}.Debug Dedicated Server|x64.ActiveCfg = Debug - {E0EE8B50-3A75-42A9-B80A-787675979B0C}.Debug|Win32.ActiveCfg = Debug - {E0EE8B50-3A75-42A9-B80A-787675979B0C}.Debug|x64.ActiveCfg = Release - {E0EE8B50-3A75-42A9-B80A-787675979B0C}.Debug|x64.Build.0 = Release - {E0EE8B50-3A75-42A9-B80A-787675979B0C}.GLDebug|Win32.ActiveCfg = Debug - {E0EE8B50-3A75-42A9-B80A-787675979B0C}.GLDebug|x64.ActiveCfg = Debug - {E0EE8B50-3A75-42A9-B80A-787675979B0C}.GLRelease|Win32.ActiveCfg = Release - {E0EE8B50-3A75-42A9-B80A-787675979B0C}.GLRelease|x64.ActiveCfg = Release - {E0EE8B50-3A75-42A9-B80A-787675979B0C}.MDebug|Win32.ActiveCfg = Debug - {E0EE8B50-3A75-42A9-B80A-787675979B0C}.MDebug|x64.ActiveCfg = Release - {E0EE8B50-3A75-42A9-B80A-787675979B0C}.MDebug|x64.Build.0 = Release - {E0EE8B50-3A75-42A9-B80A-787675979B0C}.MinGLDebug|Win32.ActiveCfg = Debug - {E0EE8B50-3A75-42A9-B80A-787675979B0C}.MinGLDebug|x64.ActiveCfg = Debug - {E0EE8B50-3A75-42A9-B80A-787675979B0C}.MinGLRelease|Win32.ActiveCfg = Release - {E0EE8B50-3A75-42A9-B80A-787675979B0C}.MinGLRelease|x64.ActiveCfg = Debug - {E0EE8B50-3A75-42A9-B80A-787675979B0C}.MRelease|Win32.ActiveCfg = Release - {E0EE8B50-3A75-42A9-B80A-787675979B0C}.MRelease|x64.ActiveCfg = Debug - {E0EE8B50-3A75-42A9-B80A-787675979B0C}.Release Dedicated Server|Win32.ActiveCfg = Release - {E0EE8B50-3A75-42A9-B80A-787675979B0C}.Release Dedicated Server|x64.ActiveCfg = Release - {E0EE8B50-3A75-42A9-B80A-787675979B0C}.Release|Win32.ActiveCfg = Release - {E0EE8B50-3A75-42A9-B80A-787675979B0C}.Release|x64.ActiveCfg = Release {0018E098-B12A-4E4D-9B22-6772DA287080}.D3DDebug|Win32.ActiveCfg = Release|Win32 {0018E098-B12A-4E4D-9B22-6772DA287080}.D3DDebug|Win32.Build.0 = Release|Win32 {0018E098-B12A-4E4D-9B22-6772DA287080}.D3DDebug|x64.ActiveCfg = Release|Win32 diff --git a/engine/gl/gl_model.c b/engine/gl/gl_model.c index 0e316b5d4..bbf4e509d 100644 --- a/engine/gl/gl_model.c +++ b/engine/gl/gl_model.c @@ -1647,34 +1647,44 @@ void Mod_LoadLighting (model_t *loadmodel, qbyte *mod_base, lump_t *l, qboolean #ifndef SERVERONLY if (!litdata && r_loadlits.value) { - char *litname; - char litnamemaps[MAX_QPATH]; - char litnamelits[MAX_QPATH]; - int depthmaps; - int depthlits; + char *litnames[] = { + "maps/%s.lit2", + "maps/%s.lit", + "lits/%s.lit2", + "lits/%s.lit" + }; + char litbase[MAX_QPATH]; + int depth; + int bestdepth = 0x7fffffff; + int best = -1; + int i; + char litname[MAX_QPATH]; size_t litsize; qboolean inhibitvalidation = false; - - { - Q_strncpyz(litnamemaps, loadmodel->name, sizeof(litnamelits)); - COM_StripExtension(loadmodel->name, litnamemaps, sizeof(litnamemaps)); - COM_DefaultExtension(litnamemaps, ".lit", sizeof(litnamemaps)); - depthmaps = COM_FDepthFile(litnamemaps, false); - } + + COM_StripExtension(loadmodel->name, litbase, sizeof(litbase)); + for (i = 0; i < sizeof(litnames)/sizeof(litnames[0]); i++) { - Q_strncpyz(litnamelits, "lits/", sizeof(litnamelits)); - COM_StripExtension(COM_SkipPath(loadmodel->name), litnamelits+5, sizeof(litnamelits) - 5); - Q_strncatz(litnamelits, ".lit", sizeof(litnamelits)); - depthlits = COM_FDepthFile(litnamelits, false); + Q_snprintfz(litname, sizeof(litname), litnames[i], litbase); + depth = COM_FDepthFile(litname, false); + if (depth < bestdepth) + { + bestdepth = depth; + best = i; + } + } + if (best >= 0) + { + Q_snprintfz(litname, sizeof(litname), litnames[best], litbase); + litdata = FS_LoadMallocGroupFile(&loadmodel->memgroup, litname, &litsize); + } + else + { + litdata = NULL; + litsize = 0; } - if (depthmaps <= depthlits) - litname = litnamemaps; //maps has priority over lits - else - litname = litnamelits; - - litdata = FS_LoadMallocGroupFile(&loadmodel->memgroup, litname, &litsize); - if (litdata) + if (litdata && litsize >= 8) { //validate it, if we loaded one. if (litdata[0] != 'Q' || litdata[1] != 'L' || litdata[2] != 'I' || litdata[3] != 'T') { @@ -2531,7 +2541,7 @@ void ModQ1_Batches_BuildQ1Q2Poly(model_t *mod, msurface_t *surf, builddata_t *co float *vec; float s, t, d; int sty; - int w,h; +// int w,h; //output the mesh's indicies for (i=0 ; inumvertexes-2 ; i++) diff --git a/engine/gl/gl_ngraph.c b/engine/gl/gl_ngraph.c index 21ce2f457..a08179596 100644 --- a/engine/gl/gl_ngraph.c +++ b/engine/gl/gl_ngraph.c @@ -38,30 +38,43 @@ static void R_LineGraph (int x, int h) { int i; int s; - int color; + int color, color2 = 0xff; s = NET_GRAPHHEIGHT; - if (h == 10000) - color = 0x6f; // yellow + if (h == 10000 || h<0) + { + color = 0; // yellow + color2 = 1; + h=abs(h); + } else if (h == 9999) - color = 0x4f; // red + { + color = 2; // red + color2 = 3; + } else if (h == 9998) - color = 0xd0; // blue + { + color = 4; // blue + color2 = 5; + } else - color = 0xfe; // white + { + color = 6; // white + color2 = 7; + } if (h>s) h = s; for (i=0 ; i= 0) + last = -last; + R_LineGraph (NET_TIMINGS-1-a, last); } } // now load the netgraph texture into gl and draw it for (y = 0; y < NET_GRAPHHEIGHT; y++) for (x = 0; x < NET_TIMINGS; x++) - ngraph_pixels[y][x] = d_8to24rgbtable[ngraph_texels[y][x]]; + ngraph_pixels[y][x] = ngraph_palette[ngraph_texels[y][x]]; x = ((vid.width - 320)>>1); x=-x; diff --git a/engine/gl/gl_rmain.c b/engine/gl/gl_rmain.c index 175611d26..8125d5614 100644 --- a/engine/gl/gl_rmain.c +++ b/engine/gl/gl_rmain.c @@ -1354,12 +1354,10 @@ static void R_RenderMotionBlur(void) "}\n" "}\n" ); -// GLBE_RenderToTexture(sceneblur_texture, r_nulltex, r_nulltex, r_nulltex, false); - Con_Printf("FIXME: tex_sourcecolour = sceneblur_texture\n"); + GLBE_FBO_Sources(sceneblur_texture, r_nulltex); R2D_ImageColours(1, 1, 1, gl_motionblur.value); R2D_Image(0, 0, vid.width, vid.height, cs-vs, ct+vt, cs+vs, ct-vt, shader); - Con_Printf("FIXME: tex_sourcecolour = reset\n"); -// GLBE_RenderToTexture(r_nulltex, r_nulltex, r_nulltex, r_nulltex, false); + GLBE_RenderToTextureUpdate2d(false); //grab the current image so we can feed that back into the next frame. GL_MTBind(0, GL_TEXTURE_2D, sceneblur_texture); @@ -1786,8 +1784,8 @@ void GLR_RenderView (void) GLBE_FBO_Sources(r_nulltex, r_nulltex); -// if (gl_motionblur.value>0 && gl_motionblur.value < 1 && qglCopyTexImage2D) -// R_RenderMotionBlur(); + if (gl_motionblur.value>0 && gl_motionblur.value < 1 && qglCopyTexImage2D) + R_RenderMotionBlur(); checkglerror(); } diff --git a/engine/gl/gl_vidcommon.c b/engine/gl/gl_vidcommon.c index 20c8ab8a4..f89b03fd8 100644 --- a/engine/gl/gl_vidcommon.c +++ b/engine/gl/gl_vidcommon.c @@ -1387,7 +1387,7 @@ static const char *glsl_hdrs[] = #endif "}\n" "#else\n" - "#define skeletaltransform() ftetransform()\n" + "#define skeletaltransform ftetransform\n" "vec4 skeletaltransform_wnst(out vec3 w, out vec3 n, out vec3 t, out vec3 b)" "{" "n = v_normal;" @@ -1820,8 +1820,12 @@ static GLhandleARB GLSlang_CreateShader (const char *name, int ver, const char * "#define v_position v_position1\n" "#endif\n" "uniform mat4 m_modelviewprojection;\n" -// "#define ftetransform() (m_modelviewprojection * vec4(v_position, 1.0))\n" +#if 1//def FTE_TARGET_WEB + //IE is buggy "vec4 ftetransform() { return m_modelviewprojection * vec4(v_position, 1.0); }\n" +#else + "#define ftetransform() (m_modelviewprojection * vec4(v_position, 1.0))\n" +#endif ; length[strings] = strlen(prstrings[strings]); strings++; diff --git a/engine/gl/gl_vidnt.c b/engine/gl/gl_vidnt.c index 6363c77d5..4a3d9826a 100644 --- a/engine/gl/gl_vidnt.c +++ b/engine/gl/gl_vidnt.c @@ -79,7 +79,7 @@ typedef BOOL (WINAPI *lpfnSetLayeredWindowAttributes)(HWND hwnd, COLORREF crKey, extern cvar_t vid_conwidth, vid_conautoscale; -#define WINDOW_CLASS_NAME "FTEGLQuake" +#define WINDOW_CLASS_NAME L"FTEGLQuake" #define MAX_MODE_LIST 128 #define VID_ROW_SIZE 3 @@ -187,8 +187,8 @@ extern cvar_t vid_gl_context_selfreset; int window_center_x, window_center_y, window_x, window_y, window_width, window_height; RECT window_rect; -HMODULE hInstGL = NULL; -HMODULE hInstwgl = NULL; +dllhandle_t *hInstGL = NULL; +dllhandle_t *hInstwgl = NULL; static qboolean usingminidriver; static char reqminidriver[MAX_OSPATH]; static char opengldllname[MAX_OSPATH]; @@ -387,7 +387,7 @@ void *getwglfunc(char *name) if (!hInstwgl) { TRACE(("dbg: getwglfunc: explicitly loading opengl32.dll\n", name)); - hInstwgl = LoadLibrary("opengl32.dll"); + hInstwgl = LoadLibraryA("opengl32.dll"); } TRACE(("dbg: getwglfunc: %s: wglgetting\n", name)); proc = GetProcAddress(hInstwgl, name); @@ -459,10 +459,10 @@ qboolean GLInitialise (char *renderer) { usingminidriver = false; if (hInstGL) - FreeLibrary(hInstGL); + Sys_CloseLibrary(hInstGL); hInstGL=NULL; if (hInstwgl) - FreeLibrary(hInstwgl); + Sys_CloseLibrary(hInstwgl); hInstwgl=NULL; Q_strncpyz(reqminidriver, renderer, sizeof(reqminidriver)); @@ -471,8 +471,7 @@ qboolean GLInitialise (char *renderer) if (*renderer && stricmp(renderer, "opengl32.dll") && stricmp(renderer, "opengl32")) { Con_DPrintf ("Loading renderer dll \"%s\"", renderer); - hInstGL = LoadLibrary(opengldllname); - + hInstGL = Sys_LoadLibrary(opengldllname, NULL); if (hInstGL) { usingminidriver = true; @@ -490,7 +489,7 @@ qboolean GLInitialise (char *renderer) strcpy(opengldllname, "opengl32"); Con_DPrintf ("Loading renderer dll \"%s\"", opengldllname); emode = SetErrorMode(SEM_FAILCRITICALERRORS); /*no annoying errors if they use glide*/ - hInstGL = LoadLibrary(opengldllname); + hInstGL = Sys_LoadLibrary(opengldllname, NULL); SetErrorMode(emode); if (hInstGL) @@ -766,10 +765,10 @@ qboolean VID_SetWindowedMode (rendererstate_t *info) WindowRect = centerrect(pleft, ptop, pwidth, pheight, wwidth, wheight); // Create the DIB window - dibwindow = CreateWindowEx ( + dibwindow = CreateWindowExW ( ExWindowStyle, WINDOW_CLASS_NAME, - FULLENGINENAME, + _L(FULLENGINENAME), WindowStyle, WindowRect.left, WindowRect.top, WindowRect.right - WindowRect.left, @@ -797,7 +796,7 @@ qboolean VID_SetWindowedMode (rendererstate_t *info) av = 70; if (av < 255) { - HMODULE hm = GetModuleHandle("user32.dll"); + HMODULE hm = GetModuleHandleA("user32.dll"); lpfnSetLayeredWindowAttributes pSetLayeredWindowAttributes; pSetLayeredWindowAttributes = (void*)GetProcAddress(hm, "SetLayeredWindowAttributes"); @@ -864,7 +863,9 @@ qboolean VID_SetWindowedMode (rendererstate_t *info) void GLVID_SetCaption(char *text) { - SetWindowText(mainwindow, text); + wchar_t wide[2048]; + widen(wide, sizeof(wide), text); + SetWindowTextW(mainwindow, wide); } @@ -926,10 +927,10 @@ qboolean VID_SetFullDIBMode (rendererstate_t *info) wheight = rect.bottom - rect.top; // Create the DIB window - dibwindow = CreateWindowEx ( + dibwindow = CreateWindowExW ( ExWindowStyle, WINDOW_CLASS_NAME, - FULLENGINENAME, + _L(FULLENGINENAME), WindowStyle, rect.left, rect.top, wwidth, @@ -1001,6 +1002,21 @@ static void Win_Touch_Init(HWND wnd); static qboolean CreateMainWindow(rendererstate_t *info) { qboolean stat; + WNDCLASSW wc; + /* Register the frame class */ + wc.style = CS_OWNDC; + wc.lpfnWndProc = (WNDPROC)GLMainWndProc; + wc.cbClsExtra = 0; + wc.cbWndExtra = 0; + wc.hInstance = global_hInstance; + wc.hIcon = hIcon; + wc.hCursor = hArrowCursor; + wc.hbrBackground = NULL; + wc.lpszMenuName = 0; + wc.lpszClassName = WINDOW_CLASS_NAME; + if (!RegisterClassW (&wc)) //this isn't really fatal, we'll let the CreateWindow fail instead. + Con_Printf("RegisterClass failed\n"); + if (!info->fullscreen) { TRACE(("dbg: GLVID_SetMode: VID_SetWindowedMode\n")); @@ -1032,10 +1048,10 @@ int GLVID_WindowThread(void *cond) wnd = mainwindow; Sys_ConditionSignal(cond); - while (GetMessage(&msg, NULL, 0, 0)) + while (GetMessageW(&msg, NULL, 0, 0)) { - TranslateMessage (&msg); - DispatchMessage (&msg); + TranslateMessageW (&msg); + DispatchMessageW (&msg); //ShowCursor is thread-local. if (cursor != mouseshowtoggle) @@ -1347,13 +1363,15 @@ qboolean VID_AttachGL (rendererstate_t *info) if (!*info->subrenderer || !stricmp(info->subrenderer, "opengl32.dll") || !stricmp(info->subrenderer, "opengl32")) //go for windows system dir if we failed with the default. Should help to avoid the 3dfx problem. { + wchar_t systemglw[MAX_OSPATH+1]; char systemgl[MAX_OSPATH+1]; - GetSystemDirectory(systemgl, sizeof(systemgl)-1); - strncat(systemgl, "\\", sizeof(systemgl)-1); + GetSystemDirectoryW(systemglw, countof(systemglw)-1); + narrowen(systemgl, sizeof(systemgl), systemglw); + Q_strncatz(systemgl, "\\", sizeof(systemgl)); if (*info->subrenderer) - strncat(systemgl, info->subrenderer, sizeof(systemgl)-1); + Q_strncatz(systemgl, info->subrenderer, sizeof(systemgl)); else - strncat(systemgl, "opengl32.dll", sizeof(systemgl)-1); + Q_strncatz(systemgl, "opengl32.dll", sizeof(systemgl)); TRACE(("dbg: VID_AttachGL: GLInitialise (system dir specific)\n")); if (GLInitialise(systemgl)) { @@ -1616,7 +1634,7 @@ static void QDECL VID_WndAlpha_Override_Callback(struct cvar_s *var, char *oldva if (modestate==MS_WINDOWED) { int av; - HMODULE hm = GetModuleHandle("user32.dll"); + HMODULE hm = GetModuleHandleA("user32.dll"); lpfnSetLayeredWindowAttributes pSetLayeredWindowAttributes; pSetLayeredWindowAttributes = (void*)GetProcAddress(hm, "SetLayeredWindowAttributes"); @@ -2106,7 +2124,7 @@ static BOOL (WINAPI *pCloseTouchInputHandle)(HTOUCHINPUT hTouchInput); static void Win_Touch_Init(HWND wnd) { HMODULE lib; - lib = LoadLibrary("user32.dll"); + lib = LoadLibraryA("user32.dll"); pRegisterTouchWindow = (void*)GetProcAddress(lib, "RegisterTouchWindow"); pGetTouchInputInfo = (void*)GetProcAddress(lib, "GetTouchInputInfo"); pCloseTouchInputHandle = (void*)GetProcAddress(lib, "CloseTouchInputHandle"); @@ -2387,7 +2405,7 @@ LONG WINAPI GLMainWndProc ( case WM_CLOSE: if (!vid_initializing) - if (MessageBox (hWnd, "Are you sure you want to quit?", "Confirm Exit", + if (MessageBoxW (hWnd, L"Are you sure you want to quit?", L"Confirm Exit", MB_YESNO | MB_SETFOREGROUND | MB_ICONQUESTION) == IDYES) { Cbuf_AddText("\nquit\n", RESTRICT_LOCAL); @@ -2433,7 +2451,7 @@ LONG WINAPI GLMainWndProc ( lRet = TRUE; break; default: - lRet = DefWindowProc (hWnd, uMsg, wParam, lParam); + lRet = DefWindowProcW (hWnd, uMsg, wParam, lParam); break; } break; @@ -2446,7 +2464,7 @@ LONG WINAPI GLMainWndProc ( default: /* pass all unhandled messages to DefWindowProc */ - lRet = DefWindowProc (hWnd, uMsg, wParam, lParam); + lRet = DefWindowProcW (hWnd, uMsg, wParam, lParam); break; } @@ -2503,7 +2521,7 @@ void GLVID_DeInit (void) Cvar_Unhook(&vid_wndalpha); Cmd_RemoveCommand("vid_recenter"); - UnregisterClass(WINDOW_CLASS_NAME, global_hInstance); + UnregisterClassW(WINDOW_CLASS_NAME, global_hInstance); } /* @@ -2516,7 +2534,6 @@ qboolean GLVID_Init (rendererstate_t *info, unsigned char *palette) extern int isPlugin; // qbyte *ptmp; DEVMODE devmode; - WNDCLASS wc; memset(&devmode, 0, sizeof(devmode)); @@ -2527,21 +2544,6 @@ qboolean GLVID_Init (rendererstate_t *info, unsigned char *palette) rf->VID_DestroyCursor = WIN_DestroyCursor; rf->VID_SetCursor = WIN_SetCursor; - /* Register the frame class */ - wc.style = CS_OWNDC; - wc.lpfnWndProc = (WNDPROC)GLMainWndProc; - wc.cbClsExtra = 0; - wc.cbWndExtra = 0; - wc.hInstance = global_hInstance; - wc.hIcon = hIcon; - wc.hCursor = hArrowCursor; - wc.hbrBackground = NULL; - wc.lpszMenuName = 0; - wc.lpszClassName = WINDOW_CLASS_NAME; - - if (!RegisterClass (&wc)) //this isn't really fatal, we'll let the CreateWindow fail instead. - MessageBox(NULL, "RegisterClass failed", "GAH", 0); - vid_initialized = false; vid_initializing = true; diff --git a/engine/http/httpclient.c b/engine/http/httpclient.c index dc7184aab..970bd2786 100644 --- a/engine/http/httpclient.c +++ b/engine/http/httpclient.c @@ -542,7 +542,15 @@ static qboolean HTTP_DL_Work(struct dl_download *dl) } if (dl->notifystarted) - dl->notifystarted(dl, *mimetype?mimetype:NULL); + { + if (!dl->notifystarted(dl, *mimetype?mimetype:NULL)) + { + dl->notifycomplete = NULL; + dl->status = DL_FAILED; + return false; + } + } + if (!dl->file) { @@ -853,7 +861,7 @@ void HTTPDL_Establish(struct dl_download *dl) Q_snprintfz(con->buffer, con->bufferlen, "GET %s HTTP/1.1\r\n" "Host: %s\r\n" - "Connection: close\r\n" + "Connection: close\r\n" //theoretically, this is not needed. but as our code will basically do it anyway, it might as well be here FIXME: implement connection reuse. #if !defined(NPFTE) && defined(AVAIL_ZLIB) "Accept-Encoding: gzip\r\n" #endif diff --git a/engine/http/iweb.h b/engine/http/iweb.h index 183b153b6..7462b8e71 100644 --- a/engine/http/iweb.h +++ b/engine/http/iweb.h @@ -142,7 +142,7 @@ struct dl_download /*not used internally by the backend, but used by HTTP_CL_Get/thread wrapper*/ struct dl_download *next; - void (*notifystarted) (struct dl_download *dl, char *mimetype); //mime can be null for some protocols, read dl->totalsize for size. + qboolean (*notifystarted) (struct dl_download *dl, char *mimetype); //mime can be null for some protocols, read dl->totalsize for size. false if the mime just isn't acceptable. void (*notifycomplete) (struct dl_download *dl); }; diff --git a/engine/qclib/pr_edict.c b/engine/qclib/pr_edict.c index 3d25a7141..ab71e16d5 100644 --- a/engine/qclib/pr_edict.c +++ b/engine/qclib/pr_edict.c @@ -3385,7 +3385,7 @@ retry: d16 = ED_FindGlobal16(progfuncs, s); if (!d16) { - printf("Progs requires \"%s\" the external function \"%s\", but the definition was stripped\n", filename, s); + printf("\"%s\" requires the external function \"%s\", but the definition was stripped\n", filename, s); PRHunkFree(progfuncs, hmark); pr_progs=NULL; return false; diff --git a/engine/server/pr_cmds.c b/engine/server/pr_cmds.c index c5b7e2b9d..a03bfca34 100644 --- a/engine/server/pr_cmds.c +++ b/engine/server/pr_cmds.c @@ -9917,7 +9917,8 @@ BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs {"uri_escape", PF_uri_escape, 0, 0, 0, 510, "string(string in)"},//DP_QC_URI_ESCAPE {"uri_unescape", PF_uri_unescape, 0, 0, 0, 511, "string(string in)"},//DP_QC_URI_ESCAPE {"num_for_edict", PF_num_for_edict, 0, 0, 0, 512, "float(entity ent)"},//DP_QC_NUM_FOR_EDICT - {"uri_get", PF_uri_get, 0, 0, 0, 513, D("float(string uril, float id, optional string postmimetype, optional string postdata)", "uri_get() gets content from an URL and calls a callback \"uri_get_callback\" with it set as string; an unique ID of the transfer is returned\nreturns 1 on success, and then calls the callback with the ID, 0 or the HTTP status code, and the received data in a string")},//DP_QC_URI_GET + {"uri_get", PF_uri_get, 0, 0, 0, 513, D("#define uri_post uri_get\nfloat(string uril, float id, optional string postmimetype, optional string postdata)", "uri_get() gets content from an URL and calls a callback \"uri_get_callback\" with it set as string; an unique ID of the transfer is returned\nreturns 1 on success, and then calls the callback with the ID, 0 or the HTTP status code, and the received data in a string")},//DP_QC_URI_GET + {"uri_post", PF_uri_get, 0, 0, 0, 513, D("float(string uril, float id, optional string postmimetype, optional string postdata)", "uri_get() gets content from an URL and calls a callback \"uri_get_callback\" with it set as string; an unique ID of the transfer is returned\nreturns 1 on success, and then calls the callback with the ID, 0 or the HTTP status code, and the received data in a string"), true},//DP_QC_URI_POST {"tokenize_console",PF_tokenize_console,0, 0, 0, 514, D("float(string str)", "Tokenize a string exactly as the console's tokenizer would do so. The regular tokenize builtin became bastardized for convienient string parsing, which resulted in a large disparity that can be exploited to bypass checks implemented in a naive SV_ParseClientCommand function, therefore you can use this builtin to make sure it exactly matches.")}, {"argv_start_index",PF_argv_start_index,0, 0, 0, 515, D("float(float idx)", "Returns the character index that the tokenized arg started at.")}, {"argv_end_index", PF_argv_end_index, 0, 0, 0, 516, D("float(float idx)", "Returns the character index that the tokenized arg stopped at.")}, diff --git a/engine/server/sv_ccmds.c b/engine/server/sv_ccmds.c index defd59d5b..dd4c57114 100644 --- a/engine/server/sv_ccmds.c +++ b/engine/server/sv_ccmds.c @@ -2315,7 +2315,7 @@ static void SV_Gamedir_f (void) } dir = Z_StrDup(dir); - COM_Gamedir (dir); + COM_Gamedir (dir, NULL); Info_SetValueForStarKey (svs.info, "*gamedir", dir, MAX_SERVERINFO_STRING); Z_Free(dir); } diff --git a/engine/server/sv_ents.c b/engine/server/sv_ents.c index 0b872aa89..fdbea791d 100644 --- a/engine/server/sv_ents.c +++ b/engine/server/sv_ents.c @@ -3099,8 +3099,8 @@ void SV_Snapshot_BuildStateQ1(entity_state_t *state, edict_t *ent, client_t *cli } } else if (progstype == PROG_UNKNOWN) - { - if (state->effects & 16) + { //unknown progs crc. things here are basically hacks. + if (state->effects & 16) //tenebrae's EF_FULLDYNAMIC { state->effects &= ~16; state->lightpflags |= PFLAGS_FULLDYNAMIC; diff --git a/engine/server/sv_phys.c b/engine/server/sv_phys.c index 098eda3cd..7d5a75797 100644 --- a/engine/server/sv_phys.c +++ b/engine/server/sv_phys.c @@ -1184,17 +1184,24 @@ static void WPhys_Physics_Noclip (world_t *w, wedict_t *ent) VectorMA (ent->v->angles, host_frametime, ent->v->avelocity, ent->v->angles); VectorMA (ent->v->origin, host_frametime, ent->v->velocity, end); - trace = World_Move (w, ent->v->origin, ent->v->mins, ent->v->maxs, end, MOVE_NOMONSTERS, (wedict_t*)ent); - impact = trace.ent; - if (impact && impact->v->solid == SOLID_PORTAL) +#ifndef CLIENTONLY + //allow spectators to no-clip through portals without bogging down sock's mods. + if (ent->entnum > 0 && ent->entnum <= sv.allocated_client_slots && w == &sv.world) { - vec3_t move; - vec3_t from; - VectorCopy(trace.endpos, from); //just in case - VectorSubtract(end, trace.endpos, move); - WPhys_PortalTransform(w, ent, impact, from, move); - VectorAdd(from, move, end); + trace = World_Move (w, ent->v->origin, ent->v->mins, ent->v->maxs, end, MOVE_NOMONSTERS, (wedict_t*)ent); + impact = trace.ent; + if (impact && impact->v->solid == SOLID_PORTAL) + { + vec3_t move; + vec3_t from; + VectorCopy(trace.endpos, from); //just in case + VectorSubtract(end, trace.endpos, move); + WPhys_PortalTransform(w, ent, impact, from, move); + VectorAdd(from, move, end); + } } +#endif + VectorCopy(end, ent->v->origin); World_LinkEdict (w, (wedict_t*)ent, false); diff --git a/engine/server/sv_user.c b/engine/server/sv_user.c index 569e07ddc..e69edb477 100644 --- a/engine/server/sv_user.c +++ b/engine/server/sv_user.c @@ -7000,27 +7000,6 @@ void SVQ2_ExecuteClientMessage (client_t *cl) SV_DropClient(cl); } - // calc ping time - frame = &cl->frameunion.q2frames[cl->netchan.incoming_acknowledged & Q2UPDATE_MASK]; - if (frame->senttime != -1) - { - int ping_time = realtime*1000 - frame->senttime; //no more phenomanally low pings please - if (ping_time > sv_minping.value+1) - { - cl->delay -= 0.001; - if (cl->delay < 0) - cl->delay = 0; - } - if (ping_time < sv_minping.value) - { - cl->delay += 0.001; - if (cl->delay > 1) - cl->delay = 1; - } - frame->senttime = -1; - frame->ping_time = ping_time; - } - // make sure the reply sequence number matches the incoming // sequence number if (cl->netchan.incoming_sequence >= cl->netchan.outgoing_sequence) @@ -7028,9 +7007,39 @@ void SVQ2_ExecuteClientMessage (client_t *cl) else cl->send_message = false; // don't reply, sequences have slipped + // calc ping time + if (cl->netchan.outgoing_sequence - cl->netchan.incoming_acknowledged > Q2UPDATE_MASK) + { + cl->delay -= 0.001; + if (cl->delay < 0) + cl->delay = 0; + } + else + { + frame = &cl->frameunion.q2frames[cl->netchan.incoming_acknowledged & Q2UPDATE_MASK]; + if (frame->senttime != -1) + { + int ping_time = (int)(realtime*1000) - frame->senttime; //no more phenomanally low pings please + if (ping_time > sv_minping.value+1) + { + cl->delay -= 0.001; + if (cl->delay < 0) + cl->delay = 0; + } + if (ping_time < sv_minping.value) + { + cl->delay += 0.001; + if (cl->delay > 1) + cl->delay = 1; + } + frame->senttime = -1; + frame->ping_time = ping_time; + } + } + // save time for ping calculations - cl->frameunion.q2frames[cl->netchan.outgoing_sequence & Q2UPDATE_MASK].senttime = realtime*1000; - cl->frameunion.q2frames[cl->netchan.outgoing_sequence & Q2UPDATE_MASK].ping_time = -1; +// cl->frameunion.q2frames[cl->netchan.outgoing_sequence & Q2UPDATE_MASK].senttime = realtime*1000; +// cl->frameunion.q2frames[cl->netchan.outgoing_sequence & Q2UPDATE_MASK].ping_time = -1; host_client = cl; sv_player = host_client->edict; @@ -7115,6 +7124,7 @@ void SVQ2_ExecuteClientMessage (client_t *cl) newcmd.upmove = 0; } + host_client->q2edict->client->ping = SV_CalcPing (host_client, false); if (!sv.paused) { if (net_drop < 20) diff --git a/engine/server/svq2_ents.c b/engine/server/svq2_ents.c index c8917f1b3..99cd488b5 100644 --- a/engine/server/svq2_ents.c +++ b/engine/server/svq2_ents.c @@ -631,11 +631,14 @@ void SVQ2_BuildClientFrame (client_t *client) numprojs = 0; // no projectiles yet #endif - // this is the frame we are creating - frame = &client->frameunion.q2frames[sv.framenum & Q2UPDATE_MASK]; + // this is the frame the client will be acking (EVIL HACKS!) + frame = &client->frameunion.q2frames[client->netchan.outgoing_sequence & Q2UPDATE_MASK]; frame->senttime = realtime*1000; // save it for ping calc later + // this is the frame we are creating + frame = &client->frameunion.q2frames[sv.framenum & Q2UPDATE_MASK]; + // find the client's PVS for (i=0 ; i<3 ; i++) org[i] = clent->client->ps.pmove.origin[i]*0.125 + clent->client->ps.viewoffset[i];