diff --git a/engine/Makefile b/engine/Makefile index 320a4607..f454de61 100644 --- a/engine/Makefile +++ b/engine/Makefile @@ -403,7 +403,7 @@ endif SDL_INCLUDES= #-I$(LIBS_DIR)/sdl/include -I/usr/include/SDL -I$(LIBS_DIR)/sdl/include/SDL -BOTLIB_CFLAGS=-I$(BOTLIB_DIR) -DBOTLIB +BOTLIB_CFLAGS=-I$(BOTLIB_DIR) -DBOTLIB -DBOTLIB_STATIC BASE_CFLAGS=$(WARNINGFLAGS) $(GNUC_FUNCS) -I$(CLIENT_DIR) -I$(SERVER_DIR) -I$(COMMON_DIR) -I$(GL_DIR) -I$(D3D_DIR) -I$(PROGS_DIR) -I. -I$(LIBS_DIR) -I$(LIBS_DIR)/dxsdk9/include -I$(LIBS_DIR)/dxsdk7/include $(SDL_INCLUDES) -I./libs/freetype2/include -I./libs/freetype2/include/freetype -I./libs/speex $(BOTLIB_CFLAGS) $(SVNREVISION) CLIENT_ONLY_CFLAGS=-DCLIENTONLY SERVER_ONLY_CFLAGS=-DSERVERONLY @@ -497,7 +497,6 @@ CLIENT_OBJS = \ image.o \ keys.o \ menu.o \ - m_download.o \ m_master.o \ m_multi.o \ m_items.o \ @@ -666,6 +665,7 @@ COMMON_OBJS = \ fs_pak.o \ fs_zip.o \ fs_xz.o \ + m_download.o \ mathlib.o \ huff.o \ md4.o \ @@ -738,9 +738,9 @@ endif SDLCONFIG?=sdl-config FTE_FULLTARGET?=sdl$(FTE_TARGET)$(BITS) -GLCL_OBJS=$(GL_OBJS) $(D3DGL_OBJS) $(GLQUAKE_OBJS) gl_vidsdl.o snd_sdl.o cd_sdl.o sys_sdl.o in_sdl.o -GL_EXE_NAME=../fteqw_gl$(FTE_FULLTARGET) -GLCL_EXE_NAME=../fteqwcl_gl$(FTE_FULLTARGET) +GLCL_OBJS=$(GL_OBJS) $(D3DGL_OBJS) $(GLQUAKE_OBJS) $(BOTLIB_OBJS) gl_vidsdl.o snd_sdl.o cd_sdl.o sys_sdl.o in_sdl.o +GL_EXE_NAME=../fteqw-gl$(FTE_FULLTARGET) +GLCL_EXE_NAME=../fteqwcl-gl$(FTE_FULLTARGET) #SDLCONFIG:=libs/sdl2_mingw/$(CC_MACHINE)/bin/sdl2-config --prefix=libs/sdl2_mingw/$(CC_MACHINE) ifdef windir @@ -757,16 +757,16 @@ GLB_DIR=gl_$(FTE_FULLTARGET) GLCL_DIR=glcl_$(FTE_FULLTARGET) SV_DIR?=sv_$(FTE_FULLTARGET) -SV_OBJS=$(COMMON_OBJS) $(SERVER_OBJS) $(PROGS_OBJS) $(SERVERONLY_OBJS) -SV_EXE_NAME=../fteqw_sv$(FTE_FULLTARGET) +SV_OBJS=$(COMMON_OBJS) $(SERVER_OBJS) $(PROGS_OBJS) $(SERVERONLY_OBJS) $(BOTLIB_OBJS) +SV_EXE_NAME=../fteqw-sv$(FTE_FULLTARGET) SV_CFLAGS=-DFTE_SDL `$(SDLCONFIG) --cflags` $(SERVER_ONLY_CFLAGS) MINGL_DIR=mingl_$(FTE_FULLTARGET) -MINGL_EXE_NAME=../fteqw_mingl$(FTE_FULLTARGET) +MINGL_EXE_NAME=../fteqw-mingl$(FTE_FULLTARGET) MB_DIR=m_$(FTE_FULLTARGET) -M_EXE_NAME=../fteqw_$(FTE_FULLTARGET) -MCL_OBJS=$(D3DGL_OBJS) $(GLQUAKE_OBJS) $(SOFTWARE_OBJS) gl_vidsdl.o snd_sdl.o cd_sdl.o sys_sdl.o in_sdl.o +M_EXE_NAME=../fteqw-$(FTE_FULLTARGET) +MCL_OBJS=$(D3DGL_OBJS) $(GLQUAKE_OBJS) $(SOFTWARE_OBJS) $(BOTLIB_OBJS) gl_vidsdl.o snd_sdl.o cd_sdl.o sys_sdl.o in_sdl.o M_CFLAGS=-DFTE_SDL $(GLCFLAGS) `$(SDLCONFIG) --cflags` QCC_DIR=qcc$(BITS) @@ -827,7 +827,7 @@ ifeq ($(FTE_TARGET),nacl) GL_CFLAGS+=-I$(realpath $(NACL_SDK_ROOT)/include) BASELDFLAGS+=-L$(realpath $(NACL_SDK_ROOT)/lib/$(NACLLIBS)) - GLCL_OBJS=$(GL_OBJS) $(D3DGL_OBJS) $(GLQUAKE_OBJS) $(SPEEX_OBJS) sys_ppapi.o cd_null.o gl_vidppapi.o fs_ppapi.o snd_ppapi.o + GLCL_OBJS=$(GL_OBJS) $(D3DGL_OBJS) $(GLQUAKE_OBJS) $(BOTLIB_OBJS) $(SPEEX_OBJS) sys_ppapi.o cd_null.o gl_vidppapi.o fs_ppapi.o snd_ppapi.o GL_LDFLAGS=$(GLLDFLAGS) $(OGGVORBISLDFLAGS) M_LDFLAGS=$(GLLDFLAGS) $(OGGVORBISLDFLAGS) @@ -836,12 +836,12 @@ ifeq ($(FTE_TARGET),nacl) MINGL_DIR=mingl_nacl_$(NARCH) ifeq ($(NARCH),pnacl) GL_EXE_NAME=../fteqw.pexe - GLCL_EXE_NAME=../fteqwcl.pexe - MINGL_EXE_NAME=../fteqw_mingl.pexe + GLCL_EXE_NAME=../fteqw-cl.pexe + MINGL_EXE_NAME=../fteqw-mingl.pexe else - GL_EXE_NAME=../fteqw_$(NARCH).nexe - GLCL_EXE_NAME=../fteqwcl_$(NARCH).nexe - MINGL_EXE_NAME=../fteqw_mingl_$(NARCH).nexe + GL_EXE_NAME=../fteqw-$(NARCH).nexe + GLCL_EXE_NAME=../fteqw-cl-$(NARCH).nexe + MINGL_EXE_NAME=../fteqw-mingl-$(NARCH).nexe endif endif @@ -862,8 +862,8 @@ ifeq (win_SDL,$(findstring win,$(FTE_TARGET))$(findstring _SDL,$(FTE_TARGET))) #the defaults for sdl come first GLCL_OBJS=$(GL_OBJS) $(D3DGL_OBJS) $(GLQUAKE_OBJS) $(BOTLIB_OBJS) $(SPEEX_OBJS) gl_vidsdl.o snd_sdl.o cd_sdl.o sys_sdl.o in_sdl.o snd_directx.o $(LTO_END) resources.o $(LTO_START) - GL_EXE_NAME=../fteqw_sdl_gl$(BITS)$(EXEPOSTFIX) - GLCL_EXE_NAME=../fteqwcl_sdl$(BITS)$(EXEPOSTFIX) + GL_EXE_NAME=../fteqw-sdl-gl$(BITS)$(EXEPOSTFIX) + GLCL_EXE_NAME=../fteqw-sdl-glcl$(BITS)$(EXEPOSTFIX) ifdef windir GL_LDFLAGS=$(GLLDFLAGS) -lmingw32 -lws2_32 `$(SDLCONFIG) --static-libs` M_LDFLAGS=$(MLDFLAGS) -lmingw32 -lws2_32 `$(SDLCONFIG) --static-libs` @@ -883,14 +883,14 @@ ifeq (win_SDL,$(findstring win,$(FTE_TARGET))$(findstring _SDL,$(FTE_TARGET))) GLCL_DIR=glcl_mgw_sdl$(BITS) SV_OBJS=$(COMMON_OBJS) $(SERVER_OBJS) $(PROGS_OBJS) $(WINDOWSSERVERONLY_OBJS) $(BOTLIB_OBJS) $(LTO_END) resources.o $(LTO_START) - SV_EXE_NAME=../fteqw_sdl_sv$(BITS)$(EXEPOSTFIX) + SV_EXE_NAME=../fteqw-sdl-sv$(BITS)$(EXEPOSTFIX) SV_CFLAGS=$(SERVER_ONLY_CFLAGS) -DFTE_SDL MINGL_DIR=mingl_sdlwin$(BITS) - MINGL_EXE_NAME=../fteqw_sdl_mingl$(BITS)$(EXEPOSTFIX) + MINGL_EXE_NAME=../fteqw-sdl-mingl$(BITS)$(EXEPOSTFIX) MB_DIR=m_mgw_sdl$(BITS) - M_EXE_NAME=../fteqw_sdl$(BITS)$(EXEPOSTFIX) + M_EXE_NAME=../fteqw-sdl$(BITS)$(EXEPOSTFIX) MCL_OBJS=$(D3DGL_OBJS) $(GLQUAKE_OBJS) $(SOFTWARE_OBJS) $(D3DQUAKE_OBJS) $(BOTLIB_OBJS) $(SPEEX_OBJS) gl_vidsdl.o snd_sdl.o cd_sdl.o sys_sdl.o in_sdl.o snd_directx.o $(LTO_END) resources.o $(LTO_START) M_CFLAGS=$(D3DCFLAGS) -DFTE_SDL -I$(LIBS_DIR) -I$(MINGW_LIBS_DIR)/ -I$(MINGW_LIBS_DIR) $(GLCFLAGS) -DLIBVORBISFILE_STATIC -D_MERGED_SDL $(DX7SDK) $(SPEEXCFLAGS) @@ -901,9 +901,9 @@ ifeq (win_SDL,$(findstring win,$(FTE_TARGET))$(findstring _SDL,$(FTE_TARGET))) M_LDFLAGS=$(GLLDFLAGS) $(IMAGELDFLAGS) $(OGGVORBISLDFLAGS) - D3DCL_OBJS=$(D3DQUAKE_OBJS) $(SPEEX_OBJS) snd_sdl.o cd_sdl.o sys_sdl.o in_sdl.o snd_directx.o $(D3DGL_OBJS) $(LTO_END) resources.o $(LTO_START) - D3D_EXE_NAME=../fted3d_sdl_qw$(BITS)$(EXEPOSTFIX) - D3DCL_EXE_NAME=../fted3d_sdl_clqw$(BITS)$(EXEPOSTFIX) + D3DCL_OBJS=$(D3DQUAKE_OBJS) $(BOTLIB_OBJS) $(SPEEX_OBJS) snd_sdl.o cd_sdl.o sys_sdl.o in_sdl.o snd_directx.o $(D3DGL_OBJS) $(LTO_END) resources.o $(LTO_START) + D3D_EXE_NAME=../fteqw-sdl-d3d$(BITS)$(EXEPOSTFIX) + D3DCL_EXE_NAME=../fteqw-sdl-d3dcl$(BITS)$(EXEPOSTFIX) D3D_LDFLAGS=$(IMAGELDFLAGS) $(OGGVORBISLDFLAGS) -lws2_32 -lmingw32 $(SDL_LDFLAGS) -mwindows -ldxguid -lwinmm -lole32 D3D_CFLAGS=$(D3DCFLAGS) -DFTE_SDL -DNO_XFLIP -I$(LIBS_DIR) -I$(MINGW_LIBS_DIR)/ -I$(MINGW_LIBS_DIR) -DLIBVORBISFILE_STATIC $(DX7SDK) $(SPEEXCFLAGS) ifeq ($(shell echo $(FTE_TARGET)|grep -E -i -v "win32.*sdl"),) @@ -913,9 +913,9 @@ ifeq (win_SDL,$(findstring win,$(FTE_TARGET))$(findstring _SDL,$(FTE_TARGET))) D3DCL_DIR=sdl_d3dcl_mgw$(BITS) - VKCL_OBJS=$(D3DQUAKE_OBJS) $(SPEEX_OBJS) snd_sdl.o cd_sdl.o sys_sdl.o in_sdl.o snd_directx.o $(D3DGL_OBJS) $(LTO_END) resources.o $(LTO_START) - VK_EXE_NAME=../ftevk_sdl_qw$(BITS)$(EXEPOSTFIX) - VKCL_EXE_NAME=../ftevk_sdl_clqw$(BITS)$(EXEPOSTFIX) + VKCL_OBJS=$(D3DQUAKE_OBJS) $(BOTLIB_OBJS) $(SPEEX_OBJS) snd_sdl.o cd_sdl.o sys_sdl.o in_sdl.o snd_directx.o $(D3DGL_OBJS) $(LTO_END) resources.o $(LTO_START) + VK_EXE_NAME=../fteqw-sdl-vk$(BITS)$(EXEPOSTFIX) + VKCL_EXE_NAME=../fteqw-sdl-vkcl$(BITS)$(EXEPOSTFIX) VK_LDFLAGS=$(IMAGELDFLAGS) $(OGGVORBISLDFLAGS) -lws2_32 -lmingw32 $(SDL_LDFLAGS) -mwindows -ldxguid -lwinmm -lole32 VK_CFLAGS=$(VKCFLAGS) -DFTE_SDL -DNO_XFLIP -I$(LIBS_DIR) -I$(MINGW_LIBS_DIR)/ -I$(MINGW_LIBS_DIR) -DLIBVORBISFILE_STATIC $(DX7SDK) $(SPEEXCFLAGS) ifeq ($(shell echo $(FTE_TARGET)|grep -E -i -v "win32.*sdl"),) @@ -994,13 +994,13 @@ ifeq ($(FTE_TARGET),vc) BASE_CFLAGS:=$(WARNINGFLAGS) $(GNUC_FUNCS) -I$(shell cygpath -m $(CLIENT_DIR)) -I$(shell cygpath -m $(SERVER_DIR)) -I$(shell cygpath -m $(COMMON_DIR)) -I$(shell cygpath -m $(GL_DIR)) -I$(shell cygpath -m $(D3D_DIR)) -I$(shell cygpath -m $(PROGS_DIR)) -I. -I$(LIBS_DIR) -I$(LIBS_DIR)/dxsdk9/include -I$(LIBS_DIR)/dxsdk7/include $(SDL_INCLUDES) -I./libs/freetype2/include -I./libs/freetype2/include/freetype -I./libs/speex $(BOTLIB_CFLAGS) $(SVNREVISION) SV_CFLAGS=$(SERVER_ONLY_CFLAGS) $(W32_CFLAGS) -DMULTITHREAD -DMSVCLIBPATH=libs/ - SV_EXE_NAME=../fteqwsv$(BITS)$(EXEPOSTFIX) + SV_EXE_NAME=../fteqw-sv$(BITS)$(EXEPOSTFIX) SV_DIR=sv_vc$(BITS) SV_OBJS=$(COMMON_OBJS) $(SERVER_OBJS) $(PROGS_OBJS) $(WINDOWSSERVERONLY_OBJS) fs_win32.o resources.o SV_LDFLAGS=/subsystem:console - GL_EXE_NAME=../fteglqw$(BITS)$(EXEPOSTFIX) - GLCL_EXE_NAME=../minfteqw.gl$(BITS) + GL_EXE_NAME=../fteqw-gl$(BITS)$(EXEPOSTFIX) + GLCL_EXE_NAME=../fteqw-mingl$(BITS) GLB_DIR=gl_vc$(BITS) GLCL_DIR=glcl_vc$(BITS) GL_LDFLAGS=$(GLLDFLAGS) $(JPEGLIB) libs/libpng$(BITS).lib uuid.lib gdi32.lib ole32.lib /subsystem:windows @@ -1009,11 +1009,11 @@ ifeq ($(FTE_TARGET),vc) GL_OBJS= MINGL_DIR=mingl_vc$(BITS) - MINGL_EXE_NAME=../fteminglqw$(BITS)$(EXEPOSTFIX) + MINGL_EXE_NAME=../fteqw-mingl$(BITS)$(EXEPOSTFIX) D3DCL_OBJS=$(D3DQUAKE_OBJS) $(D3DGL_OBJS) $(SPEEX_OBJS) $(WINDOWS_OBJS) - D3D_EXE_NAME=../fted3dqw$(BITS)$(EXEPOSTFIX) - D3DCL_EXE_NAME=../fted3dclqw$(BITS)$(EXEPOSTFIX) + D3D_EXE_NAME=../fteqw-d3d$(BITS)$(EXEPOSTFIX) + D3DCL_EXE_NAME=../fteqw-d3dcl$(BITS)$(EXEPOSTFIX) D3D_LDFLAGS=$(JPEGLIB) libs/libpng$(BITS).lib uuid.lib gdi32.lib ole32.lib /subsystem:windows D3D_CFLAGS=$(D3DCFLAGS) $(W32_CFLAGS) $(DX7SDK) -DMULTITHREAD $(SPEEXCFLAGS) -DMSVCLIBPATH=libs/ D3DB_DIR=d3d_vc$(BITS) @@ -1081,7 +1081,7 @@ ifeq (win,$(findstring win,$(FTE_TARGET))$(findstring _SDL,$(FTE_TARGET))) MB_DIR=m_mgw$(BITS) MCL_DIR=mcl_mgw$(BITS) - D3DCL_OBJS=$(D3DQUAKE_OBJS) $(D3DGL_OBJS) $(SPEEX_OBJS) $(WINDOWS_OBJS) + D3DCL_OBJS=$(D3DQUAKE_OBJS) $(D3DGL_OBJS) $(BOTLIB_OBJS) $(SPEEX_OBJS) $(WINDOWS_OBJS) D3D_EXE_NAME=../fted3dqw$(BITS)$(EXEPOSTFIX) D3DCL_EXE_NAME=../fted3dclqw$(BITS)$(EXEPOSTFIX) D3D_LDFLAGS=$(IMAGELDFLAGS) $(OGGVORBISLDFLAGS) -ldxguid -lws2_32 -lwinmm -lgdi32 -lole32 -Wl,--subsystem,windows @@ -1089,7 +1089,7 @@ ifeq (win,$(findstring win,$(FTE_TARGET))$(findstring _SDL,$(FTE_TARGET))) D3DB_DIR=d3d_mgw$(BITS) D3DCL_DIR=d3dcl_mgw$(BITS) - VKCL_OBJS=$(GLQUAKE_OBJS) $(D3DGL_OBJS) $(SPEEX_OBJS) $(WINDOWS_OBJS) vk_win32.o + VKCL_OBJS=$(GLQUAKE_OBJS) $(D3DGL_OBJS) $(BOTLIB_OBJS) $(SPEEX_OBJS) $(WINDOWS_OBJS) vk_win32.o VK_EXE_NAME=../ftevkqw$(BITS)$(EXEPOSTFIX) VKCL_EXE_NAME=../ftevkclqw$(BITS)$(EXEPOSTFIX) VK_LDFLAGS=$(IMAGELDFLAGS) $(OGGVORBISLDFLAGS) -ldxguid -lws2_32 -lwinmm -lgdi32 -lole32 -Wl,--subsystem,windows @@ -1101,12 +1101,12 @@ ifeq (win,$(findstring win,$(FTE_TARGET))$(findstring _SDL,$(FTE_TARGET))) MINGL_DIR=mingl_mgw$(BITS) ifeq ($(NOCOMPAT),1) - SV_EXE_NAME=../engine_sv$(BITS)$(EXEPOSTFIX) - GL_EXE_NAME=../engine_gl$(BITS)$(EXEPOSTFIX) - VK_EXE_NAME=../engine_vk$(BITS)$(EXEPOSTFIX) + SV_EXE_NAME=../engine-sv$(BITS)$(EXEPOSTFIX) + GL_EXE_NAME=../engine-gl$(BITS)$(EXEPOSTFIX) + VK_EXE_NAME=../engine-vk$(BITS)$(EXEPOSTFIX) M_EXE_NAME=../engine$(BITS)$(EXEPOSTFIX) - D3D_EXE_NAME=../engine_d3d$(BITS)$(EXEPOSTFIX) - MINGL_EXE_NAME=../engine_cl_gl$(BITS)$(EXEPOSTFIX) + D3D_EXE_NAME=../engine-d3d$(BITS)$(EXEPOSTFIX) + MINGL_EXE_NAME=../engine-mingl$(BITS)$(EXEPOSTFIX) endif endif @@ -1119,8 +1119,8 @@ ifeq ($(FTE_TARGET),bsd) SV_CFLAGS=$(SERVER_ONLY_CFLAGS) GLCL_OBJS=$(GL_OBJS) $(D3DGL_OBJS) $(GLQUAKE_OBJS) $(BOTLIB_OBJS) gl_vidlinuxglx.o snd_linux.o cd_null.o sys_linux.o sys_linux_threads.o - GL_EXE_NAME=../fteqw.gl - GLCL_EXE_NAME=../fteqwcl.gl + GL_EXE_NAME=../fteqw-gl + GLCL_EXE_NAME=../fteqw-glcl GL_LDFLAGS= -L/usr/local/lib $(GLLDFLAGS) $(XLDFLAGS) -lpthread GL_CFLAGS=$(GLCFLAGS) -I/usr/local/include -I/usr/X11R6/include GLB_DIR=gl_bsd @@ -1128,18 +1128,18 @@ ifeq ($(FTE_TARGET),bsd) MCL_OBJS=$(D3DGL_OBJS) $(GLQUAKE_OBJS) $(SOFTWARE_OBJS) $(BOTLIB_OBJS) gl_vidlinuxglx.o snd_linux.o cd_null.o sys_linux.o sys_linux_threads.o M_EXE_NAME=../fteqw - MCL_EXE_NAME=../fteqwcl + MCL_EXE_NAME=../fteqw-cl M_LDFLAGS=$(GLLDFLAGS) $(XLDFLAGS) -lpthread M_CFLAGS=$(VKCFLAGS) $(GLCFLAGS) -I/usr/X11R6/include MB_DIR=m_bsd MCL_DIR=mcl_bsd - MINGL_EXE_NAME=../fteqw.mingl + MINGL_EXE_NAME=../fteqw-mingl MINGL_DIR=mingl_bsd endif ifneq (,$(findstring linux,$(FTE_TARGET))) SV_DIR=sv_linux$(BITS) - SV_EXE_NAME=../fteqw.sv$(BITS) + SV_EXE_NAME=../fteqw-sv$(BITS) SV_LDFLAGS= SV_CFLAGS=$(SERVER_ONLY_CFLAGS) -DMULTITHREAD @@ -1152,16 +1152,16 @@ ifneq (,$(findstring linux,$(FTE_TARGET))) NPFTEB_DIR=npfte_linux$(BITS) GLCL_OBJS=$(GL_OBJS) $(D3DGL_OBJS) $(GLQUAKE_OBJS) $(BOTLIB_OBJS) $(SPEEX_OBJS) vid_headless.o 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_EXE_NAME=../fteqw-gl$(BITS) + GLCL_EXE_NAME=../fteqw-glcl$(BITS) GL_LDFLAGS=$(GLLDFLAGS) $(XLDFLAGS) $(OGGVORBISLDFLAGS) 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) VKCL_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 - VK_EXE_NAME=../fteqw_vk$(BITS) - VKCL_EXE_NAME=../fteqwcl_vk$(BITS) + VK_EXE_NAME=../fteqw-vk$(BITS) + VKCL_EXE_NAME=../fteqw-vkcl$(BITS) VK_LDFLAGS=$(GLLDFLAGS) $(XLDFLAGS) $(OGGVORBISLDFLAGS) VK_CFLAGS=$(VKCFLAGS) -I/usr/X11R6/include $(SPEEXCFLAGS) -DMULTITHREAD -DLIBVORBISFILE_STATIC -DDYNAMIC_LIBPNG -DDYNAMIC_LIBJPEG -DDYNAMIC_SDL VKB_DIR=vk_linux$(BITS) @@ -1169,7 +1169,7 @@ ifneq (,$(findstring linux,$(FTE_TARGET))) 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) + MCL_EXE_NAME=../fteqw-cl$(BITS) M_LDFLAGS=$(GL_LDFLAGS) M_CFLAGS=$(VKCFLAGS) $(GL_CFLAGS) MB_DIR=m_linux$(BITS) @@ -1185,7 +1185,7 @@ ifneq (,$(findstring linux,$(FTE_TARGET))) endif - MINGL_EXE_NAME=../fteqw.mingl$(BITS) + MINGL_EXE_NAME=../fteqw-mingl$(BITS) MINGL_DIR=mingl_linux$(BITS) endif @@ -1221,17 +1221,17 @@ ifneq ($(shell echo $(FTE_TARGET)|grep macosx),) endif GL_LDFLAGS=-framework AGL -framework OpenGL -framework Cocoa -framework AudioUnit -lz -lpng -ljpeg - GLCL_OBJS=$(GL_OBJS) $(D3DGL_OBJS) $(GLQUAKE_OBJS) gl_vidcocoa.mo gl_vidmacos.o sys_linux.o cd_null.o snd_macos.o sys_linux_threads.o + GLCL_OBJS=$(GL_OBJS) $(D3DGL_OBJS) $(GLQUAKE_OBJS) $(BOTLIB_OBJS) gl_vidcocoa.mo gl_vidmacos.o sys_linux.o cd_null.o snd_macos.o sys_linux_threads.o - GL_EXE_NAME=../macosx_fteqw.gl$(EXTENSION)$(BITS) - GLCL_EXE_NAME=../macosx_fteqwcl.gl$(EXTENSION)$(BITS) - M_EXE_NAME=../macosx_fteqw$(EXTENSION)$(BITS) - MCL_EXE_NAME=../macosx_fteqwcl$(EXTENSION)$(BITS) - MINGL_EXE_NAME=../macosx_fteqw.mingl$(EXTENSION)$(BITS) + GL_EXE_NAME=../fteqw-macosx-gl$(EXTENSION)$(BITS) + GLCL_EXE_NAME=../fteqwcl-macosx-gl$(EXTENSION)$(BITS) + M_EXE_NAME=../fteqw-macosx$(EXTENSION)$(BITS) + MCL_EXE_NAME=../fteqw-macosx-cl$(EXTENSION)$(BITS) + MINGL_EXE_NAME=../fteqw-macosx-mingl$(EXTENSION)$(BITS) MINGL_DIR=mingl_macosx$(EXTENSION)$(BITS) - SV_OBJS=$(COMMON_OBJS) $(SERVER_OBJS) $(PROGS_OBJS) $(SERVERONLY_OBJS) - SV_EXE_NAME=../macosx_fteqw.sv$(EXTENSION)$(BITS) + SV_OBJS=$(COMMON_OBJS) $(SERVER_OBJS) $(PROGS_OBJS) $(BOTLIB_OBJS) $(SERVERONLY_OBJS) + SV_EXE_NAME=../fteqw-macosx-sv$(EXTENSION)$(BITS) SV_CFLAGS=$(SERVER_ONLY_CFLAGS) SV_LDFLAGS=-lz @@ -1249,26 +1249,26 @@ ifeq ($(FTE_TARGET),morphos) OGGVORBISLDFLAGS= GLCL_OBJS=$(GL_OBJS) $(D3DGL_OBJS) $(GLQUAKE_OBJS) $(BOTLIB_OBJS) gl_vidmorphos.o in_morphos.o snd_morphos.o cd_null.o sys_morphos.o - GL_EXE_NAME=../morphos_fteqw.gl - GLCL_EXE_NAME=../morphos_fteqwcl.gl + GL_EXE_NAME=../fteqw-morphos-gl + GLCL_EXE_NAME=../fteqw-morphos-glcl GL_LDFLAGS=$(GLLDFLAGS) -ldl $(IMAGELDFLAGS) -lz GL_CFLAGS=$(GLCFLAGS) -noixemul -I./libs/speex -I./ GLB_DIR=gl_morphos GLCL_DIR=glcl_morphos MCL_OBJS=$(D3DGL_OBJS) $(GLQUAKE_OBJS) $(SOFTWARE_OBJS) $(BOTLIB_OBJS) gl_vidmorphos.o vid_morphos.o in_morphos.o snd_morphos.o cd_null.o sys_morphos.o - M_EXE_NAME=../morphos_fteqw - MCL_EXE_NAME=../morphos_fteqwcl + M_EXE_NAME=../fteqw-morphos + MCL_EXE_NAME=../fteqw-morphos-cl M_LDFLAGS=$(GLLDFLAGS) M_CFLAGS=$(GLCFLAGS) MB_DIR=m_morphos MCL_DIR=mcl_morphos - MINGL_EXE_NAME=../morphos_fteqw.mingl + MINGL_EXE_NAME=../fteqw-morphos-mingl MINGL_DIR=mingl_morphos SV_OBJS=$(COMMON_OBJS) $(SERVER_OBJS) $(PROGS_OBJS) $(SERVERONLY_OBJS) $(BOTLIB_OBJS) - SV_EXE_NAME=../morphos_fteqw.sv$(BITS) + SV_EXE_NAME=../fteqw-morphos-sv$(BITS) SV_CFLAGS=$(SERVER_ONLY_CFLAGS) endif @@ -1280,16 +1280,16 @@ ifeq ($(FTE_TARGET),cyg) EXEPOSTFIX=.exe GLCL_OBJS=$(GL_OBJS) $(D3DGL_OBJS) $(GLQUAKE_OBJS) $(BOTLIB_OBJS) $(SPEEX_OBJS) gl_vidlinuxglx.o snd_linux.o cd_null.o sys_linux.o sys_linux_threads.o - GL_EXE_NAME=../fteqwglcyg$(EXEPOSTFIX) - GLCL_EXE_NAME=../fteqwclglcyg$(EXEPOSTFIX) + GL_EXE_NAME=../fteqw-cyg-gl$(EXEPOSTFIX) + GLCL_EXE_NAME=../fteqw-cyg-glcl$(EXEPOSTFIX) GL_LDFLAGS=$(GLLDFLAGS) $(XLDFLAGS) $(OGGVORBISLDFLAGS) -lz -lltdl GL_CFLAGS=$(GLCFLAGS) -I/usr/X11R6/include $(SPEEXCFLAGS) -DLIBVORBISFILE_STATIC -DUSE_LIBTOOL GLB_DIR=gl_cygwin GLCL_DIR=glcl_cygwin MCL_OBJS=$(D3DGL_OBJS) $(GLQUAKE_OBJS) $(SOFTWARE_OBJS) $(BOTLIB_OBJS) $(SPEEX_OBJS) gl_vidlinuxglx.o snd_linux.o cd_null.o sys_linux.o sys_linux_threads.o - M_EXE_NAME=../fteqwcyg$(EXEPOSTFIX) - MCL_EXE_NAME=../fteqwclcyg$(EXEPOSTFIX) + M_EXE_NAME=../fteqw-cyg$(EXEPOSTFIX) + MCL_EXE_NAME=../fteqw-cyg-cl$(EXEPOSTFIX) M_LDFLAGS=$(GLLDFLAGS) $(XLDFLAGS) $(OGGVORBISLDFLAGS) -lz -lltdl M_CFLAGS=$(GLCFLAGS) $(SPEEXCFLAGS) -DLIBVORBISFILE_STATIC -DUSE_LIBTOOL MB_DIR=m_cygwin @@ -1297,7 +1297,7 @@ ifeq ($(FTE_TARGET),cyg) LIBS_DIR = $(BASE_DIR)/libs - MINGL_EXE_NAME=../fteqwminglcyg$(EXEPOSTFIX) + MINGL_EXE_NAME=../fteqw-cyg-mingl$(EXEPOSTFIX) MINGL_DIR=mingl_cygwin endif diff --git a/engine/client/cl_main.c b/engine/client/cl_main.c index 9fd967a4..a6487503 100644 --- a/engine/client/cl_main.c +++ b/engine/client/cl_main.c @@ -57,7 +57,7 @@ cvar_t cl_pure = CVARD("cl_pure", "0", "0=standard quake rules.\n1=clients shou cvar_t cl_sbar = CVARFC("cl_sbar", "0", CVAR_ARCHIVE, CL_Sbar_Callback); cvar_t cl_hudswap = CVARF("cl_hudswap", "0", CVAR_ARCHIVE); cvar_t cl_maxfps = CVARF("cl_maxfps", "500", CVAR_ARCHIVE); -cvar_t cl_idlefps = CVARFD("cl_idlefps", "0", CVAR_ARCHIVE, "This is the maximum framerate to attain while idle/paused."); +cvar_t cl_idlefps = CVARFD("cl_idlefps", "0", CVAR_ARCHIVE, "This is the maximum framerate to attain while idle/paused/unfocused."); cvar_t cl_yieldcpu = CVARFD("cl_yieldcpu", "0", CVAR_ARCHIVE, "Attempt to yield between frames. This can resolve issues with certain drivers and background software, but can mean less consistant frame times. Will reduce power consumption/heat generation so should be set on laptops or similar (over-hot/battery powered) devices."); cvar_t cl_nopext = CVARF("cl_nopext", "0", CVAR_ARCHIVE); cvar_t cl_pext_mask = CVAR("cl_pext_mask", "0xffffffff"); @@ -2070,6 +2070,13 @@ void CL_CheckServerInfo(void) cl.maxpitch = *s ? Q_atof(s) : 80.0f; s = (cls.z_ext & Z_EXT_PITCHLIMITS) ? Info_ValueForKey (cl.serverinfo, "minpitch") : ""; cl.minpitch = *s ? Q_atof(s) : -70.0f; + + if (cls.protocol == CP_NETQUAKE) + { //proquake likes spamming us with fixangles + float div = cls.proquake_angles_hack?65536:256; + cl.maxpitch -= 1.0/2048; + cl.minpitch -= 0.5/div; + } } else { @@ -4257,7 +4264,7 @@ void Host_WriteConfiguration (void) { if (strchr(cfg_save_name.string, '.')) { - Con_TPrintf ("Couldn't write config.cfg.\n"); + Con_TPrintf (CON_ERROR "Couldn't write config.cfg.\n"); return; } @@ -4266,7 +4273,7 @@ void Host_WriteConfiguration (void) f = FS_OpenVFS(savename, "wb", FS_GAMEONLY); if (!f) { - Con_TPrintf ("Couldn't write config.cfg.\n"); + Con_TPrintf (CON_ERROR "Couldn't write config.cfg.\n"); return; } @@ -5507,6 +5514,9 @@ void CL_ExecInitialConfigs(char *resetcommand) Cbuf_AddText("cl_warncmd 0\n", RESTRICT_LOCAL); Cbuf_AddText("cvar_purgedefaults\n", RESTRICT_LOCAL); //reset cvar defaults to their engine-specified values. the tail end of 'exec default.cfg' will update non-cheat defaults to mod-specified values. Cbuf_AddText("cvarreset *\n", RESTRICT_LOCAL); //reset all cvars to their current (engine) defaults +#ifndef CLIENTONLY + Cbuf_AddText(va("sv_gamedir \"%s\"\n", FS_GetGamedir(true)), RESTRICT_LOCAL); +#endif Cbuf_AddText(resetcommand, RESTRICT_LOCAL); Cbuf_AddText("\n", RESTRICT_LOCAL); COM_ParsePlusSets(true); @@ -5630,6 +5640,8 @@ void Host_FinishLoading(void) #endif r_blockvidrestart = 2; + + Menu_Download_Update(); } #ifdef ANDROID @@ -5734,6 +5746,7 @@ void Host_Init (quakeparms_t *parms) R_SetRenderer(NULL);//set the renderer stuff to unset... + Cvar_ParseWatches(); host_initialized = true; forcesaveprompt = false; @@ -5816,6 +5829,7 @@ void Host_Shutdown(void) Validation_FlushFileList(); Cmd_Shutdown(); + PM_Shutdown(); Key_Unbindall_f(); #ifdef PLUGINS diff --git a/engine/client/cl_parse.c b/engine/client/cl_parse.c index b72a95c0..5a6055fa 100644 --- a/engine/client/cl_parse.c +++ b/engine/client/cl_parse.c @@ -1752,10 +1752,6 @@ int CL_DownloadRate(void) return 0; } -#ifdef _MSC_VER -#define strtoull _strtoui64 -#endif - //called when the server acks the download. opens the local file and stuff. returns false on failure qboolean DL_Begun(qdownload_t *dl) { diff --git a/engine/client/cl_plugin.inc b/engine/client/cl_plugin.inc index 1b61a335..aa1dd910 100644 --- a/engine/client/cl_plugin.inc +++ b/engine/client/cl_plugin.inc @@ -460,7 +460,7 @@ static qintptr_t VARGS Plug_LocalSound(void *offset, quintptr_t mask, const qint static qintptr_t VARGS Plug_CL_GetStats(void *offset, quintptr_t mask, const qintptr_t *arg) { - int i; + int i = 0; int pnum = VM_LONG(arg[0]); unsigned int *stats = VM_POINTER(arg[1]); int pluginstats = VM_LONG(arg[2]); @@ -475,10 +475,24 @@ static qintptr_t VARGS Plug_CL_GetStats(void *offset, quintptr_t mask, const qin max = pluginstats; if (max > MAX_CL_STATS) max = MAX_CL_STATS; - for (i = 0; i < max; i++) - { //fill stats with the right player's stats - stats[i] = cl.playerview[pnum].stats[i]; + if (pnum < 0) + { + pnum = -pnum-1; + if (pnum < MAX_CLIENTS) + { + for (i = 0; i < max; i++) + stats[i] = cl.players[pnum].stats[i]; + } } + else if (pnum < cl.splitclients) + { + for (i = 0; i < max; i++) + { //fill stats with the right player's stats + stats[i] = cl.playerview[pnum].stats[i]; + } + } + + max = i; for (; i < pluginstats; i++) //plugin has too many stats (wow) stats[i] = 0; //fill the rest. return max; @@ -837,8 +851,6 @@ static qintptr_t VARGS Plug_GetWeaponStats(void *offset, quintptr_t mask, const struct wstats_s *result = VM_POINTER(arg[1]); size_t maxresults = VM_LONG(arg[2]); - int i; - if (VM_OOB(arg[0], maxresults*sizeof(*result))) return 0; @@ -855,8 +867,8 @@ static qintptr_t VARGS Plug_GetWeaponStats(void *offset, quintptr_t mask, const if (self < 0) return 0; - if (maxresults > countof(cl.players[i].weaponstats)) - maxresults = countof(cl.players[i].weaponstats); + if (maxresults > countof(cl.players[self].weaponstats)) + maxresults = countof(cl.players[self].weaponstats); memcpy(result, cl.players[self].weaponstats, sizeof(*result) * maxresults); return VM_LONG(maxresults); } diff --git a/engine/client/cl_screen.c b/engine/client/cl_screen.c index 918b8c9e..90fb899a 100644 --- a/engine/client/cl_screen.c +++ b/engine/client/cl_screen.c @@ -548,16 +548,16 @@ void VARGS Stats_Message(char *msg, ...) p->time_start = cl.time; } -#define MAX_CPRINT_LINES 128 +#define MAX_CPRINT_LINES 256 void SCR_DrawCenterString (vrect_t *rect, cprint_t *p, struct font_s *font) { - int l; - int y, x; + int l; + int y, x; int left; int right; int top; int bottom; - int remaining; + int remaining; shader_t *pic; conchar_t *line_start[MAX_CPRINT_LINES]; @@ -1609,6 +1609,11 @@ void SCR_DrawPause (void) if (!cl.paused) return; +#ifndef CLIENTONLY + if (sv.active && sv.paused == PAUSE_AUTO) + return; +#endif + if (Key_Dest_Has(kdm_emenu) || Key_Dest_Has(kdm_gmenu)) return; @@ -2337,7 +2342,7 @@ static void SCR_ScreenShot_f (void) } BZ_Free(rgbbuffer); } - Con_Printf ("Couldn't write %s\n", sysname); + Con_Printf (CON_ERROR "Couldn't write %s\n", sysname); } void *SCR_ScreenShot_Capture(int fbwidth, int fbheight, enum uploadfmt *fmt) @@ -2667,8 +2672,9 @@ static void SCR_DrawCharToSnap (int num, qbyte *dest, int width) if (!draw_chars) { - draw_chars = W_SafeGetLumpName("conchars"); - if (!draw_chars) + size_t lumpsize; + draw_chars = W_SafeGetLumpName("conchars", &lumpsize); + if (!draw_chars || lumpsize != 128*128) return; } @@ -2681,7 +2687,7 @@ static void SCR_DrawCharToSnap (int num, qbyte *dest, int width) while (drawline--) { for (x=0 ; x<8 ; x++) - if (source[x]!=255) + if (source[x] && source[x]!=255) dest[x] = source[x]; source += 128; dest -= width; diff --git a/engine/client/clhl_game.c b/engine/client/clhl_game.c index 2d264035..35553dee 100644 --- a/engine/client/clhl_game.c +++ b/engine/client/clhl_game.c @@ -12,22 +12,22 @@ struct hlcvar_s *QDECL GHL_CVarGetPointer(char *varname); #if defined(_MSC_VER) - #if _MSC_VER >= 1300 - #define __func__ __FUNCTION__ - #else - #define __func__ "unknown" - #endif +# if _MSC_VER >= 1300 +# define __func__ __FUNCTION__ +# else +# define __func__ "unknown" +# endif #else - //I hope you're c99 and have a __func__ + //I hope you're c99 and have a __func__ #endif -extern cvar_t temp1; +//extern cvar_t temp1; #define ignore(s) Con_Printf("Fixme: " s "\n") #define notimpl(l) Con_Printf("halflife cl builtin not implemented on line %i\n", l) #define notimpf(f) Con_Printf("halflife cl builtin %s not implemented\n", f) #define notimp() Con_Printf("halflife cl builtin %s not implemented\n", __func__) -#define bi_begin() if (temp1.ival)Con_Printf("enter %s\n", __func__) -#define bi_end() if (temp1.ival)Con_Printf("leave %s\n", __func__) +#define bi_begin() //if (temp1.ival)Con_Printf("enter %s\n", __func__) +#define bi_end() //if (temp1.ival)Con_Printf("leave %s\n", __func__) #define bi_trace() bi_begin(); bi_end() #if HLCLIENT >= 1 @@ -1443,12 +1443,9 @@ int CLHL_ParseGamePacket(void) int flags; int lifetime; explosion_t *ef; - extern cvar_t temp1; subcode = MSG_ReadByte(); - if (temp1.value) - Con_Printf("Temp ent %i\n", subcode); switch(subcode) { case 3: diff --git a/engine/client/clq2_ents.c b/engine/client/clq2_ents.c index fc55beda..b4b2a300 100644 --- a/engine/client/clq2_ents.c +++ b/engine/client/clq2_ents.c @@ -4,6 +4,11 @@ #ifdef Q2CLIENT #include "shader.h" +//q2pro's framerate scaling runs the entire server at a higher rate (including gamecode). +//this allows lower latency on player movements without breaking things too much +//animations are still assumed to run at 10fps, so those need some fixup too +//events are keyed to not renew twice within the same 10fps window, unless the entity was actually updated. + extern cvar_t r_drawviewmodel; extern cvar_t cl_nopred; diff --git a/engine/client/console.c b/engine/client/console.c index 202b3046..7eecd7ea 100644 --- a/engine/client/console.c +++ b/engine/client/console.c @@ -1257,7 +1257,7 @@ int Con_DrawInput (console_t *con, qboolean focused, int left, int right, int y, textstart[p+cmdstart] = (unsigned int)fname[p] | (COLOR_GREEN<buttonsdown & CB_SIZELEFT) || (con_curwindow==w && w->mousecursor[0] >= -8 && w->mousecursor[0] < 0 && w->mousecursor[1] >= 8 && w->mousecursor[1] < w->wnd_h)) - R2D_FillBlock(w->wnd_x, w->wnd_y+8, 8, w->wnd_h-8); - if ((w->buttonsdown & CB_SIZERIGHT) || (con_curwindow==w && w->mousecursor[0] >= w->wnd_w-16 && w->mousecursor[0] < w->wnd_w-8 && w->mousecursor[1] >= 8 && w->mousecursor[1] < w->wnd_h)) - R2D_FillBlock(w->wnd_x+w->wnd_w-8, w->wnd_y+8, 8, w->wnd_h-8); - if ((w->buttonsdown & CB_SIZEBOTTOM) || (con_curwindow==w && w->mousecursor[0] >= -8 && w->mousecursor[0] < w->wnd_w-8 && w->mousecursor[1] >= w->wnd_h-8 && w->mousecursor[1] < w->wnd_h)) - R2D_FillBlock(w->wnd_x, w->wnd_y+w->wnd_h-8, w->wnd_w, 8); + if (!fadetime) + { + R2D_ImageColours(0, 0.1, 0.2, 1.0); + if ((w->buttonsdown & CB_SIZELEFT) || (con_curwindow==w && w->mousecursor[0] >= -8 && w->mousecursor[0] < 0 && w->mousecursor[1] >= 8 && w->mousecursor[1] < w->wnd_h)) + R2D_FillBlock(w->wnd_x, w->wnd_y+8, 8, w->wnd_h-8); + if ((w->buttonsdown & CB_SIZERIGHT) || (con_curwindow==w && w->mousecursor[0] >= w->wnd_w-16 && w->mousecursor[0] < w->wnd_w-8 && w->mousecursor[1] >= 8 && w->mousecursor[1] < w->wnd_h)) + R2D_FillBlock(w->wnd_x+w->wnd_w-8, w->wnd_y+8, 8, w->wnd_h-8); + if ((w->buttonsdown & CB_SIZEBOTTOM) || (con_curwindow==w && w->mousecursor[0] >= -8 && w->mousecursor[0] < w->wnd_w-8 && w->mousecursor[1] >= w->wnd_h-8 && w->mousecursor[1] < w->wnd_h)) + R2D_FillBlock(w->wnd_x, w->wnd_y+w->wnd_h-8, w->wnd_w, 8); + } if (R2D_Flush) R2D_Flush(); BE_Scissor(&srect); diff --git a/engine/client/image.c b/engine/client/image.c index b8e8e6d8..7308ed21 100644 --- a/engine/client/image.c +++ b/engine/client/image.c @@ -2421,8 +2421,9 @@ static void Image_LoadTextureMips(void *ctx, void *data, size_t a, size_t b) //ezhud breaks without this. I assume other things will too. this is why you shouldn't depend upon querying an image's size. if (!strncmp(tex->ident, "gfx/", 4)) { - qpic_t *pic = W_SafeGetLumpName(tex->ident+4); - if (pic) + size_t lumpsize; + qpic_t *pic = W_SafeGetLumpName(tex->ident+4, &lumpsize); + if (pic && lumpsize == 8 + pic->width*pic->height) { tex->width = pic->width; tex->height = pic->height; @@ -4350,204 +4351,220 @@ static void Image_LoadHiResTextureWorker(void *ctx, void *data, size_t a, size_t char *buf; size_t fsize; int firstex = (tex->flags & IF_EXACTEXTENSION)?tex_extensions_count-1:0; + char *altname; + char *nextalt; // Sys_Sleep(0.3); - //see if we recognise the extension, and only strip it if we do. - COM_FileExtension(tex->ident, nicename, sizeof(nicename)); - e = 0; - if (strcmp(nicename, "lmp") && strcmp(nicename, "wal")) - for (; e < tex_extensions_count; e++) - { - if (!strcmp(nicename, (*tex_extensions[e].name=='.')?tex_extensions[e].name+1:tex_extensions[e].name)) - break; - } - - //strip it and try replacements if we do, otherwise assume that we're meant to be loading progs/foo.mdl_0.tga or whatever - if (e == tex_extensions_count || (tex->flags & IF_EXACTEXTENSION)) - Q_strncpyz(nicename, tex->ident, sizeof(nicename)); - else - COM_StripExtension(tex->ident, nicename, sizeof(nicename)); - - if ((tex->flags & IF_TEXTYPE) == IF_CUBEMAP) - { //cubemaps require special handling because they are (normally) 6 files instead of 1. - //the exception is single-file dds cubemaps, but we don't support those. - if (!Image_LoadCubemapTexture(tex, nicename)) - { - if (tex->flags & IF_NOWORKER) - Image_LoadTexture_Failed(tex, NULL, 0, 0); - else - COM_AddWork(WG_MAIN, Image_LoadTexture_Failed, tex, NULL, 0, 0); - } - return; - } - - if (!tex->fallbackdata || (gl_load24bit.ival && !(tex->flags & IF_NOREPLACE))) + for(altname = tex->ident;altname;altname = nextalt) { - Q_snprintfz(fname, sizeof(fname), "dds/%s.dds", nicename); - if ((buf = COM_LoadFile (fname, 5, &fsize))) + nextalt = strchr(altname, ':'); + if (nextalt) { - Q_snprintfz(iname, sizeof(iname), "dds/%s", nicename); /*should be safe if its null*/ - if (Image_LoadTextureFromMemory(tex, tex->flags, iname, fname, buf, fsize)) - return; + nextalt++; + if (nextalt-altname >= sizeof(fname)) + continue; //too long... + memcpy(fname, altname, nextalt-altname-1); + fname[nextalt-altname-1] = 0; + altname = fname; } + //see if we recognise the extension, and only strip it if we do. + COM_FileExtension(altname, nicename, sizeof(nicename)); + e = 0; + if (strcmp(nicename, "lmp") && strcmp(nicename, "wal")) + for (; e < tex_extensions_count; e++) + { + if (!strcmp(nicename, (*tex_extensions[e].name=='.')?tex_extensions[e].name+1:tex_extensions[e].name)) + break; + } - if (strchr(nicename, '/') || strchr(nicename, '\\')) //never look in a root dir for the pic - i = 0; + //strip it and try replacements if we do, otherwise assume that we're meant to be loading progs/foo.mdl_0.tga or whatever + if (e == tex_extensions_count || (tex->flags & IF_EXACTEXTENSION)) + Q_strncpyz(nicename, altname, sizeof(nicename)); else - i = 1; + COM_StripExtension(altname, nicename, sizeof(nicename)); - for (; i < sizeof(tex_path)/sizeof(tex_path[0]); i++) + if ((tex->flags & IF_TEXTYPE) == IF_CUBEMAP) + { //cubemaps require special handling because they are (normally) 6 files instead of 1. + //the exception is single-file dds cubemaps, but we don't support those. + if (!Image_LoadCubemapTexture(tex, nicename)) + { + if (tex->flags & IF_NOWORKER) + Image_LoadTexture_Failed(tex, NULL, 0, 0); + else + COM_AddWork(WG_MAIN, Image_LoadTexture_Failed, tex, NULL, 0, 0); + } + return; + } + + if (!tex->fallbackdata || (gl_load24bit.ival && !(tex->flags & IF_NOREPLACE))) { - if (!tex_path[i].enabled) - continue; - if (tex_path[i].args >= 3) - { //this is a path that needs subpaths - char subpath[MAX_QPATH]; - char basename[MAX_QPATH]; - char *s, *n; - if (!tex->subpath || !*nicename) + Q_snprintfz(fname, sizeof(fname), "dds/%s.dds", nicename); + if ((buf = COM_LoadFile (fname, 5, &fsize))) + { + Q_snprintfz(iname, sizeof(iname), "dds/%s", nicename); /*should be safe if its null*/ + if (Image_LoadTextureFromMemory(tex, tex->flags, iname, fname, buf, fsize)) + return; + } + + + if (strchr(nicename, '/') || strchr(nicename, '\\')) //never look in a root dir for the pic + i = 0; + else + i = 1; + + for (; i < sizeof(tex_path)/sizeof(tex_path[0]); i++) + { + if (!tex_path[i].enabled) continue; + if (tex_path[i].args >= 3) + { //this is a path that needs subpaths + char subpath[MAX_QPATH]; + char basename[MAX_QPATH]; + char *s, *n; + if (!tex->subpath || !*nicename) + continue; - s = COM_SkipPath(nicename); - n = basename; - while (*s && *s != '.' && n < basename+sizeof(basename)-5) - *n++ = *s++; - s = strchr(s, '_'); - if (s) - { - while (*s && n < basename+sizeof(basename)-5) + s = COM_SkipPath(nicename); + n = basename; + while (*s && *s != '.' && n < basename+sizeof(basename)-5) *n++ = *s++; - } - *n = 0; - - for(s = tex->subpath; s; s = n) - { - //subpath a:b:c tries multiple possible sub paths, for compatibility - n = strchr(s, ':'); - if (n) + s = strchr(s, '_'); + if (s) { - if (n-s >= sizeof(subpath)) - *subpath = 0; - else - { - memcpy(subpath, s, n-s); - subpath[n-s] = 0; - } - n++; + while (*s && n < basename+sizeof(basename)-5) + *n++ = *s++; } - else - Q_strncpyz(subpath, s, sizeof(subpath)); + *n = 0; + + for(s = tex->subpath; s; s = n) + { + //subpath a:b:c tries multiple possible sub paths, for compatibility + n = strchr(s, ':'); + if (n) + { + if (n-s >= sizeof(subpath)) + *subpath = 0; + else + { + memcpy(subpath, s, n-s); + subpath[n-s] = 0; + } + n++; + } + else + Q_strncpyz(subpath, s, sizeof(subpath)); + for (e = firstex; e < tex_extensions_count; e++) + { + if (tex->flags & IF_NOPCX) + if (!strcmp(tex_extensions[e].name, ".pcx")) + continue; + Q_snprintfz(fname, sizeof(fname), tex_path[i].path, subpath, basename, tex_extensions[e].name); + if ((buf = COM_LoadFile (fname, 5, &fsize))) + { + Q_snprintfz(iname, sizeof(iname), "%s/%s", subpath, nicename); /*should be safe if its null*/ + if (Image_LoadTextureFromMemory(tex, tex->flags, iname, fname, buf, fsize)) + return; + } + } + } + } + else + { for (e = firstex; e < tex_extensions_count; e++) { if (tex->flags & IF_NOPCX) if (!strcmp(tex_extensions[e].name, ".pcx")) continue; - Q_snprintfz(fname, sizeof(fname), tex_path[i].path, subpath, basename, tex_extensions[e].name); + Q_snprintfz(fname, sizeof(fname), tex_path[i].path, nicename, tex_extensions[e].name); if ((buf = COM_LoadFile (fname, 5, &fsize))) - { - Q_snprintfz(iname, sizeof(iname), "%s/%s", subpath, nicename); /*should be safe if its null*/ - if (Image_LoadTextureFromMemory(tex, tex->flags, iname, fname, buf, fsize)) + if (Image_LoadTextureFromMemory(tex, tex->flags, nicename, fname, buf, fsize)) return; - } } } - } - else - { - for (e = firstex; e < tex_extensions_count; e++) - { - if (tex->flags & IF_NOPCX) - if (!strcmp(tex_extensions[e].name, ".pcx")) - continue; - Q_snprintfz(fname, sizeof(fname), tex_path[i].path, nicename, tex_extensions[e].name); - if ((buf = COM_LoadFile (fname, 5, &fsize))) - if (Image_LoadTextureFromMemory(tex, tex->flags, nicename, fname, buf, fsize)) - return; - } - } - //support expansion of _bump textures to _norm textures. - if (tex->flags & IF_TRYBUMP) - { - if (tex_path[i].args >= 3) + //support expansion of _bump textures to _norm textures. + if (tex->flags & IF_TRYBUMP) { - /*no legacy compat needed, hopefully*/ - } - else - { - char bumpname[MAX_QPATH], *n, *b; - b = bumpname; - n = nicename; - while(*n) + if (tex_path[i].args >= 3) { - if (*n == '_' && !strcmp(n, "_norm")) - { - strcpy(b, "_bump"); - b += 5; - n += 5; - break; - } - *b++ = *n++; + /*no legacy compat needed, hopefully*/ } - if (*n) //no _norm, give up with that - continue; - *b = 0; - for (e = firstex; e < tex_extensions_count; e++) + else { - if (!strcmp(tex_extensions[e].name, ".tga")) + char bumpname[MAX_QPATH], *n, *b; + b = bumpname; + n = nicename; + while(*n) { - Q_snprintfz(fname, sizeof(fname), tex_path[i].path, bumpname, tex_extensions[e].name); - if ((buf = COM_LoadFile (fname, 5, &fsize))) + if (*n == '_' && !strcmp(n, "_norm")) { - int w, h; - qboolean a; - qbyte *d; - if ((d = ReadTargaFile(buf, fsize, &w, &h, &a, 2))) //Only load a greyscale image. + strcpy(b, "_bump"); + b += 5; + n += 5; + break; + } + *b++ = *n++; + } + if (*n) //no _norm, give up with that + continue; + *b = 0; + for (e = firstex; e < tex_extensions_count; e++) + { + if (!strcmp(tex_extensions[e].name, ".tga")) + { + Q_snprintfz(fname, sizeof(fname), tex_path[i].path, bumpname, tex_extensions[e].name); + if ((buf = COM_LoadFile (fname, 5, &fsize))) { - BZ_Free(buf); - if (Image_LoadRawTexture(tex, tex->flags, d, NULL, w, h, TF_HEIGHT8)) + int w, h; + qboolean a; + qbyte *d; + if ((d = ReadTargaFile(buf, fsize, &w, &h, &a, 2))) //Only load a greyscale image. { - BZ_Free(tex->fallbackdata); - tex->fallbackdata = NULL; - return; + BZ_Free(buf); + if (Image_LoadRawTexture(tex, tex->flags, d, NULL, w, h, TF_HEIGHT8)) + { + BZ_Free(tex->fallbackdata); + tex->fallbackdata = NULL; + return; + } } + else + BZ_Free(buf); } - else - BZ_Free(buf); } } } } } - } - /*still failed? attempt to load quake lmp files, which have no real format id (hence why they're not above)*/ - Q_strncpyz(fname, nicename, sizeof(fname)); - COM_DefaultExtension(fname, ".lmp", sizeof(fname)); - if (!(tex->flags & IF_NOPCX) && (buf = COM_LoadFile (fname, 5, &fsize))) - { - if (Image_LoadTextureFromMemory(tex, tex->flags, nicename, fname, buf, fsize)) - return; - } - else - { - int imgwidth; - int imgheight; - qboolean alphaed; - //now look in wad files. (halflife compatability) - buf = W_GetTexture(nicename, &imgwidth, &imgheight, &alphaed); - if (buf) + /*still failed? attempt to load quake lmp files, which have no real format id (hence why they're not above)*/ + Q_strncpyz(fname, nicename, sizeof(fname)); + COM_DefaultExtension(fname, ".lmp", sizeof(fname)); + if (!(tex->flags & IF_NOPCX) && (buf = COM_LoadFile (fname, 5, &fsize))) { - if (Image_LoadRawTexture(tex, tex->flags, buf, NULL, imgwidth, imgheight, TF_RGBA32)) - { - BZ_Free(tex->fallbackdata); - tex->fallbackdata = NULL; + if (Image_LoadTextureFromMemory(tex, tex->flags, nicename, fname, buf, fsize)) return; + } + else + { + int imgwidth; + int imgheight; + qboolean alphaed; + //now look in wad files. (halflife compatability) + buf = W_GetTexture(nicename, &imgwidth, &imgheight, &alphaed); + if (buf) + { + if (Image_LoadRawTexture(tex, tex->flags, buf, NULL, imgwidth, imgheight, TF_RGBA32)) + { + BZ_Free(tex->fallbackdata); + tex->fallbackdata = NULL; + return; + } + BZ_Free(buf); } - BZ_Free(buf); } } } diff --git a/engine/client/in_sdl.c b/engine/client/in_sdl.c index 84be2d31..4d0e4e47 100644 --- a/engine/client/in_sdl.c +++ b/engine/client/in_sdl.c @@ -991,7 +991,7 @@ void INS_ReInit (void) { #if SDL_MAJOR_VERSION >= 2 unsigned int i; - memset(sdljoy, sizeof(sdljoy), 0); + memset(sdljoy, 0, sizeof(sdljoy)); for (i = 0; i < MAX_JOYSTICKS; i++) sdljoy[i].qdevid = DEVID_UNSET; SDL_InitSubSystem(SDL_INIT_JOYSTICK|SDL_INIT_GAMECONTROLLER); diff --git a/engine/client/in_win.c b/engine/client/in_win.c index ebd78e28..79841b86 100644 --- a/engine/client/in_win.c +++ b/engine/client/in_win.c @@ -1415,6 +1415,20 @@ void INS_Accumulate (void) { if (mouseactive && !dinput) { + //if you have two programs side by side that both think that they own the mouse cursor then there are certain race conditions when switching between them + //when alt+tabbing, windows won't wait for a response, so we may have already lost focus by the time we get here, and none of our internal state will know about it. + //fte won't grab the mouse until its actually inside the window, but other programs don't have similar delays. + //so when switching to other quake ports, expect fte to detect the oter engine's setcursorpos as a really big mouse move. + + RECT cliprect; + if (GetClipCursor (&cliprect) && !( + cliprect.left >= window_rect.left && + cliprect.right <= window_rect.right && + cliprect.top >= window_rect.top && + cliprect.bottom <= window_rect.bottom + )) + ; //cliprect now covers some area outside of where we asked for. + else #ifdef USINGRAWINPUT //raw input disables the system mouse, to avoid dupes if (!rawmicecount) diff --git a/engine/client/keys.c b/engine/client/keys.c index ac504d16..8c13f948 100644 --- a/engine/client/keys.c +++ b/engine/client/keys.c @@ -440,16 +440,18 @@ int Con_Navigate(console_t *con, char *line) int Con_ExecuteLine(console_t *con, char *line) { qboolean waschat = false; - char deutf8[8192]; + char *deutf8 = NULL; if (com_parseutf8.ival <= 0) { unsigned int unicode; int err; int len = 0; + int maxlen = strlen(line)*6+1; + deutf8 = malloc(maxlen); while(*line) { unicode = utf8_decode(&err, line, &line); - len += unicode_encode(deutf8+len, unicode, sizeof(deutf8)-1 - len, true); + len += unicode_encode(deutf8+len, unicode, maxlen-1 - len, true); } deutf8[len] = 0; line = deutf8; @@ -507,6 +509,7 @@ int Con_ExecuteLine(console_t *con, char *line) { Con_Printf ("]%s\n",line); Cmd_ExecuteString(exec, RESTRICT_SERVER); + free(deutf8); return true; } @@ -528,6 +531,7 @@ int Con_ExecuteLine(console_t *con, char *line) // SCR_UpdateScreen (); // force an update, because the command // // may take some time + free(deutf8); return true; } @@ -1524,6 +1528,11 @@ qboolean Key_Console (console_t *con, unsigned int unicode, int key) { // backslash text are commands, else chat int oldl = edit_line; +#ifndef FTE_TARGET_WEB + if (keydown[K_LALT] || keydown[K_RALT]) + Cbuf_AddText("\nvid_toggle\n", RESTRICT_LOCAL); +#endif + if (con_commandmatch) { //if that isn't actually a command, and we can actually complete it to something, then lets try to complete it. char *txt = key_lines[edit_line]+1; diff --git a/engine/client/m_download.c b/engine/client/m_download.c index 63aa0d5b..a4b0ce25 100644 --- a/engine/client/m_download.c +++ b/engine/client/m_download.c @@ -1,3 +1,5 @@ +//copyright 'Spike', license gplv2+ +//provides both a package manager and downloads menu. #include "quakedef.h" #if defined(WEBCLIENT) && !defined(NOBUILTINMENUS) @@ -5,7 +7,7 @@ #endif #ifdef DOWNLOADMENU - +#include "fs.h" //whole load of extra args for the downloads menu (for the downloads menu to handle engine updates). #ifdef VKQUAKE @@ -41,35 +43,82 @@ #ifndef SVNREVISION #define SVNREVISION - #endif -#define DOWNLOADABLESARGS "?ver=" STRINGIFY(SVNREVISION) PHPVK PHPGL PHPD3D PHPMIN PHPLEG PHPDBG +#define DOWNLOADABLESARGS "?ver=" STRINGIFY(SVNREVISION) PHPVK PHPGL PHPD3D PHPMIN PHPLEG PHPDBG "&arch="PLATFORM "_" ARCH_CPU_POSTFIX extern cvar_t fs_downloads_url; #define INSTALLEDFILES "installed.lst" //the file that resides in the quakedir (saying what's installed). -#define DPF_HAVEAVERSION 1 //any old version -#define DPF_WANTTOINSTALL 2 //user selected it -#define DPF_DISPLAYVERSION 4 //some sort of conflict, the package is listed twice, so show versions so the user knows what's old. -#define DPF_FORGETONUNINSTALL 8 //for previously installed packages, remove them from the list if there's no current version any more (should really be automatic if there's no known mirrors) -#define DPF_UNKNOWNVERSION 16 //we have a file with this name already, with no idea where it came from. -#define DPF_HIDDEN 32 //wrong arch, file conflicts, etc. still listed if actually installed. +//installed native okay [previously manually installed, or has no a qhash] +//installed cached okay [had a qhash] +//installed native corrupt [they overwrote it manually] +//installed cached corrupt [we fucked up, probably] +//installed native missing (becomes not installed) [deleted] +//installed cached missing (becomes not installed) [deleted] +//installed none [meta package with no files] + +//!installed native okay [was manually installed, flag as installed now] +//!installed cached okay [they got it from some other source / previously installed] +//!installed native corrupt [manually installed conflict] +//!installed cached corrupt [we fucked up, probably] + +//!installed * missing [simply not installed] + +#define DPF_INSTALLED 0x01 +#define DPF_NATIVE 0x02 //appears to be installed properly +#define DPF_CACHED 0x04 //appears to be installed in their dlcache dir (and has a qhash) +#define DPF_CORRUPT 0x08 //will be deleted before it can be changed + +#define DPF_MARKED 0x10 //user selected it +#define DPF_DISPLAYVERSION 0x20 //some sort of conflict, the package is listed twice, so show versions so the user knows what's old. +#define DPF_FORGETONUNINSTALL 0x40 //for previously installed packages, remove them from the list if there's no current version any more (should really be automatic if there's no known mirrors) +#define DPF_HIDDEN 0x80 //wrong arch, file conflicts, etc. still listed if actually installed. +#define DPF_ENGINE 0x100 //engine update. replaces old autoupdate mechanism +#define DPF_PURGE 0x200 //package should be completely removed (ie: the dlcache dir too). if its still marked then it should be reinstalled anew. available on cached or corrupt packages, implied by native. + +//pak.lst +//priories <0 +//pakX +//manifest packages +//priority 0-999 +//*.pak +//priority >=1000 +#define PM_DEFAULTPRIORITY 1000 void CL_StartCinematicOrMenu(void); -//note: these are allocated for the life of the exe -static char *downloadablelist[32]; -static char *downloadablelistnameprefix[countof(downloadablelist)]; -static char downloadablelistreceived[countof(downloadablelist)]; //well -static int numdownloadablelists = 0; +#if defined(SERVERONLY) +# define ENGINE_RENDERER "sv" +#elif defined(GLQUAKE) && (defined(VKQUAKE) || defined(D3DQUAKE) || defined(SWQUAKE)) +# define ENGINE_RENDERER "m" +#elif defined(GLQUAKE) +# define ENGINE_RENDERER "gl" +#elif defined(VKQUAKE) +# define ENGINE_RENDERER "vk" +#elif defined(D3DQUAKE) +# define ENGINE_RENDERER "d3d" +#else +# define ENGINE_RENDERER "none" +#endif +#if defined(NOCOMPAT) +# define ENGINE_CLIENT "-nc" +#elif defined(MINIMAL) +# define ENGINE_CLIENT "-min" +#elif defined(CLIENTONLY) +# define ENGINE_CLIENT "-cl" +#else +# define ENGINE_CLIENT +#endif #define THISARCH PLATFORM "_" ARCH_CPU_POSTFIX +#define THISENGINE THISARCH "-" DISTRIBUTION "-" ENGINE_RENDERER ENGINE_CLIENT typedef struct package_s { char fullname[256]; char *name; - struct package_s *override; //the package that obscures this one (later version, or whatever) + struct package_s *alternative; //alternative (hidden) forms of this package. unsigned int trymirrors; char *mirror[8]; @@ -77,6 +126,12 @@ typedef struct package_s { enum fs_relative fsroot; char version[16]; char *arch; + char *qhash; + + char *description; + char *license; + char *author; + char *previewimage; enum { EXTRACT_COPY, //just copy the download over @@ -103,24 +158,325 @@ typedef struct package_s { struct dl_download *download; int flags; + int priority; + struct package_s **link; struct package_s *next; } package_t; -typedef struct { - menucustom_t *list; - char intermediatefilename[MAX_QPATH]; - char pathprefix[MAX_QPATH]; - int parsedsourcenum; - qboolean populated; -} dlmenu_t; - +static qboolean loadedinstalled; static package_t *availablepackages; static int numpackages; -#ifdef HAVEAUTOUPDATE -static int autoupdatesetting = -1; -#endif -static qboolean MD_CheckFile(const char *filename, enum fs_relative base) +//FIXME: these are allocated for the life of the exe. changing games should purge the list. +static int numdownloadablelists = 0; +static struct +{ + char *url; + char *prefix; + char received; //says if we got a response yet or not + struct dl_download *curdl; //the download context +} downloadablelist[32]; +int downloadablessequence; //bumped any time any package is purged + +static void PM_FreePackage(package_t *p) +{ + struct packagedep_s *d; + int i; + + if (p->link) + { + if (p->alternative) + { //replace it with its alternative package + *p->link = p->alternative; + p->alternative->alternative = p->alternative->next; + if (p->alternative->alternative) + p->alternative->alternative->link = &p->alternative->alternative; + p->alternative->next = p->next; + p->alternative->link = p->link; + } + else + { //just remove it from the list. + *p->link = p->next; + if (p->next) + p->next->link = p->link; + } + } + + //free its data. + while(p->deps) + { + d = p->deps; + p->deps = d->next; + Z_Free(d); + } + + for (i = 0; i < countof(p->mirror); i++) + Z_Free(p->mirror[i]); + + Z_Free(p->qhash); + Z_Free(p->arch); + Z_Free(p); +} + +//checks the status of each package +void PM_ValidatePackage(package_t *p) +{ + package_t *o; + struct packagedep_s *dep; + vfsfile_t *pf; + p->flags &=~ (DPF_NATIVE|DPF_CACHED|DPF_CORRUPT); + if (p->flags & DPF_INSTALLED) + { + for (dep = p->deps; dep; dep = dep->next) + { + char *n; + if (dep->dtype != DEP_FILE) + continue; + if (*p->gamedir) + n = va("%s/%s", p->gamedir, dep->name); + else + n = dep->name; + pf = FS_OpenVFS(n, "rb", p->fsroot); + if (pf) + { + VFS_CLOSE(pf); + p->flags |= DPF_NATIVE; + } + else if (*p->gamedir && p->qhash) + { + char temp[MAX_OSPATH]; + if (FS_GenCachedPakName(n, p->qhash, temp, sizeof(temp))) + { + pf = FS_OpenVFS(temp, "rb", p->fsroot); + if (pf) + { + VFS_CLOSE(pf); + p->flags |= DPF_CACHED; + } + } + } + if (!(p->flags & (DPF_NATIVE|DPF_CACHED))) + Con_Printf("WARNING: %s (%s) no longer exists\n", p->fullname, n); + } + } + else + { + for (dep = p->deps; dep; dep = dep->next) + { + char *n; + struct packagedep_s *odep; + unsigned int fl = DPF_NATIVE; + if (dep->dtype != DEP_FILE) + continue; + if (*p->gamedir) + n = va("%s/%s", p->gamedir, dep->name); + else + n = dep->name; + pf = FS_OpenVFS(n, "rb", p->fsroot); + if (!pf && *p->gamedir && p->qhash) + { + char temp[MAX_OSPATH]; + if (FS_GenCachedPakName(n, p->qhash, temp, sizeof(temp))) + { + pf = FS_OpenVFS(temp, "rb", p->fsroot); + fl = DPF_CACHED; + } + //fixme: skip any archive checks + } + + if (pf) + { + for (o = availablepackages; o; o = o->next) + { + if (o == p) + continue; + if (o->flags & DPF_INSTALLED) + { + if (!strcmp(p->gamedir, o->gamedir) && p->fsroot == o->fsroot) + if (strcmp(p->fullname, o->fullname) || strcmp(p->version, o->version)) + { + for (odep = o->deps; odep; odep = odep->next) + { + if (!strcmp(dep->name, odep->name)) + break; + } + if (odep) + break; + } + } + } + if (o && o->qhash && p->qhash && (o->flags & DPF_CACHED) && fl == DPF_CACHED) + p->flags |= DPF_CACHED; + else if (!o) + { + if (p->qhash) + { + char buf[8]; + searchpathfuncs_t *archive; + + if (!Q_strcasecmp(COM_FileExtension(n, buf, sizeof(buf)), "pak")) + archive = FSPAK_LoadArchive(pf, n, NULL); + else + { +#ifdef AVAIL_ZLIB //assume zip/pk3/pk4/apk/etc + archive = FSZIP_LoadArchive(pf, n, NULL); +#else + archive = NULL; +#endif + } + + if (archive) + { + unsigned int fqhash; + pf = NULL; + fqhash = archive->GeneratePureCRC(archive, 0, 0); + archive->ClosePath(archive); + + if (fqhash == (unsigned int)strtoul(p->qhash, NULL, 0)) + { + p->flags |= fl; + if (fl&DPF_NATIVE) + p->flags |= DPF_MARKED|DPF_INSTALLED; + break; + } + else + pf = NULL; + } + else + VFS_CLOSE(pf); + } + else + { + p->flags |= DPF_CORRUPT|fl; + VFS_CLOSE(pf); + } + break; + } + VFS_CLOSE(pf); + } + } + } +} + +static qboolean PM_MergePackage(package_t *oldp, package_t *newp) +{ + //we don't track mirrors for previously-installed packages. + //use the file list of the installed package, zips ignore the file list of the remote package but otherwise they must match to be mergeable + //local installed copies of the package may lack some information, like mirrors. + //the old package *might* be installed, the new won't be. this means we need to use the old's file list rather than the new + if (!oldp->qhash || !strcmp(oldp->qhash?oldp->qhash:"", newp->qhash?newp->qhash:"")) + { + unsigned int om, nm; + struct packagedep_s *od, *nd; + qboolean ignorefiles; + for (om = 0; om < countof(oldp->mirror) && oldp->mirror[om]; om++) + ; + for (nm = 0; nm < countof(newp->mirror) && newp->mirror[nm]; nm++) + ; + if (oldp->priority != newp->priority) + return false; + + ignorefiles = (oldp->extract==EXTRACT_ZIP); //zips ignore the remote file list, its only important if its already installed (so just keep the old file list and its fine). + if (oldp->extract != newp->extract) + { //if both have mirrors of different types then we have some sort of conflict + if (ignorefiles || (om && nm)) + return false; + } + for (od = oldp->deps, nd = newp->deps; od && nd; ) + { + //if its a zip then the 'remote' file list will be blank while the local list is not (we can just keep the local list). + //if the file list DOES change, then bump the version. + if (ignorefiles) + { + if (od->dtype == DEP_FILE) + { + od = od->next; + continue; + } + if (nd->dtype == DEP_FILE) + { + nd = nd->next; + continue; + } + } + + if (od->dtype != nd->dtype) + return false; //deps don't match + if (strcmp(od->name, nd->name)) + return false; + od = od->next; + nd = nd->next; + } + + //overwrite these. use the 'new' / remote values for each of them + //the versions of the two packages will be the same, so the texts should be the same. still favour the new one so that things can be corrected serverside without needing people to redownload everything. + if (newp->qhash){Z_Free(oldp->qhash); oldp->qhash = Z_StrDup(newp->qhash);} + if (newp->description){Z_Free(oldp->description); oldp->description = Z_StrDup(newp->description);} + if (newp->license){Z_Free(oldp->license); oldp->license = Z_StrDup(newp->license);} + if (newp->author){Z_Free(oldp->author); oldp->author = Z_StrDup(newp->author);} + if (newp->previewimage){Z_Free(oldp->previewimage); oldp->previewimage = Z_StrDup(newp->previewimage);} + + if (nm) + { //copy over the mirrors + oldp->extract = newp->extract; + for (; nm --> 0 && om < countof(oldp->mirror); om++) + { + oldp->mirror[om] = newp->mirror[nm]; + newp->mirror[nm] = NULL; + } + } + oldp->flags &= ~DPF_FORGETONUNINSTALL | (newp->flags & DPF_FORGETONUNINSTALL); + + PM_FreePackage(newp); + return true; + } + return false; +} + +static void PM_InsertPackage(package_t *p) +{ + package_t **link; + for (link = &availablepackages; *link; link = &(*link)->next) + { + package_t *prev = *link; + int v = strcmp(prev->fullname, p->fullname); + if (v > 0) + break; //insert before this one + else if (v == 0) + { //name matches. + //if (!strcmp(p->fullname),prev->fullname) + if (!strcmp(p->version, prev->version)) + if (!strcmp(p->gamedir, prev->gamedir)) + if (!strcmp(p->arch?p->arch:"", prev->arch?prev->arch:"")) + { /*package matches, merge them somehow, don't add*/ + package_t *a; + if (PM_MergePackage(prev, p)) + return; + for (a = p->alternative; a; a = a->next) + { + if (PM_MergePackage(a, p)) + return; + } + p->next = prev->alternative; + prev->alternative = p; + p->link = &prev->alternative; + return; + } + + //something major differs, display both independantly. + p->flags |= DPF_DISPLAYVERSION; + prev->flags |= DPF_DISPLAYVERSION; + } + } + p->next = *link; + p->link = link; + *link = p; + PM_ValidatePackage(p); + numpackages++; +} + + +static qboolean PM_CheckFile(const char *filename, enum fs_relative base) { vfsfile_t *f = FS_OpenVFS(filename, "rb", base); if (f) @@ -130,7 +486,7 @@ static qboolean MD_CheckFile(const char *filename, enum fs_relative base) } return false; } -void MD_AddDep(package_t *p, int deptype, const char *depname) +static void PM_AddDep(package_t *p, int deptype, const char *depname) { struct packagedep_s *nd, **link; @@ -149,35 +505,33 @@ void MD_AddDep(package_t *p, int deptype, const char *depname) *link = nd; } -static void M_DL_AddSubList(const char *url, const char *prefix) +static void PM_AddSubList(char *url, const char *prefix) { int i; for (i = 0; i < numdownloadablelists; i++) { - if (!strcmp(downloadablelist[i], url)) + if (!strcmp(downloadablelist[i].url, url)) break; } if (i == numdownloadablelists && i < countof(downloadablelist)) { - downloadablelist[i] = BZ_Malloc(strlen(url)+1); - strcpy(downloadablelist[i], url); + downloadablelist[i].url = BZ_Malloc(strlen(url)+1); + strcpy(downloadablelist[i].url, url); - downloadablelistnameprefix[i] = BZ_Malloc(strlen(prefix)+1); - strcpy(downloadablelistnameprefix[i], prefix); + downloadablelist[i].prefix = BZ_Malloc(strlen(prefix)+1); + strcpy(downloadablelist[i].prefix, prefix); numdownloadablelists++; } } -static package_t *BuildPackageList(vfsfile_t *f, int flags, const char *url, const char *prefix) +static void PM_ParsePackageList(vfsfile_t *f, int parseflags, const char *url, const char *prefix) { - char line[1024]; - package_t *p, *o; - package_t *first = NULL; + char line[65536]; + package_t *p; struct packagedep_s *dep; char *sl; - vfsfile_t *pf; int version; char defaultgamedir[64]; @@ -186,7 +540,7 @@ static package_t *BuildPackageList(vfsfile_t *f, int flags, const char *url, con int argc; if (!f) - return NULL; + return; Q_strncpyz(defaultgamedir, FS_GetGamedir(false), sizeof(defaultgamedir)); @@ -210,13 +564,13 @@ static package_t *BuildPackageList(vfsfile_t *f, int flags, const char *url, con } while (!Cmd_Argc()); if (strcmp(Cmd_Argv(0), "version")) - return NULL; //it's not the right format. + return; //it's not the right format. version = atoi(Cmd_Argv(1)); if (version != 0 && version != 1 && version != 2) { Con_Printf("Packagelist is of a future or incompatible version\n"); - return NULL; //it's not the right version. + return; //it's not the right version. } while(1) @@ -238,7 +592,7 @@ static package_t *BuildPackageList(vfsfile_t *f, int flags, const char *url, con subprefix = va("%s/%s", prefix, Cmd_Argv(2)); else subprefix = Cmd_Argv(2); - M_DL_AddSubList(Cmd_Argv(1), subprefix); + PM_AddSubList(Cmd_Argv(1), subprefix); continue; } if (!strcmp(Cmd_Argv(0), "set")) @@ -267,16 +621,27 @@ static package_t *BuildPackageList(vfsfile_t *f, int flags, const char *url, con } continue; } - if (version == 2) + if (version > 1) { char *fullname = Cmd_Argv(0); char *file = NULL; char *url = NULL; char *gamedir = NULL; char *ver = NULL; + char *arch = NULL; + char *qhash = NULL; + char *description = NULL; + char *license = NULL; + char *author = NULL; + char *previewimage = NULL; int extract = EXTRACT_COPY; + int priority = PM_DEFAULTPRIORITY; + unsigned int flags = parseflags; int i; + if (version > 2) + flags &= DPF_INSTALLED; + p = Z_Malloc(sizeof(*p)); for (i = 1; i < argc; i++) { @@ -290,12 +655,24 @@ static package_t *BuildPackageList(vfsfile_t *f, int flags, const char *url, con else if (!strncmp(arg, "v=", 2)) ver = arg+2; else if (!strncmp(arg, "arch=", 5)) - /*arch = arg+5*/; + arch = arg+5; + else if (!strncmp(arg, "priority=", 9)) + priority = atoi(arg+9); + else if (!strncmp(arg, "qhash=", 6)) + qhash = arg+6; + else if (!strncmp(arg, "desc=", 5)) + description = arg+5; + else if (!strncmp(arg, "license=", 8)) + license = arg+8; + else if (!strncmp(arg, "author=", 7)) + author = arg+7; + else if (!strncmp(arg, "preview=", 8)) + previewimage = arg+8; else if (!strncmp(arg, "file=", 5)) { if (!file) file = arg+5; - MD_AddDep(p, DEP_FILE, arg+5); + PM_AddDep(p, DEP_FILE, arg+5); } else if (!strncmp(arg, "extract=", 8)) { @@ -309,13 +686,17 @@ static package_t *BuildPackageList(vfsfile_t *f, int flags, const char *url, con Con_Printf("Unknown decompression method: %s\n", arg+8); } else if (!strncmp(arg, "depend=", 7)) - MD_AddDep(p, DEP_REQUIRE, arg+7); + PM_AddDep(p, DEP_REQUIRE, arg+7); else if (!strncmp(arg, "conflict=", 9)) - MD_AddDep(p, DEP_CONFLICT, arg+9); + PM_AddDep(p, DEP_CONFLICT, arg+9); else if (!strncmp(arg, "fileconflict=", 13)) - MD_AddDep(p, DEP_FILECONFLICT, arg+13); + PM_AddDep(p, DEP_FILECONFLICT, arg+13); else if (!strncmp(arg, "recommend=", 10)) - MD_AddDep(p, DEP_RECOMMEND, arg+10); + PM_AddDep(p, DEP_RECOMMEND, arg+10); + else if (!strncmp(arg, "stale=", 6) && version==2) + flags &= ~DPF_INSTALLED; + else if (!strncmp(arg, "installed=", 6) && version>2) + flags |= parseflags & DPF_INSTALLED; else { Con_DPrintf("Unknown package property\n"); @@ -336,6 +717,15 @@ static package_t *BuildPackageList(vfsfile_t *f, int flags, const char *url, con Q_snprintfz(p->gamedir, sizeof(p->gamedir), "%s", gamedir); p->fsroot = FS_ROOT; p->extract = extract; + p->priority = priority; + p->flags = flags; + + p->arch = arch?Z_StrDup(arch):NULL; + p->qhash = qhash?Z_StrDup(qhash):NULL; + p->description = description?Z_StrDup(description):NULL; + p->license = license?Z_StrDup(license):NULL; + p->author = author?Z_StrDup(author):NULL; + p->previewimage = previewimage?Z_StrDup(previewimage):NULL; if (url && (!strncmp(url, "http://", 7) || !strncmp(url, "https://", 8))) p->mirror[0] = Z_StrDup(url); @@ -353,8 +743,11 @@ static package_t *BuildPackageList(vfsfile_t *f, int flags, const char *url, con ext = ".zip"; url = file; } - for (m = 0; m < nummirrors; m++) - p->mirror[m] = Z_StrDup(va("%s%s%s", mirror[m], url, ext)); + if (url) + { + for (m = 0; m < nummirrors; m++) + p->mirror[m] = Z_StrDup(va("%s%s%s", mirror[m], url, ext)); + } } } else @@ -375,8 +768,11 @@ static package_t *BuildPackageList(vfsfile_t *f, int flags, const char *url, con while((sl = strchr(p->name, '/'))) p->name = sl+1; + p->priority = PM_DEFAULTPRIORITY; + p->flags = parseflags; + p->mirror[0] = Z_StrDup(Cmd_Argv(1)); - MD_AddDep(p, DEP_FILE, Cmd_Argv(2)); + PM_AddDep(p, DEP_FILE, Cmd_Argv(2)); Q_strncpyz(p->version, Cmd_Argv(3), sizeof(p->version)); Q_strncpyz(p->gamedir, Cmd_Argv(4), sizeof(p->gamedir)); if (!strcmp(p->gamedir, "../")) @@ -394,10 +790,21 @@ static package_t *BuildPackageList(vfsfile_t *f, int flags, const char *url, con p->fsroot = FS_ROOT; } } - p->flags = flags; - if (p->arch && Q_strcasecmp(p->arch, THISARCH)) - p->flags |= DPF_HIDDEN; + if (p->arch) + { + if (!Q_strcasecmp(p->arch, THISENGINE)) + { + if (Sys_GetAutoUpdateSetting() == UPD_UNSUPPORTED) + p->flags |= DPF_HIDDEN; + else + p->flags |= DPF_ENGINE; + } + else if (!Q_strcasecmp(p->arch, THISARCH)) + ; + else + p->flags |= DPF_HIDDEN; //other engine builds or other cpus are all hidden + } for (dep = p->deps; dep; dep = dep->next) { if (dep->dtype == DEP_FILECONFLICT) @@ -407,86 +814,452 @@ static package_t *BuildPackageList(vfsfile_t *f, int flags, const char *url, con n = va("%s/%s", p->gamedir, dep->name); else n = dep->name; - if (MD_CheckFile(n, p->fsroot)) + if (PM_CheckFile(n, p->fsroot)) p->flags |= DPF_HIDDEN; } } + if (p->flags & DPF_INSTALLED) + p->flags |= DPF_MARKED; - if (flags & DPF_HAVEAVERSION) - { - for (dep = p->deps; dep; dep = dep->next) - { - char *n; - if (dep->dtype != DEP_FILE) - continue; - if (*p->gamedir) - n = va("%s/%s", p->gamedir, dep->name); - else - n = dep->name; - pf = FS_OpenVFS(n, "rb", p->fsroot); - if (pf) - VFS_CLOSE(pf); - else - Con_Printf("WARNING: %s (%s) no longer exists\n", p->fullname, n); - } - } - else - { - for (dep = p->deps; dep; dep = dep->next) - { - char *n; - struct packagedep_s *odep; - if (dep->dtype != DEP_FILE) - continue; - if (*p->gamedir) - n = va("%s/%s", p->gamedir, dep->name); - else - n = dep->name; - pf = FS_OpenVFS(n, "rb", p->fsroot); - if (pf) - { - VFS_CLOSE(pf); + PM_InsertPackage(p); + } + } +} - for (o = availablepackages; o; o = o->next) - { - if (o->flags & DPF_HAVEAVERSION) - { - if (!strcmp(p->gamedir, o->gamedir) && p->fsroot == o->fsroot) - if (strcmp(p->fullname, o->fullname) || strcmp(p->version, o->version)) - { - for (odep = o->deps; odep; odep = odep->next) - { - if (!strcmp(dep->name, odep->name)) - break; - } - if (odep) - break; - } - } - } - if (!o) - { - p->flags |= DPF_UNKNOWNVERSION; - break; - } - } - } - } +void PM_LoadPackages(searchpath_t **oldpaths, const char *parent_pure, const char *parent_logical, searchpath_t *search, unsigned int loadstuff, int minpri, int maxpri) +{ + package_t *p; + struct packagedep_s *d; + char temp[MAX_OSPATH]; + int pri; - p->next = first; - first = p; + //figure out what we've previously installed. + if (!loadedinstalled) + { + vfsfile_t *f = FS_OpenVFS(INSTALLEDFILES, "rb", FS_ROOT); + loadedinstalled = true; + if (f) + { + PM_ParsePackageList(f, DPF_FORGETONUNINSTALL|DPF_INSTALLED, NULL, ""); + VFS_CLOSE(f); } } - return first; + do + { + //find the lowest used priority above the previous + pri = maxpri; + for (p = availablepackages; p; p = p->next) + { + if ((p->flags & DPF_INSTALLED) && p->qhash && p->priority>=minpri&&p->prioritygamedir)) + pri = p->priority; + } + minpri = pri+1; + + for (p = availablepackages; p; p = p->next) + { + if ((p->flags & DPF_INSTALLED) && p->qhash && p->priority==pri && !Q_strcasecmp(parent_pure, p->gamedir)) + { + for (d = p->deps; d; d = d->next) + { + if (d->dtype == DEP_FILE) + { + Q_snprintfz(temp, sizeof(temp), "%s/%s", p->gamedir, d->name); + FS_AddHashedPackage(oldpaths, parent_pure, parent_logical, search, loadstuff, temp, p->qhash, NULL); + } + } + } + } + } while (pri < maxpri); } +void PM_Shutdown(void) +{ + //free everything... + loadedinstalled = false; + fs_downloads_url.modified = false; + + downloadablessequence++; + + while(numdownloadablelists > 0) + { + numdownloadablelists--; + + if (downloadablelist[numdownloadablelists].curdl) + { + DL_Close(downloadablelist[numdownloadablelists].curdl); + downloadablelist[numdownloadablelists].curdl = NULL; + } + downloadablelist[numdownloadablelists].received = 0; + Z_Free(downloadablelist[numdownloadablelists].url); + downloadablelist[numdownloadablelists].url = NULL; + Z_Free(downloadablelist[numdownloadablelists].prefix); + downloadablelist[numdownloadablelists].prefix = NULL; + } + + while (availablepackages) + PM_FreePackage(availablepackages); +} + +#ifndef SERVERONLY +qboolean doautoupdate; + +static void PM_PreparePackageList(void) +{ + //figure out what we've previously installed. + if (!loadedinstalled) + { + vfsfile_t *f = FS_OpenVFS(INSTALLEDFILES, "rb", FS_ROOT); + loadedinstalled = true; + if (f) + { + PM_ParsePackageList(f, DPF_FORGETONUNINSTALL|DPF_INSTALLED, NULL, ""); + VFS_CLOSE(f); + } + } +} + + + +//finds the newest version +static package_t *PM_FindPackage(char *packagename) +{ + package_t *p, *r = NULL; + + for (p = availablepackages; p; p = p->next) + { + if (!strcmp(p->fullname, packagename)) + { + if (!r || strcmp(r->version, p->version)>0) + r = p; + } + } + if (r) + return r; + + for (p = availablepackages; p; p = p->next) + { + if (!strcmp(p->name, packagename)) + { + if (!r || strcmp(r->version, p->version)>0) + r = p; + } + } + return r; +} +//returns the marked version of a package, if any. +static package_t *PM_MarkedPackage(char *packagename) +{ + package_t *p; + for (p = availablepackages; p; p = p->next) + { + if (p->flags & DPF_MARKED) + if (!strcmp(p->name, packagename) || !strcmp(p->fullname, packagename)) + return p; + } + return NULL; +} + +//just flags, doesn't delete +static void PM_UnmarkPackage(package_t *package) +{ + package_t *o; + struct packagedep_s *dep; + + if (!(package->flags & DPF_MARKED)) + return; //looks like its already deselected. + package->flags &= ~(DPF_MARKED); + + //Is this safe? + package->trymirrors = 0; //if its enqueued, cancel that quickly... + if (package->download) + { //if its currently downloading, cancel it. + DL_Close(package->download); + package->download = NULL; + } + + //remove stuff that depends on us + for (o = availablepackages; o; o = o->next) + { + for (dep = o->deps; dep; dep = dep->next) + if (dep->dtype == DEP_REQUIRE) + if (!strcmp(dep->name, package->name) || !strcmp(dep->name, package->fullname)) + PM_UnmarkPackage(o); + } +} + +//just flags, doesn't install +static void PM_MarkPackage(package_t *package) +{ + package_t *o; + struct packagedep_s *dep, *dep2; + qboolean replacing = false; + + if (package->flags & DPF_MARKED) + return; //looks like its already picked. + + //any file-conflicts prevent the package from being installable. + //this is mostly for pak1.pak + for (dep = package->deps; dep; dep = dep->next) + { + if (dep->dtype == DEP_FILECONFLICT) + { + const char *n; + if (*package->gamedir) + n = va("%s/%s", package->gamedir, dep->name); + else + n = dep->name; + if (PM_CheckFile(n, package->fsroot)) + return; + } + } + + package->flags |= DPF_MARKED; + + //first check to see if we're replacing a different version of the same package + for (o = availablepackages; o; o = o->next) + { + if (o == package) + continue; + + if (o->flags & DPF_MARKED) + { + if (!strcmp(o->fullname, package->fullname)) + { //replaces this package + o->flags &= ~DPF_MARKED; + replacing = true; + } + else + { //two packages with the same filename are always mutually incompatible, but with totally separate dependancies etc. + qboolean remove = false; + for (dep = package->deps; dep; dep = dep->next) + { + if (dep->dtype == DEP_FILE) + for (dep2 = o->deps; dep2; dep2 = dep2->next) + { + if (dep2->dtype == DEP_FILE) + if (!strcmp(dep->name, dep2->name)) + { + PM_UnmarkPackage(o); + remove = true; + break; + } + } + if (remove) + break; + } + //fixme: zip content conflicts + } + } + } + + //if we are replacing an existing one, then dependancies are already settled (only because we don't do version deps) + if (replacing) + return; + + //satisfy our dependancies. + for (dep = package->deps; dep; dep = dep->next) + { + if (dep->dtype == DEP_REQUIRE || dep->dtype == DEP_RECOMMEND) + { + package_t *d = PM_MarkedPackage(dep->name); + if (!d) + { + d = PM_FindPackage(dep->name); + if (d) + PM_MarkPackage(d); + else + Con_DPrintf("Couldn't find dependancy \"%s\"\n", dep->name); + } + } + if (dep->dtype == DEP_CONFLICT) + { + for (;;) + { + package_t *d = PM_MarkedPackage(dep->name); + if (!d) + break; + PM_UnmarkPackage(d); + } + } + } + + //remove any packages that conflict with us. + for (o = availablepackages; o; o = o->next) + { + for (dep = o->deps; dep; dep = dep->next) + if (dep->dtype == DEP_CONFLICT) + if (!strcmp(dep->name, package->fullname) || !strcmp(dep->name, package->name)) + PM_UnmarkPackage(o); + } +} + +//just flag stuff as needing updating +static unsigned int PM_MarkUpdates (void) +{ + unsigned int changecount = 0; + package_t *p, *o, *b, *e = NULL; + for (p = availablepackages; p; p = p->next) + { + if ((p->flags & DPF_ENGINE) && !(p->flags & DPF_HIDDEN)) + { + if ((p->flags & DPF_MARKED) || !e || strcmp(e->version, p->version) < 0) + e = p; + } + if (p->flags & DPF_MARKED) + { + b = NULL; + for (o = availablepackages; o; o = o->next) + { + if (p == o || (o->flags & DPF_HIDDEN)) + continue; + if (!strcmp(o->fullname, p->fullname) && !strcmp(o->arch?o->arch:"", p->arch?p->arch:"") && strcmp(o->version, p->version) > 0) + { + if (!b || strcmp(b->version, o->version) < 0) + b = o; + } + } + + if (b) + { + changecount++; + PM_MarkPackage(b); + PM_UnmarkPackage(p); + } + } + } + if (e && !(e->flags & DPF_MARKED)) + { + if (Sys_GetAutoUpdateSetting() >= UPD_STABLE) + { + changecount++; + PM_MarkPackage(e); + } + } + + return changecount; +} + +static void PM_ListDownloaded(struct dl_download *dl) +{ + int i; + vfsfile_t *f; + f = dl->file; + dl->file = NULL; + + i = dl->user_num; + + if (dl != downloadablelist[i].curdl) + { + //this request looks stale. + VFS_CLOSE(f); + return; + } + downloadablelist[i].curdl = NULL; + + if (f) + { + downloadablelist[i].received = 1; + PM_ParsePackageList(f, 0, dl->url, downloadablelist[i].prefix); + VFS_CLOSE(f); + } + else + downloadablelist[i].received = -1; + + if (!doautoupdate) + return; //don't spam this. + for (i = 0; i < numdownloadablelists; i++) + { + if (!downloadablelist[i].received) + break; + } + if (i == numdownloadablelists) + { + doautoupdate = true; + if (PM_MarkUpdates()) + { + if (Key_Dest_Has(kdm_emenu)) + { + Key_Dest_Remove(kdm_emenu); + m_state = m_none; + } +#ifdef MENU_DAT + if (Key_Dest_Has(kdm_gmenu)) + MP_Toggle(0); +#endif + Cmd_ExecuteString("menu_download\n", RESTRICT_LOCAL); + } + } +} +//retry 1== +static void PM_UpdatePackageList(qboolean autoupdate, int retry) +{ + unsigned int i; + + if (retry>1 || fs_downloads_url.modified) + PM_Shutdown(); + + PM_PreparePackageList(); + + //make sure our sources are okay. + if (*fs_downloads_url.string) + PM_AddSubList(fs_downloads_url.string, ""); + + doautoupdate |= autoupdate; + + //kick off the initial tier of downloads. + for (i = 0; i < numdownloadablelists; i++) + { + if (downloadablelist[i].received) + continue; + autoupdate = false; + if (downloadablelist[i].curdl) + continue; + + downloadablelist[i].curdl = HTTP_CL_Get(va("%s"DOWNLOADABLESARGS, downloadablelist[i].url), NULL, PM_ListDownloaded); + if (downloadablelist[i].curdl) + { + downloadablelist[i].curdl->user_num = i; + + downloadablelist[i].curdl->file = VFSPIPE_Open(); + downloadablelist[i].curdl->isquery = true; + DL_CreateThread(downloadablelist[i].curdl, NULL, NULL); + } + else + { + Con_Printf("Could not contact server - %s\n", downloadablelist[i].url); + downloadablelist[i].received = -1; + } + } + + if (autoupdate) + { + doautoupdate = 0; + if (PM_MarkUpdates()) + { + Cbuf_AddText("menu_download\n", RESTRICT_LOCAL); + } + } +} + + + +typedef struct { + menucustom_t *list; + char intermediatefilename[MAX_QPATH]; + char pathprefix[MAX_QPATH]; + int downloadablessequence; + qboolean populated; +} dlmenu_t; + +static int autoupdatesetting = UPD_UNSUPPORTED; + static void COM_QuotedConcat(const char *cat, char *buf, size_t bufsize) { const unsigned char *gah; for (gah = (const unsigned char*)cat; *gah; gah++) { - if (*gah <= ' ' || *gah == '$' || *gah == '\"') + if (*gah <= ' ' || *gah == '$' || *gah == '\"' || *gah == '\n' || *gah == '\r') break; } if (*gah || *cat == '\\' || @@ -502,11 +1275,11 @@ static void COM_QuotedConcat(const char *cat, char *buf, size_t bufsize) Q_strncatz(buf, cat, bufsize); } } -static void WriteInstalledPackages(void) +static void PM_WriteInstalledPackages(void) { char *s; - package_t *p; - struct packagedep_s *dep; + package_t *p, *e = NULL; + struct packagedep_s *dep, *ef = NULL; vfsfile_t *f = FS_OpenVFS(INSTALLEDFILES, "wb", FS_ROOT); if (!f) { @@ -518,11 +1291,21 @@ static void WriteInstalledPackages(void) VFS_WRITE(f, s, strlen(s)); for (p = availablepackages; p ; p=p->next) { - if (p->flags & DPF_HAVEAVERSION) + if (p->flags & (DPF_CACHED|DPF_INSTALLED)) { char buf[8192]; buf[0] = 0; COM_QuotedString(p->fullname, buf, sizeof(buf), false); + if (p->flags & DPF_INSTALLED) + { //v3+ +// Q_strncatz(buf, " ", sizeof(buf)); +// COM_QuotedConcat(va("installed=1"), buf, sizeof(buf)); + } + else + { //v2 + Q_strncatz(buf, " ", sizeof(buf)); + COM_QuotedConcat(va("stale=1"), buf, sizeof(buf)); + } if (*p->version) { Q_strncatz(buf, " ", sizeof(buf)); @@ -533,18 +1316,54 @@ static void WriteInstalledPackages(void) Q_strncatz(buf, " ", sizeof(buf)); COM_QuotedConcat(va("gamedir=%s", p->gamedir), buf, sizeof(buf)); } + if (p->qhash) + { + Q_strncatz(buf, " ", sizeof(buf)); + COM_QuotedConcat(va("qhash=%s", p->qhash), buf, sizeof(buf)); + } + if (p->priority!=PM_DEFAULTPRIORITY) + { + Q_strncatz(buf, " ", sizeof(buf)); + COM_QuotedConcat(va("priority=%i", p->priority), buf, sizeof(buf)); + } if (p->arch) { Q_strncatz(buf, " ", sizeof(buf)); COM_QuotedConcat(va("arch=%s", p->arch), buf, sizeof(buf)); } + if (p->description) + { + Q_strncatz(buf, " ", sizeof(buf)); + COM_QuotedConcat(va("description=%s", p->description), buf, sizeof(buf)); + } + if (p->license) + { + Q_strncatz(buf, " ", sizeof(buf)); + COM_QuotedConcat(va("license=%s", p->license), buf, sizeof(buf)); + } + if (p->author) + { + Q_strncatz(buf, " ", sizeof(buf)); + COM_QuotedConcat(va("author=%s", p->author), buf, sizeof(buf)); + } + if (p->previewimage) + { + Q_strncatz(buf, " ", sizeof(buf)); + COM_QuotedConcat(va("preview=%s", p->previewimage), buf, sizeof(buf)); + } + for (dep = p->deps; dep; dep = dep->next) { if (dep->dtype == DEP_FILE) { Q_strncatz(buf, " ", sizeof(buf)); COM_QuotedConcat(va("file=%s", dep->name), buf, sizeof(buf)); + if ((p->flags & DPF_ENGINE) && (!e || strcmp(e->version, p->version) < 0)) + { + e = p; + ef = dep; + } } else if (dep->dtype == DEP_REQUIRE) { @@ -568,134 +1387,79 @@ static void WriteInstalledPackages(void) } } + buf[sizeof(buf)-2] = 0; //just in case. Q_strncatz(buf, "\n", sizeof(buf)); VFS_WRITE(f, buf, strlen(buf)); } } VFS_CLOSE(f); -} -static qboolean ComparePackages(package_t **l, package_t *p) -{ - int v = strcmp((*l)->fullname, p->fullname); - if (v > 0) + if (ef) { - p->next = (*l); - (*l) = p; - - numpackages++; - return true; + char native[MAX_OSPATH]; + FS_NativePath(ef->name, e->fsroot, native, sizeof(native)); + Sys_SetUpdatedBinary(native); } - else if (v == 0) - { - if (!strcmp(p->version, (*l)->version)) - if (!strcmp(p->gamedir, (*l)->gamedir)) -// if (!strcmp((*l)->fullname, p->fullname)) - { /*package matches, free the new one, don't add*/ - p->override = *l; - return false; - } - - p->flags |= DPF_DISPLAYVERSION; - (*l)->flags |= DPF_DISPLAYVERSION; - } - return false; -} - -static void InsertPackage(package_t **l, package_t *p) -{ - package_t *lp; - if (!*l) //there IS no list. - { - *l = p; - p->next = NULL; - - numpackages++; - return; - } - if (ComparePackages(l, p)) - return; - for (lp = *l; lp->next; lp=lp->next) - { - if (ComparePackages(&lp->next, p)) - return; - } - lp->next = p; - p->next = NULL; - numpackages++; -} -static void ConcatPackageLists(package_t *l2) -{ - package_t *n; - while(l2) - { - n = l2->next; - l2->next = NULL; - InsertPackage(&availablepackages, l2); - l2 = n; - } -} - -static void M_DL_Notification(struct dl_download *dl) -{ - int i; - vfsfile_t *f; - f = dl->file; - dl->file = NULL; - - i = dl->user_num; - - if (f) - { - downloadablelistreceived[i] = 1; - ConcatPackageLists(BuildPackageList(f, 0, dl->url, downloadablelistnameprefix[i])); - VFS_CLOSE(f); - } - else - downloadablelistreceived[i] = -1; } static void MD_Draw (int x, int y, struct menucustom_s *c, struct menu_s *m) { package_t *p; - int fl; char *n; + if (c->dint != downloadablessequence) + return; //probably stale p = c->dptr; if (p) { - fl = p->flags & (DPF_HAVEAVERSION | DPF_WANTTOINSTALL); - if (p->flags & DPF_HIDDEN) - { - Draw_FunString (x+4, y, "---"); - return; - } - else if (p->download) + if (p->alternative && (p->flags & DPF_HIDDEN)) + p = p->alternative; + + if (p->download) Draw_FunString (x+4, y, va("%i", (int)p->download->qdownload.percent)); else if (p->trymirrors) Draw_FunString (x+4, y, "PND"); - else + else { - switch(fl) + switch((p->flags & (DPF_INSTALLED | DPF_MARKED))) { case 0: - if (p->flags & DPF_UNKNOWNVERSION) - Draw_FunString (x, y, "???"); + if (p->flags & DPF_PURGE) + Draw_FunString (x, y, "DEL"); //purge + else if (p->flags & DPF_HIDDEN) + Draw_FunString (x+4, y, "---"); + else if (p->flags & DPF_CORRUPT) + Draw_FunString (x, y, "!!!"); else { Draw_FunString (x+4, y, "^Ue080^Ue082"); Draw_FunString (x+8, y, "^Ue081"); } break; - case DPF_HAVEAVERSION: - Draw_FunString (x, y, "DEL"); + case DPF_INSTALLED: + if (p->flags & DPF_PURGE || !(p->qhash && (p->flags & DPF_CACHED))) + Draw_FunString (x, y, "DEL"); + else + Draw_FunString (x, y, "REM"); break; - case DPF_WANTTOINSTALL: - Draw_FunString (x, y, "GET"); + case DPF_MARKED: + if (p->flags & DPF_PURGE) + Draw_FunString (x, y, "GET"); + else if (p->flags & (DPF_CACHED|DPF_NATIVE)) + Draw_FunString (x, y, "USE"); + else + Draw_FunString (x, y, "GET"); break; - case DPF_HAVEAVERSION | DPF_WANTTOINSTALL: - Draw_FunString (x+4, y, "^Ue080^Ue082"); - Draw_FunString (x+8, y, "^Ue083"); + case DPF_INSTALLED | DPF_MARKED: + if (p->flags & DPF_PURGE) + Draw_FunString (x, y, "GET"); //purge and reinstall. + else if (p->flags & DPF_CORRUPT) + Draw_FunString (x, y, "?""?""?"); + else + { + Draw_FunString (x+4, y, "^Ue080^Ue082"); + Draw_FunString (x+8, y, "^Ue083"); + } break; } } @@ -711,177 +1475,68 @@ static void MD_Draw (int x, int y, struct menucustom_s *c, struct menu_s *m) } } -//finds the newest version -static package_t *MD_FindPackage(char *packagename) -{ - package_t *p, *r = NULL; - for (p = availablepackages; p; p = p->next) - { - if (!strcmp(p->name, packagename)) - { - if (!r || strcmp(r->version, p->version)>0) - r = p; - } - } - return r; -} -//returns the installed version of a package, if any. -static package_t *MD_HavePackage(char *packagename) -{ - package_t *p; - for (p = availablepackages; p; p = p->next) - { - if (p->flags & DPF_WANTTOINSTALL) - if (!strcmp(p->name, packagename)) - return p; - } - return NULL; -} - -//just flags, doesn't delete -static void MD_RemovePackage(package_t *package) -{ - package_t *o; - struct packagedep_s *dep; - - if (!(package->flags & DPF_WANTTOINSTALL)) - return; //looks like its already deselected. - package->flags &= ~DPF_WANTTOINSTALL; - - //Is this safe? - package->trymirrors = 0; //if its enqueued, cancel that quickly... - if (package->download) - { //if its currently downloading, cancel it. - DL_Close(package->download); - package->download = NULL; - } - - //remove stuff that depends on us - for (o = availablepackages; o; o = o->next) - { - for (dep = package->deps; dep; dep = dep->next) - if (dep->dtype == DEP_REQUIRE) - if (!strcmp(dep->name, package->name)) - MD_RemovePackage(o); - } -} - -//just flags, doesn't install -static void MD_AddPackage(package_t *package) -{ - package_t *o; - struct packagedep_s *dep, *dep2; - qboolean replacing = false; - - if (package->flags & DPF_WANTTOINSTALL) - return; //looks like its already picked. - - //any file-conflicts prevent the package from being installable. - //this is mostly for pak1.pak - for (dep = package->deps; dep; dep = dep->next) - { - if (dep->dtype == DEP_FILECONFLICT) - { - const char *n; - if (*package->gamedir) - n = va("%s/%s", package->gamedir, dep->name); - else - n = dep->name; - if (MD_CheckFile(n, package->fsroot)) - return; - } - } - - package->flags |= DPF_WANTTOINSTALL; - - //first check to see if we're replacing a different version of the same package - for (o = availablepackages; o; o = o->next) - { - if (o == package) - continue; - - if (o->flags & DPF_WANTTOINSTALL) - { - if (!strcmp(o->fullname, package->fullname)) - { //replaces this package - o->flags &= ~DPF_WANTTOINSTALL; - replacing = true; - } - else - { //two packages with the same filename are always mutually incompatible, but with totally separate dependancies etc. - qboolean remove = false; - for (dep = package->deps; dep; dep = dep->next) - { - if (dep->dtype == DEP_FILE) - for (dep2 = o->deps; dep2; dep2 = dep2->next) - { - if (dep2->dtype == DEP_FILE) - if (!strcmp(dep->name, dep2->name)) - { - MD_RemovePackage(o); - remove = true; - break; - } - } - if (remove) - break; - } - //fixme: zip content conflicts - } - } - } - - //if we are replacing an existing one, then dependancies are already settled (only because we don't do version deps) - if (replacing) - return; - - //satisfy our dependancies. - for (dep = package->deps; dep; dep = dep->next) - { - if (dep->dtype == DEP_REQUIRE || dep->dtype == DEP_RECOMMEND) - { - package_t *d = MD_FindPackage(dep->name); - if (d) - MD_AddPackage(d); - } - if (dep->dtype == DEP_CONFLICT) - { - for (;;) - { - package_t *d = MD_HavePackage(dep->name); - if (!d) - break; - MD_RemovePackage(d); - } - } - } - - //remove any packages that conflict with us. - for (o = availablepackages; o; o = o->next) - { - for (dep = package->deps; dep; dep = dep->next) - if (dep->dtype == DEP_CONFLICT) - if (!strcmp(dep->name, package->name)) - MD_RemovePackage(o); - } -} static qboolean MD_Key (struct menucustom_s *c, struct menu_s *m, int key, unsigned int unicode) { package_t *p, *p2; struct packagedep_s *dep, *dep2; + if (c->dint != downloadablessequence) + return false; //probably stale p = c->dptr; - if (p->flags & DPF_HIDDEN) - return false; if (key == K_ENTER || key == K_KP_ENTER || key == K_MOUSE1) { - if (p->flags & DPF_WANTTOINSTALL) - MD_RemovePackage(p); -// else if (p->flags & DPF_UNKNOWNVERSION) -// p->flags &= ~DPF_UNKNOWNVERSION; - else - MD_AddPackage(p); + if (p->alternative && (p->flags & DPF_HIDDEN)) + p = p->alternative; - if (p->flags&DPF_WANTTOINSTALL) + if (p->flags & DPF_INSTALLED) + { + switch (p->flags & (DPF_PURGE|DPF_MARKED)) + { + case DPF_MARKED: + PM_UnmarkPackage(p); //deactivate it + break; + case 0: + p->flags |= DPF_PURGE; //purge + if (p->flags & (DPF_CACHED | DPF_CORRUPT)) + break; + //fall through + case DPF_PURGE: + PM_MarkPackage(p); //reinstall +// if (!(p->flags & DPF_HIDDEN) && !(p->flags & DPF_CACHED)) +// break; + //fall through + case DPF_MARKED|DPF_PURGE: + p->flags &= ~DPF_PURGE; //back to no-change + break; + } + } + else + { + switch (p->flags & (DPF_PURGE|DPF_MARKED)) + { + case 0: + PM_MarkPackage(p); + //now: try to install + break; + case DPF_MARKED: + p->flags |= DPF_PURGE; + //now: re-get despite already having it. + if (p->flags & (DPF_CACHED | DPF_CORRUPT)) + break; //only makes sense if we already have a cached copy that we're not going to use. + //fallthrough + case DPF_MARKED|DPF_PURGE: + PM_UnmarkPackage(p); + //now: delete + if (p->flags & (DPF_CACHED | DPF_CORRUPT)) + break; //only makes sense if we have a cached/corrupt copy of it already + //fallthrough + case DPF_PURGE: + p->flags &= ~DPF_PURGE; + //now: no change + break; + } + } + + if (p->flags&DPF_MARKED) { //any other packages that conflict should be flagged for uninstall now that this one will replace it. for (p2 = availablepackages; p2; p2 = p2->next) @@ -898,7 +1553,7 @@ static qboolean MD_Key (struct menucustom_s *c, struct menu_s *m, int key, unsig continue; if (!strcmp(dep->name, dep2->name)) { - p2->flags &= ~DPF_WANTTOINSTALL; + PM_UnmarkPackage(p2); break; } } @@ -913,8 +1568,7 @@ static qboolean MD_Key (struct menucustom_s *c, struct menu_s *m, int key, unsig return false; } -#ifdef HAVEAUTOUPDATE -static void MD_EngineUpdate_Draw (int x, int y, struct menucustom_s *c, struct menu_s *m) +static void MD_AutoUpdate_Draw (int x, int y, struct menucustom_s *c, struct menu_s *m) { char *settings[] = { @@ -924,36 +1578,32 @@ static void MD_EngineUpdate_Draw (int x, int y, struct menucustom_s *c, struct m "Stable Updates", "Unsable Updates" }; - int setting = autoupdatesetting; char *text; - if (setting == -1) - { - setting = Sys_GetAutoUpdateSetting(); + int setting = Sys_GetAutoUpdateSetting(); + if (setting == UPD_UNSUPPORTED) + text = va("Auto Update: %s", settings[autoupdatesetting+1]); + else if (autoupdatesetting == UPD_UNSUPPORTED) text = va("Auto Update: %s", settings[setting+1]); - } else - text = va("Auto Update: %s (unsaved)", settings[setting+1]); + text = va("Auto Update: %s (unsaved)", settings[autoupdatesetting+1]); if (&m->selecteditem->common == &c->common) Draw_AltFunString (x+4, y, text); else Draw_FunString (x+4, y, text); } -static qboolean MD_EngineUpdate_Key (struct menucustom_s *c, struct menu_s *m, int key, unsigned int unicode) +static qboolean MD_AutoUpdate_Key (struct menucustom_s *c, struct menu_s *m, int key, unsigned int unicode) { if (key == K_ENTER || key == K_KP_ENTER || key == K_MOUSE1) { - if (autoupdatesetting == -1) - autoupdatesetting = Sys_GetAutoUpdateSetting(); - if (autoupdatesetting != -1) - { - autoupdatesetting+=1; - if (autoupdatesetting >= 4) - autoupdatesetting = 0; - } + if (autoupdatesetting == UPD_UNSUPPORTED) + autoupdatesetting = min(0, Sys_GetAutoUpdateSetting()); + autoupdatesetting+=1; + if (autoupdatesetting > UPD_TESTING) + autoupdatesetting = (Sys_GetAutoUpdateSetting() == UPD_UNSUPPORTED)?1:0; + PM_UpdatePackageList(true, 2); } return false; } -#endif qboolean MD_PopMenu (union menuoption_s *mo,struct menu_s *m,int key) { @@ -970,17 +1620,26 @@ vfsfile_t *FS_GZ_DecompressWriteFilter(vfsfile_t *outfile, qboolean autoclosefil static char *MD_GetTempName(package_t *p) { - struct packagedep_s *dep; + struct packagedep_s *dep, *fdep; char *destname, *t, *ts; - //always favour a file so that we can rename safely without needing a copy. - for (dep = p->deps; dep; dep = dep->next) + //always favour the file so that we can rename safely without needing a copy. + for (dep = p->deps, fdep = NULL; dep; dep = dep->next) { if (dep->dtype != DEP_FILE) continue; + if (fdep) + { + fdep = NULL; + break; + } + fdep = dep; + } + if (fdep) + { if (*p->gamedir) - destname = va("%s/%s.tmp", p->gamedir, dep->name); + destname = va("%s/%s.tmp", p->gamedir, fdep->name); else - destname = va("%s.tmp", dep->name); + destname = va("%s.tmp", fdep->name); return Z_StrDup(destname); } ts = Z_StrDup(p->name); @@ -1050,9 +1709,30 @@ static void MD_StartADownload(void) if (!mirror) { //erk... p->trymirrors = 0; + + for (i = 0; i < countof(p->mirror); i++) + if (p->mirror[i]) + break; + if (i == countof(p->mirror)) + { //this appears to be a meta package with no download + //just directly install it. + p->flags &= ~(DPF_NATIVE|DPF_CACHED|DPF_CORRUPT); + p->flags |= DPF_INSTALLED; + PM_WriteInstalledPackages(); + } continue; } - + + if (p->qhash && (p->flags & DPF_CACHED)) + { //its in our cache directory, so lets just use that + p->trymirrors = 0; + p->flags |= DPF_INSTALLED; + PM_WriteInstalledPackages(); + FS_ReloadPackFiles(); + continue; + } + + temp = MD_GetTempName(p); //FIXME: we should lock in the temp path, in case the user foolishly tries to change gamedirs. @@ -1099,14 +1779,12 @@ static void MD_StartADownload(void) p->download->file = tmpfile; p->download->user_ctx = temp; -#ifdef MULTITHREAD DL_CreateThread(p->download, NULL, NULL); -#endif } else { Con_Printf("Unable to download %s\n", p->fullname); - p->flags &= ~DPF_WANTTOINSTALL; //can't do it. + p->flags &= ~DPF_MARKED; //can't do it. if (tmpfile) VFS_CLOSE(tmpfile); FS_Remove(temp, p->fsroot); @@ -1121,13 +1799,13 @@ static qboolean MD_ApplyDownloads (union menuoption_s *mo,struct menu_s *m,int k { if (key == K_ENTER || key == K_KP_ENTER || key == K_MOUSE1) { - package_t *p, *o, **link; + package_t *p, **link; #ifdef HAVEAUTOUPDATE - if (autoupdatesetting != -1) + if (autoupdatesetting != UPD_UNSUPPORTED) { Sys_SetAutoUpdateSetting(autoupdatesetting); - autoupdatesetting = -1; + autoupdatesetting = UPD_UNSUPPORTED; } #endif @@ -1135,7 +1813,7 @@ static qboolean MD_ApplyDownloads (union menuoption_s *mo,struct menu_s *m,int k for (link = &availablepackages; *link ; ) { p = *link; - if (!(p->flags&DPF_WANTTOINSTALL) && (p->flags&DPF_HAVEAVERSION)) + if ((p->flags & DPF_PURGE) || (!(p->flags&DPF_MARKED) && (p->flags&DPF_INSTALLED))) { //if we don't want it but we have it anyway: qboolean reloadpacks = false; struct packagedep_s *dep; @@ -1154,47 +1832,47 @@ static qboolean MD_ApplyDownloads (union menuoption_s *mo,struct menu_s *m,int k } } if (*p->gamedir) - FS_Remove(va("%s/%s", p->gamedir, dep->name), p->fsroot); + { + char *f = va("%s/%s", p->gamedir, dep->name); + char temp[MAX_OSPATH]; + if (p->qhash && FS_GenCachedPakName(f, p->qhash, temp, sizeof(temp)) && PM_CheckFile(temp, p->fsroot)) + { + if (p->flags & DPF_PURGE) + FS_Remove(temp, p->fsroot); + } + else + FS_Remove(va("%s/%s", p->gamedir, dep->name), p->fsroot); + } else FS_Remove(dep->name, p->fsroot); } } + + p->flags &= ~(DPF_NATIVE|DPF_CACHED|DPF_CORRUPT|DPF_PURGE|DPF_INSTALLED); + PM_ValidatePackage(p); + PM_WriteInstalledPackages(); + if (reloadpacks) FS_ReloadPackFiles(); - p->flags &= ~DPF_UNKNOWNVERSION; - p->flags &= ~DPF_HAVEAVERSION; - - //make sure it actually got wiped. if there's still a file there then something went screwy. - //we don't reliably know if the remove actually succeeded or failed. - for (dep = p->deps; dep; dep = dep->next) - { - if (dep->dtype == DEP_FILE) - { - const char *n; - if (*p->gamedir) - n = va("%s/%s", p->gamedir, dep->name); - else - n = dep->name; - if (MD_CheckFile(n, p->fsroot)) - { - p->flags |= DPF_UNKNOWNVERSION; - break; - } - } - } - WriteInstalledPackages(); - if (p->flags & DPF_FORGETONUNINSTALL) { - *link = p->next; - - for (o = availablepackages; o; o = o->next) - { - if (o->override == p) - o->override = NULL; + if (p->alternative) + { //replace it with its alternative package + *p->link = p->alternative; + p->alternative->alternative = p->alternative->next; + if (p->alternative->alternative) + p->alternative->alternative->link = &p->alternative->alternative; + p->alternative->next = p->next; + } + else + { //just remove it from the list. + *p->link = p->next; + if (p->next) + p->next->link = p->link; } +//FIXME: the menu(s) hold references to packages, so its not safe to purge them p->flags |= DPF_HIDDEN; // BZ_Free(p); @@ -1208,7 +1886,7 @@ static qboolean MD_ApplyDownloads (union menuoption_s *mo,struct menu_s *m,int k //and flag any new/updated ones for a download for (p = availablepackages; p ; p=p->next) { - if ((p->flags&DPF_WANTTOINSTALL) && !(p->flags&DPF_HAVEAVERSION) && !p->download) + if ((p->flags&DPF_MARKED) && !(p->flags&DPF_INSTALLED) && !p->download) p->trymirrors = ~0u; } MD_StartADownload(); //and try to do those downloads. @@ -1217,6 +1895,32 @@ static qboolean MD_ApplyDownloads (union menuoption_s *mo,struct menu_s *m,int k return false; } +static qboolean MD_MarkUpdatesButton (union menuoption_s *mo,struct menu_s *m,int key) +{ + if (key == K_ENTER || key == K_KP_ENTER || key == K_MOUSE1) + { + PM_MarkUpdates(); + return true; + } + return false; +} +static qboolean MD_RevertUpdates (union menuoption_s *mo,struct menu_s *m,int key) +{ + if (key == K_ENTER || key == K_KP_ENTER || key == K_MOUSE1) + { + package_t *p; + for (p = availablepackages; p; p = p->next) + { + if (p->flags & DPF_INSTALLED) + p->flags |= DPF_MARKED; + else + p->flags &= ~DPF_MARKED; + } + return true; + } + return false; +} + void M_AddItemsToDownloadMenu(menu_t *m) { char path[MAX_QPATH]; @@ -1236,26 +1940,30 @@ void M_AddItemsToDownloadMenu(menu_t *m) y+=8; MC_AddCommand(m, 0, 170, y, "Back", MD_PopMenu); y+=8; -#ifdef HAVEAUTOUPDATE + if (!prefixlen) + { + MC_AddCommand(m, 0, 170, y, "Mark Updates", MD_MarkUpdatesButton); + y+=8; + + MC_AddCommand(m, 0, 170, y, "Revert Updates", MD_RevertUpdates); + y+=8; + } if (!prefixlen) { c = MC_AddCustom(m, 0, y, p, 0); - c->draw = MD_EngineUpdate_Draw; - c->key = MD_EngineUpdate_Key; + c->draw = MD_AutoUpdate_Draw; + c->key = MD_AutoUpdate_Key; c->common.width = 320; c->common.height = 8; y += 8; } -#endif y+=4; //small gap for (p = availablepackages; p; p = p->next) { if (strncmp(p->fullname, info->pathprefix, prefixlen)) continue; - if ((p->flags & DPF_HIDDEN) && !(p->flags & DPF_HAVEAVERSION)) - continue; - if (p->override) + if ((p->flags & DPF_HIDDEN) && (p->arch || !(p->flags & DPF_INSTALLED))) continue; slash = strchr(p->fullname+prefixlen, '/'); @@ -1281,11 +1989,12 @@ void M_AddItemsToDownloadMenu(menu_t *m) } else { - c = MC_AddCustom(m, 0, y, p, 0); + c = MC_AddCustom(m, 0, y, p, downloadablessequence); c->draw = MD_Draw; c->key = MD_Key; c->common.width = 320; c->common.height = 8; + c->common.tooltip = p->description; y += 8; if (!m->selecteditem) @@ -1294,56 +2003,66 @@ void M_AddItemsToDownloadMenu(menu_t *m) } } +#include "shader.h" void M_Download_UpdateStatus(struct menu_s *m) { - struct dl_download *dl; dlmenu_t *info = m->data; int i; - while (!cls.download && (info->parsedsourcenum==-1 || info->parsedsourcenum < numdownloadablelists)) - { //done downloading - info->parsedsourcenum++; - - if (info->parsedsourcenum < numdownloadablelists) - { - if (!downloadablelistreceived[info->parsedsourcenum]) - { - dl = HTTP_CL_Get(va("%s"DOWNLOADABLESARGS, downloadablelist[info->parsedsourcenum]), NULL, M_DL_Notification); - if (dl) - { - dl->user_num = info->parsedsourcenum; - - dl->file = VFSPIPE_Open(); - dl->isquery = true; - } - else - Con_Printf("Could not contact server\n"); - return; - } - } - } - for (i = 0; i < numdownloadablelists; i++) + if (info->downloadablessequence != downloadablessequence) { - if (!downloadablelistreceived[i]) + while(m->options) { -// Draw_String(x+8, y+8, "Waiting for package list"); - return; + menuoption_t *op = m->options; + m->options = op->common.next; + if (op->common.iszone) + Z_Free(op); } + m->cursoritem = m->selecteditem = NULL; + + info->populated = false; + MC_AddWhiteText(m, 24, 170, 8, "Downloads", false); + MC_AddWhiteText(m, 16, 170, 24, "^Ue01d^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01f", false); + + //FIXME: should probably reselect the previous selected item. lets just assume everyone uses a mouse... } if (!info->populated) { + for (i = 0; i < numdownloadablelists; i++) + { + if (!downloadablelist[i].received) + { + Draw_FunStringWidth(0, vid.height - 8, "Querying for package list", vid.width, 2, false); + return; + } + } + info->populated = true; M_AddItemsToDownloadMenu(m); } + + if (m->selecteditem && m->selecteditem->common.type == mt_custom && m->selecteditem->custom.dptr) + { + package_t *p = m->selecteditem->custom.dptr; + if (p->previewimage) + { + shader_t *sh = R_RegisterPic(p->previewimage); + if (R_GetShaderSizes(sh, NULL, NULL, false) > 0) + R2D_Image(0, 0, vid.width, vid.height, 0, 0, 1, 1, sh); + } + } } -#include "fs.h" static int QDECL MD_ExtractFiles(const char *fname, qofs_t fsize, time_t mtime, void *parm, searchpathfuncs_t *spath) { //this is gonna suck. threading would help, but gah. package_t *p = parm; flocation_t loc; - if (spath->FindFile(spath, &loc, fname, NULL) && loc.len < 0x80000000u) + if (fname[strlen(fname)-1] == '/') + { //directory. + + } + else if (spath->FindFile(spath, &loc, fname, NULL) && loc.len < 0x80000000u) { char *f = malloc(loc.len); const char *n; @@ -1354,11 +2073,12 @@ static int QDECL MD_ExtractFiles(const char *fname, qofs_t fsize, time_t mtime, n = va("%s/%s", p->gamedir, fname); else n = fname; - FS_WriteFile(n, f, loc.len, p->fsroot); + if (FS_WriteFile(n, f, loc.len, p->fsroot)) + p->flags |= DPF_NATIVE|DPF_INSTALLED; free(f); //keep track of the installed files, so we can delete them properly after. - MD_AddDep(p, DEP_FILE, fname); + PM_AddDep(p, DEP_FILE, fname); } } return 1; @@ -1406,19 +2126,29 @@ static void Menu_Download_Got(struct dl_download *dl) searchpathfuncs_t *archive = FSZIP_LoadArchive(f, tempname, NULL); if (archive) { + p->flags &= ~(DPF_NATIVE|DPF_CACHED|DPF_CORRUPT|DPF_INSTALLED); archive->EnumerateFiles(archive, "*", MD_ExtractFiles, p); + archive->EnumerateFiles(archive, "*/*", MD_ExtractFiles, p); + archive->EnumerateFiles(archive, "*/*/*", MD_ExtractFiles, p); + archive->EnumerateFiles(archive, "*/*/*/*", MD_ExtractFiles, p); + archive->EnumerateFiles(archive, "*/*/*/*/*", MD_ExtractFiles, p); + archive->EnumerateFiles(archive, "*/*/*/*/*/*", MD_ExtractFiles, p); + archive->EnumerateFiles(archive, "*/*/*/*/*/*/*", MD_ExtractFiles, p); + archive->EnumerateFiles(archive, "*/*/*/*/*/*/*/*", MD_ExtractFiles, p); + archive->EnumerateFiles(archive, "*/*/*/*/*/*/*/*/*", MD_ExtractFiles, p); archive->ClosePath(archive); - p->flags |= DPF_HAVEAVERSION; - WriteInstalledPackages(); + PM_WriteInstalledPackages(); - if (!stricmp(ext, "pak") || !stricmp(ext, "pk3")) - FS_ReloadPackFiles(); +// if (!stricmp(ext, "pak") || !stricmp(ext, "pk3")) +// FS_ReloadPackFiles(); } else VFS_CLOSE(f); } - FS_Remove (tempname, FS_GAMEONLY); + PM_ValidatePackage(p); + + FS_Remove (tempname, p->fsroot); Z_Free(tempname); MD_StartADownload(); return; @@ -1427,37 +2157,54 @@ static void Menu_Download_Got(struct dl_download *dl) { for (dep = p->deps; dep; dep = dep->next) { + unsigned int nfl; if (dep->dtype != DEP_FILE) continue; COM_FileExtension(dep->name, ext, sizeof(ext)); if (!stricmp(ext, "pak") || !stricmp(ext, "pk3")) FS_UnloadPackFiles(); //we reload them after + if ((!stricmp(ext, "dll") || !stricmp(ext, "so")) && !Q_strncmp(dep->name, "fteplug_", 8)) + Cmd_ExecuteString(va("plug_close %s\n", dep->name), RESTRICT_LOCAL); //try to purge plugins so there's no files left open + nfl = DPF_NATIVE; if (*p->gamedir) + { + char temp[MAX_OSPATH]; destname = va("%s/%s", p->gamedir, dep->name); + if (p->qhash && FS_GenCachedPakName(destname, p->qhash, temp, sizeof(temp))) + { + nfl = DPF_CACHED; + destname = va("%s", temp); + } + } else destname = dep->name; + nfl |= DPF_INSTALLED | (p->flags & ~(DPF_CACHED|DPF_NATIVE|DPF_CORRUPT)); + FS_CreatePath(destname, p->fsroot); if (FS_Remove(destname, p->fsroot)) ; if (!FS_Rename2(tempname, destname, p->fsroot, p->fsroot)) { + //error! Con_Printf("Couldn't rename %s to %s. Removed instead.\n", tempname, destname); FS_Remove (tempname, p->fsroot); - Z_Free(tempname); - MD_StartADownload(); - return; } - Z_Free(tempname); - Con_Printf("Downloaded %s (to %s)\n", p->name, destname); + else + { //success! + Con_Printf("Downloaded %s (to %s)\n", p->name, destname); + p->flags = nfl; + PM_WriteInstalledPackages(); + } - p->flags |= DPF_HAVEAVERSION; - - WriteInstalledPackages(); + PM_ValidatePackage(p); if (!stricmp(ext, "pak") || !stricmp(ext, "pk3")) FS_ReloadPackFiles(); + if ((!stricmp(ext, "dll") || !stricmp(ext, "so")) && !Q_strncmp(dep->name, "fteplug_", 8)) + Cmd_ExecuteString(va("plug_load %s\n", dep->name), RESTRICT_LOCAL); + Z_Free(tempname); MD_StartADownload(); return; } @@ -1474,8 +2221,6 @@ static void Menu_Download_Got(struct dl_download *dl) void Menu_DownloadStuff_f (void) { - static qboolean loadedinstalled; - int i; menu_t *menu; dlmenu_t *info; @@ -1486,40 +2231,40 @@ void Menu_DownloadStuff_f (void) info = menu->data; menu->predraw = M_Download_UpdateStatus; -/* - menu->selecteditem = (menuoption_t *)(info->list = MC_AddCustom(menu, 0, 32, NULL)); - info->list->draw = M_Download_Draw; - info->list->key = M_Download_Key; -*/ - info->parsedsourcenum = -1; + info->downloadablessequence = downloadablessequence; - if (*fs_downloads_url.string) - M_DL_AddSubList(fs_downloads_url.string, ""); Q_strncpyz(info->pathprefix, Cmd_Argv(1), sizeof(info->pathprefix)); - if (!*info->pathprefix) - { - for (i = 0; i < numdownloadablelists; i++) - downloadablelistreceived[i] = 0; - } + if (!*info->pathprefix || !loadedinstalled) + PM_UpdatePackageList(false, true); MC_AddWhiteText(menu, 24, 170, 8, "Downloads", false); MC_AddWhiteText(menu, 16, 170, 24, "^Ue01d^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01e^Ue01f", false); - - if (!loadedinstalled) - { - vfsfile_t *f = FS_OpenVFS(INSTALLEDFILES, "rb", FS_ROOT); - loadedinstalled = true; - if (f) - { - ConcatPackageLists(BuildPackageList(f, DPF_FORGETONUNINSTALL|DPF_HAVEAVERSION|DPF_WANTTOINSTALL, NULL, "")); - VFS_CLOSE(f); - } - } } + +//should only be called AFTER the filesystem etc is inited. +void Menu_Download_Update(void) +{ + if (Sys_GetAutoUpdateSetting() == UPD_OFF || Sys_GetAutoUpdateSetting() == UPD_REVERT) + return; + + PM_UpdatePackageList(true, 2); +} + +#endif + #else void Menu_DownloadStuff_f (void) { Con_Printf("Download menu not implemented in this build\n"); } +void Menu_Download_Update(void) +{ +} +void PM_LoadPackages(searchpath_t **oldpaths, const char *parent_pure, const char *parent_logical, searchpath_t *search, unsigned int loadstuff, int minpri, int maxpri) +{ +} +void PM_Shutdown(void) +{ +} #endif diff --git a/engine/client/m_items.c b/engine/client/m_items.c index f77c3440..2d60a8c8 100644 --- a/engine/client/m_items.c +++ b/engine/client/m_items.c @@ -267,14 +267,10 @@ int maxdots; int mindot; int dotofs; -static void MenuTooltipSplit(menu_t *menu, const char *text) +static void MenuTooltipChange(menu_t *menu, const char *text) { - char buf[1024]; - char *c, *space; - int lines, lnsize, txsize; - int lnmax; + unsigned int MAX_CHARS=1024; menutooltip_t *mtt; - if (menu->tooltip) { Z_Free(menu->tooltip); @@ -284,85 +280,9 @@ static void MenuTooltipSplit(menu_t *menu, const char *text) if (!text || !text[0] || vid.width < 320 || vid.height < 200) return; - // calc a line maximum, use a third of the screen or 30 characters, whichever is bigger - lnmax = (vid.width / 24) - 2; - if (lnmax < 30) - lnmax = 30; - // word wrap - lines = 1; - lnsize = txsize = 0; - space = NULL; - for (c = buf; *text && txsize < sizeof(buf) - 1; text++) - { - if (lnsize >= lnmax) - { - if (space) - { - lnsize = (c - space) - 1; - *space = '\n'; - space = NULL; - } - else - { - lnsize = 0; - *c = '\n'; - c++; - txsize++; - if (txsize >= sizeof(buf) - 1) - break; - } - lines++; - } - - *c = *text; - switch (*c) - { - case '\n': - lines++; - lnsize = 0; - space = NULL; - break; - case ' ': - space = c; - break; - } - c++; - txsize++; - lnsize++; - } - // remove stray newlines at end and terminate string - while (txsize > 0 && buf[txsize - 1] == '\n') - { - lines--; - txsize--; - } - buf[txsize] = '\0'; - // allocate new tooltip structure, copy text to structure - mtt = (menutooltip_t *)Z_Malloc(sizeof(menutooltip_t) + sizeof(char *)*lines + txsize + 1); - mtt->lines = (char **)(mtt + 1); - mtt->rows = lines; - Q_memcpy(mtt->lines + lines, buf, txsize + 1); - mtt->lines[0] = (char *)(mtt->lines + lines); - - // rescan text, get max column length, convert \n to \0 - lines = lnmax = txsize = 0; - for (c = mtt->lines[0]; *c; c++) - { - if (*c == '\n') - { - if (lnmax < txsize) - lnmax = txsize; - txsize = 0; - *c = '\0'; - mtt->lines[++lines] = c + 1; - } - else - txsize++; - } - if (lnmax < txsize) - lnmax = txsize; - mtt->columns = lnmax; + mtt = (menutooltip_t *)Z_Malloc(sizeof(menutooltip_t) + sizeof(conchar_t)*MAX_CHARS); + mtt->end = COM_ParseFunString(CON_WHITEMASK, text, mtt->text, sizeof(conchar_t)*MAX_CHARS, false); menu->tooltip = mtt; } @@ -456,7 +376,7 @@ static void M_CheckMouseMove(void) menu->selecteditem = option; menu->tooltiptime = realtime + 1; - MenuTooltipSplit(menu, menu->selecteditem->common.tooltip); + MenuTooltipChange(menu, menu->selecteditem->common.tooltip); } if (menu->cursoritem) menu->cursoritem->common.posy = menu->selecteditem->common.posy; @@ -711,11 +631,28 @@ static void MenuDraw(menu_t *menu) if (omousex > menu->xpos+option->common.posx && omousex < menu->xpos+option->common.posx+option->common.width) if (omousey > menu->ypos+option->common.posy && omousey < menu->ypos+option->common.posy+option->common.height) { - int x = omousex; + int x = omousex+8; int y = omousey; - int w = (menu->tooltip->columns + 3) * 8; - int h = (menu->tooltip->rows + 2) * 8; + int w; + int h; int l, lines; + conchar_t *line_start[16]; + conchar_t *line_end[countof(line_start)]; + + //figure out the line breaks + Font_BeginString(font_default, 0, 0, &l, &l); + lines = Font_LineBreaks(menu->tooltip->text, menu->tooltip->end, min(vid.pixelwidth/2, 30*8*vid.pixelwidth/vid.width), countof(line_start), line_start, line_end); + Font_EndString(font_default); + + //figure out how wide that makes the tip + w = 16; + h = (lines+2)*8; + for (l = 0; l < lines; l++) + { + int lw = 16+Font_LineWidth(line_start[l], line_end[l])*vid.width/vid.pixelwidth; + if (w < lw) + w = lw; + } // keep the tooltip within view if (x + w >= vid.width) @@ -723,16 +660,19 @@ static void MenuDraw(menu_t *menu) if (y + h >= vid.height) y -= h; - // draw tooltip - Draw_TextBox(x, y, menu->tooltip->columns, menu->tooltip->rows); - lines = menu->tooltip->rows; + // draw the background + Draw_TextBox(x, y, (w-16)/8, lines); x += 8; y += 8; + + //draw the text + Font_BeginString(font_default, x, y, &x, &y); for (l = 0; l < lines; l++) { - Draw_FunString(x, y, menu->tooltip->lines[l]); - y += 8; + Font_LineDraw(x, y, line_start[l], line_end[l]); + y += Font_CharHeight(); } + Font_EndString(font_default); } } diff --git a/engine/client/m_options.c b/engine/client/m_options.c index bc9ca0d6..93f9f930 100644 --- a/engine/client/m_options.c +++ b/engine/client/m_options.c @@ -2883,7 +2883,7 @@ static void M_ModelViewerDraw(int x, int y, struct menucustom_s *c, struct menu_ // ent.fatness = sin(realtime)*5; ent.playerindex = -1; ent.skinnum = mods->skingroup; - ent.shaderTime = realtime; + ent.shaderTime = 0;//realtime; ent.framestate.g[FS_REG].lerpweight[0] = 1; ent.framestate.g[FS_REG].frame[0] = mods->framegroup; ent.framestate.g[FS_REG].frametime[0] = realtime - mods->framechangetime; @@ -3112,7 +3112,10 @@ static void Mods_Draw(int x, int y, struct menucustom_s *c, struct menu_s *m) mods->y = y; if (!mods->nummanifests) - Draw_FunString(x, y, "No games or mods known"); + { + Draw_FunString(x, y+0, "No games or mods known"); + Draw_FunString(x, y+8, "Consider using -basedir $PATHTOGAME on the commandline"); + } for (i = 0; y+8 <= ym && i < mods->nummanifests; y+=8, i++) { diff --git a/engine/client/menu.h b/engine/client/menu.h index 9edb799e..1f299a14 100644 --- a/engine/client/menu.h +++ b/engine/client/menu.h @@ -254,9 +254,8 @@ typedef union menuoption_s { } menuoption_t; typedef struct menutooltip_s { - char **lines; - int rows; - int columns; + conchar_t *end; + conchar_t text[1]; } menutooltip_t; typedef struct menuresel_s //THIS STRUCT MUST BE STATICALLY ALLOCATED. diff --git a/engine/client/merged.h b/engine/client/merged.h index 2180c170..5be6db7d 100644 --- a/engine/client/merged.h +++ b/engine/client/merged.h @@ -1,6 +1,8 @@ #ifdef VKQUAKE #if defined(__LP64__) || defined(_WIN64) #define VulkanWasDesignedByARetard void* +#elif defined(_MSC_VER) && _MSC_VER < 1300 +#define VulkanWasDesignedByARetard __int64 #else #define VulkanWasDesignedByARetard long long #endif @@ -375,15 +377,15 @@ typedef struct texnums_s { //not all modes accept meshes - STENCIL(intentional) and DEPTHONLY(not implemented) typedef enum backendmode_e { - BEM_STANDARD, //regular mode to draw surfaces akin to q3 (aka: legacy mode). lightmaps+delux+ambient - BEM_DEPTHONLY, //just a quick depth pass. textures used only for alpha test (shadowmaps). - BEM_WIREFRAME, //for debugging or something - BEM_STENCIL, //used for drawing shadow volumes to the stencil buffer. - BEM_DEPTHDARK, //a quick depth pass. textures used only for alpha test. additive textures still shown as normal. - BEM_CREPUSCULAR, //sky is special, everything else completely black - BEM_DEPTHNORM, //all opaque stuff drawn using 'depthnorm' shader - BEM_FOG, //drawing a fog volume - BEM_LIGHT, //we have a valid light + BEM_STANDARD, //regular mode to draw surfaces akin to q3 (aka: legacy mode). lightmaps+delux+ambient + BEM_DEPTHONLY, //just a quick depth pass. textures used only for alpha test (shadowmaps). + BEM_WIREFRAME, //for debugging or something + BEM_STENCIL, //used for drawing shadow volumes to the stencil buffer. + BEM_DEPTHDARK, //a quick depth pass. textures used only for alpha test. additive textures still shown as normal. + BEM_CREPUSCULAR, //sky is special, everything else completely black + BEM_DEPTHNORM, //all opaque stuff drawn using 'depthnorm' shader + BEM_FOG, //drawing a fog volume + BEM_LIGHT, //we have a valid light } backendmode_t; typedef struct rendererinfo_s { @@ -395,24 +397,24 @@ typedef struct rendererinfo_s { void (*Draw_Init) (void); void (*Draw_Shutdown) (void); - void (*IMG_UpdateFiltering) (image_t *imagelist, int filtermip[3], int filterpic[3], int mipcap[2], float anis); + void (*IMG_UpdateFiltering) (image_t *imagelist, int filtermip[3], int filterpic[3], int mipcap[2], float anis); qboolean (*IMG_LoadTextureMips) (texid_t tex, struct pendingtextureinfo *mips); - void (*IMG_DestroyTexture) (texid_t tex); + void (*IMG_DestroyTexture) (texid_t tex); - void (*R_Init) (void); //FIXME - merge implementations - void (*R_DeInit) (void); //FIXME - merge implementations - void (*R_RenderView) (void); // must set r_refdef first + void (*R_Init) (void); //FIXME - merge implementations + void (*R_DeInit) (void); //FIXME - merge implementations + void (*R_RenderView) (void); // must set r_refdef first qboolean (*VID_Init) (rendererstate_t *info, unsigned char *palette); void (*VID_DeInit) (void); - void (*VID_SwapBuffers) (void); //force a buffer swap, regardless of what's displayed. + void (*VID_SwapBuffers) (void); //force a buffer swap, regardless of what's displayed. qboolean (*VID_ApplyGammaRamps) (unsigned int size, unsigned short *ramps); - void *(*VID_CreateCursor) (const char *filename, float hotx, float hoty, float scale); //may be null, stub returns null + void *(*VID_CreateCursor) (const char *filename, float hotx, float hoty, float scale); //may be null, stub returns null qboolean (*VID_SetCursor) (void *cursor); //may be null - void (*VID_DestroyCursor) (void *cursor); //may be null + void (*VID_DestroyCursor) (void *cursor); //may be null - void (*VID_SetWindowCaption) (const char *msg); + void (*VID_SetWindowCaption) (const char *msg); char *(*VID_GetRGBInfo) (int *truevidwidth, int *truevidheight, enum uploadfmt *fmt); qboolean (*SCR_UpdateScreen) (void); @@ -431,22 +433,23 @@ typedef struct rendererinfo_s { //called at init, force the display to the right defaults etc void (*BE_Init)(void); //Generates an optimised VBO, one for each texture on the map - void (*BE_GenBrushModelVBO)(struct model_s *mod); + void (*BE_GenBrushModelVBO)(struct model_s *mod); //Destroys the given vbo - void (*BE_ClearVBO)(struct vbo_s *vbo); + void (*BE_ClearVBO)(struct vbo_s *vbo); //Uploads all modified lightmaps - void (*BE_UploadAllLightmaps)(void); - void (*BE_SelectEntity)(struct entity_s *ent); + void (*BE_UploadAllLightmaps)(void); + void (*BE_SelectEntity)(struct entity_s *ent); qboolean (*BE_SelectDLight)(struct dlight_s *dl, vec3_t colour, vec3_t axis[3], unsigned int lmode); - void (*BE_Scissor)(srect_t *rect); + void (*BE_Scissor)(srect_t *rect); /*check to see if an ent should be drawn for the selected light*/ qboolean (*BE_LightCullModel)(vec3_t org, struct model_s *model); - void (*BE_VBO_Begin)(vbobctx_t *ctx, size_t maxsize); - void (*BE_VBO_Data)(vbobctx_t *ctx, void *data, size_t size, vboarray_t *varray); - void (*BE_VBO_Finish)(vbobctx_t *ctx, void *edata, size_t esize, vboarray_t *earray, void **vbomem, void **ebomem); - void (*BE_VBO_Destroy)(vboarray_t *vearray, void *mem); - void (*BE_RenderToTextureUpdate2d)(qboolean destchanged); - char *alignment; + void (*BE_VBO_Begin)(vbobctx_t *ctx, size_t maxsize); + void (*BE_VBO_Data)(vbobctx_t *ctx, void *data, size_t size, vboarray_t *varray); + void (*BE_VBO_Finish)(vbobctx_t *ctx, void *edata, size_t esize, vboarray_t *earray, void **vbomem, void **ebomem); + void (*BE_VBO_Destroy)(vboarray_t *vearray, void *mem); + void (*BE_RenderToTextureUpdate2d)(qboolean destchanged); + + char *alignment; //just to make sure that added functions cause compile warnings. } rendererinfo_t; #define rf currentrendererstate.renderer diff --git a/engine/client/net_master.c b/engine/client/net_master.c index a6e53115..4a70cf10 100644 --- a/engine/client/net_master.c +++ b/engine/client/net_master.c @@ -2324,7 +2324,7 @@ void MasterInfo_WriteServers(void) mf = FS_OpenVFS("masters.txt", "wt", FS_ROOT); if (!mf) { - Con_Printf("Couldn't write masters.txt"); + Con_Printf(CON_ERROR "Couldn't write masters.txt"); return; } diff --git a/engine/client/pr_csqc.c b/engine/client/pr_csqc.c index e502a8e3..6d34a0d3 100644 --- a/engine/client/pr_csqc.c +++ b/engine/client/pr_csqc.c @@ -4055,6 +4055,29 @@ static void QCBUILTIN PF_cl_te_explosion2 (pubprogfuncs_t *prinst, struct global } S_StartSound (0, 0, cl_sfx_r_exp3, pos, NULL, 1, 1, 0, 0, 0); } + +static void QCBUILTIN PF_cl_te_flamejet (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) +{ + vec3_t pos, vel; + int count; + + // origin + pos[0] = MSG_ReadCoord (); + pos[1] = MSG_ReadCoord (); + pos[2] = MSG_ReadCoord (); + + // velocity + vel[0] = MSG_ReadCoord (); + vel[1] = MSG_ReadCoord (); + vel[2] = MSG_ReadCoord (); + + // count + count = MSG_ReadByte (); + + if (P_RunParticleEffectType(pos, vel, count, P_FindParticleType("TE_FLAMEJET"))) + P_RunParticleEffect (pos, vel, 232, count); +} + static void QCBUILTIN PF_cl_te_lightning1 (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) { csqcedict_t *ent = (csqcedict_t*)G_EDICT(prinst, OFS_PARM0); @@ -5490,6 +5513,8 @@ static struct { {"fputs", PF_fputs, 113}, // #113 void(float fnum, string str) fputs (FRIK_FILE) {"fread", PF_fread, 0}, {"fwrite", PF_fwrite, 0}, + {"fseek", PF_fseek, 0}, + {"fsize", PF_fsize, 0}, {"strlen", PF_strlen, 114}, // #114 float(string str) strlen (FRIK_FILE) {"strcat", PF_strcat, 115}, // #115 string(string str1, string str2, ...) strcat (FRIK_FILE) @@ -5839,7 +5864,7 @@ static struct { // {"WriteUnterminatedString",PF_WriteString2, 456}, //writestring but without the null terminator. makes things a little nicer. //DP_TE_FLAMEJET -// {"te_flamejet", PF_te_flamejet, 457}, // #457 void(vector org, vector vel, float howmany) te_flamejet + {"te_flamejet", PF_cl_te_flamejet, 457}, // #457 void(vector org, vector vel, float howmany) te_flamejet //no 458 documented. @@ -7292,7 +7317,7 @@ qboolean CSQC_KeyPress(int key, int unicode, qboolean down, unsigned int devid) G_FLOAT(OFS_PARM3) = devid; //small sanity check, so things don't break too much if things get big. - if (devid < 0 || (unsigned)devid >= sizeof(csqckeysdown[0])*8) + if ((unsigned)devid >= sizeof(csqckeysdown[0])*8) devid = sizeof(csqckeysdown[0])*8-1; if (key < 0 || key >= K_MAX) key = 0; //panic. everyone panic. diff --git a/engine/client/pr_menu.c b/engine/client/pr_menu.c index b1b43b7a..b9e5cb3a 100644 --- a/engine/client/pr_menu.c +++ b/engine/client/pr_menu.c @@ -2058,6 +2058,8 @@ static struct { {"fputs", PF_fputs, 51}, {"fread", PF_fread, 0}, {"fwrite", PF_fwrite, 0}, + {"fseek", PF_fseek, 0}, + {"fsize", PF_fsize, 0}, {"strlen", PF_strlen, 52}, {"strcat", PF_strcat, 53}, {"substring", PF_substring, 54}, diff --git a/engine/client/quakedef.h b/engine/client/quakedef.h index e763b825..84dafa93 100644 --- a/engine/client/quakedef.h +++ b/engine/client/quakedef.h @@ -110,7 +110,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #define PNG_SUCKS_WITH_SETJMP //cos it does. #endif -#define QUAKE_GAME // as opposed to utilities //define PARANOID // speed sapping error checking #include diff --git a/engine/client/r_2d.c b/engine/client/r_2d.c index af012ee5..3f06102f 100644 --- a/engine/client/r_2d.c +++ b/engine/client/r_2d.c @@ -431,8 +431,9 @@ apic_t *R2D_LoadAtlasedPic(const char *name) if (!gl_load24bit.ival) { - qp = W_SafeGetLumpName(name); - if (qp) + size_t lumpsize; + qp = W_SafeGetLumpName(name, &lumpsize); + if (qp && lumpsize == 8+qp->width*qp->height) { apic->width = qp->width; apic->height = qp->height; diff --git a/engine/client/r_d3.c b/engine/client/r_d3.c index 0d9612b1..ade0704d 100644 --- a/engine/client/r_d3.c +++ b/engine/client/r_d3.c @@ -133,9 +133,9 @@ static void R_BuildDefaultTexnums_Doom3(shader_t *shader) if ((shader->flags & SHADER_HASFULLBRIGHT) && r_fb_bmodels.value && gl_load24bit.value) { if (!TEXVALID(tex->fullbright) && *mapname) - tex->fullbright = R_LoadHiResTexture(va("%s_luma", mapname), NULL, imageflags); + tex->fullbright = R_LoadHiResTexture(va("%s_luma:%s_glow", mapname, mapname), NULL, imageflags); if (!TEXVALID(tex->fullbright)) - tex->fullbright = R_LoadHiResTexture(va("%s_luma", imagename), subpath, imageflags); + tex->fullbright = R_LoadHiResTexture(va("%s_luma:%s_glow", imagename, imagename), subpath, imageflags); } } } diff --git a/engine/client/r_surf.c b/engine/client/r_surf.c index 1c4f70f1..e7631d35 100644 --- a/engine/client/r_surf.c +++ b/engine/client/r_surf.c @@ -2642,6 +2642,7 @@ struct webostate_s char dbgid[12]; model_t *wmodel; mleaf_t *leaf[2]; + int cluster[2]; qbyte pvs[MAX_MAP_LEAFS/8]; vboarray_t ebo; void *ebomem; @@ -2727,7 +2728,13 @@ void R_GeneratedWorldEBO(void *ctx, void *data, size_t a_, size_t b_) webostate->batches[i].idxbuffer = (index_t*)NULL + idxcount; idxcount += webostate->batches[i].numidx; } - BE_VBO_Finish(NULL, indexes, sizeof(*indexes) * idxcount, &webostate->ebo, NULL, &webostate->ebomem); + if (idxcount) + BE_VBO_Finish(NULL, indexes, sizeof(*indexes) * idxcount, &webostate->ebo, NULL, &webostate->ebomem); + else + { + memset(&webostate->ebo, 0, sizeof(webostate->ebo)); + webostate->ebomem = NULL; + } free(indexes); } #endif @@ -2741,11 +2748,22 @@ void R_GeneratedWorldEBO(void *ctx, void *data, size_t a_, size_t b_) if (!webostate->batches[i].numidx) continue; + if (batch->shader->flags & SHADER_NODRAW) + continue; + m = &webostate->batches[i].m; webostate->batches[i].pm = m; b = &webostate->batches[i].b; memcpy(b, batch, sizeof(*b)); memset(m, 0, sizeof(*m)); + + if (b->shader->flags & SHADER_NEEDSARRAYS) + { + if (b->shader->flags & SHADER_SKY) + continue; + b->shader = R_RegisterShader_Vertex("unsupported"); + } + m->numvertexes = webostate->batches[i].b.vbo->vertcount; b->mesh = &webostate->batches[i].pm; b->meshes = 1; @@ -2763,15 +2781,15 @@ void R_GeneratedWorldEBO(void *ctx, void *data, size_t a_, size_t b_) } } } -static void Surf_SimpleWorld(struct webostate_s *es, qbyte *pvs) +static void Surf_SimpleWorld_Q1BSP(struct webostate_s *es, qbyte *pvs) { mleaf_t *leaf; msurface_t *surf, **mark, **end; mesh_t *mesh; - int l; - int fc = -r_framecount; model_t *wmodel = es->wmodel; - for (leaf = wmodel->leafs+wmodel->numclusters, l = wmodel->numclusters; l-- > 0; leaf--) + int l = wmodel->numclusters; + int fc = -r_framecount; + for (leaf = wmodel->leafs+l; l-- > 0; leaf--) { if ((pvs[l>>3] & (1u<<(l&7))) && leaf->nummarksurfaces) { @@ -2792,7 +2810,6 @@ static void Surf_SimpleWorld(struct webostate_s *es, qbyte *pvs) if (eb->maxidx < eb->numidx + mesh->numindexes) { //FIXME: pre-allocate -// continue; eb->maxidx = eb->numidx + surf->mesh->numindexes + 512; eb->idxbuffer = BZ_Realloc(eb->idxbuffer, eb->maxidx * sizeof(index_t)); } @@ -2804,6 +2821,51 @@ static void Surf_SimpleWorld(struct webostate_s *es, qbyte *pvs) } } } +#if defined(Q2BSP) || defined(Q3BSP) +static void Surf_SimpleWorld_Q3BSP(struct webostate_s *es, qbyte *pvs) +{ + mleaf_t *leaf; + msurface_t *surf, **mark, **end; + mesh_t *mesh; + model_t *wmodel = es->wmodel; + int l = wmodel->numleafs; //is this doing submodels too? + int c; + int fc = -r_framecount; + for (leaf = wmodel->leafs; l-- > 0; leaf++) + { + c = leaf->cluster; + if (c < 0) + continue; //o.O + if ((pvs[c>>3] & (1u<<(c&7))) && leaf->nummarksurfaces) + { + mark = leaf->firstmarksurface; + end = mark+leaf->nummarksurfaces; + while(mark < end) + { + surf = *mark++; + if (surf->visframe != fc) + { + int i; + struct wesbatch_s *eb; + surf->visframe = fc; + + mesh = surf->mesh; + eb = &es->batches[surf->sbatch->ebobatch]; + if (eb->maxidx < eb->numidx + mesh->numindexes) + { + //FIXME: pre-allocate + eb->maxidx = eb->numidx + surf->mesh->numindexes + 512; + eb->idxbuffer = BZ_Realloc(eb->idxbuffer, eb->maxidx * sizeof(index_t)); + } + for (i = 0; i < mesh->numindexes; i++) + eb->idxbuffer[eb->numidx+i] = mesh->indexes[i] + mesh->vbofirstvert; + eb->numidx += mesh->numindexes; + } + } + } + } +} +#endif void R_GenWorldEBO(void *ctx, void *data, size_t a, size_t b) { int i; @@ -2812,23 +2874,6 @@ void R_GenWorldEBO(void *ctx, void *data, size_t a, size_t b) es->numbatches = es->wmodel->numbatches; - //maybe we should just use fatpvs instead, and wait for completion when outside? - if (es->leaf[1]) - { //view is near to a water boundary. this implies the water crosses the near clip plane. - qbyte tmppvs[MAX_MAP_LEAFS/8]; - int c; - Q1BSP_LeafPVS (es->wmodel, es->leaf[0], es->pvs, sizeof(es->pvs)); - Q1BSP_LeafPVS (es->wmodel, es->leaf[1], tmppvs, sizeof(tmppvs)); - c = (es->wmodel->numclusters+31)/32; - for (i=0 ; ipvs)[i] |= ((int *)tmppvs)[i]; - pvs = es->pvs; - } - else - { - pvs = Q1BSP_LeafPVS (es->wmodel, es->leaf[0], es->pvs, sizeof(es->pvs)); - } - for (i = 0; i < es->numbatches; i++) { es->batches[i].numidx = 0; @@ -2836,7 +2881,46 @@ void R_GenWorldEBO(void *ctx, void *data, size_t a, size_t b) es->batches[i].idxbuffer = NULL; } - Surf_SimpleWorld(es, pvs); +#if defined(Q2BSP) || defined(Q3BSP) + if (es->wmodel->fromgame == fg_quake2 || es->wmodel->fromgame == fg_quake3) + { + if (es->cluster[1] != -1 && es->cluster[0] != es->cluster[1]) + { //view is near to a water boundary. this implies the water crosses the near clip plane. + qbyte tmppvs[MAX_MAP_LEAFS/8], *pvs2; + int c; + pvs = es->wmodel->funcs.ClusterPVS(es->wmodel, es->cluster[0], es->pvs, sizeof(es->pvs)); + pvs2 = es->wmodel->funcs.ClusterPVS(es->wmodel, es->cluster[1], tmppvs, sizeof(tmppvs)); + c = (es->wmodel->numclusters+31)/32; + for (i=0 ; ipvs)[i] = ((int *)pvs)[i] | ((int *)pvs2)[i]; + pvs = es->pvs; + } + else + pvs = es->wmodel->funcs.ClusterPVS(es->wmodel, es->cluster[0], es->pvs, sizeof(es->pvs)); + + Surf_SimpleWorld_Q3BSP(es, pvs); + } + else +#endif + { + //maybe we should just use fatpvs instead, and wait for completion when outside? + if (es->leaf[1]) + { //view is near to a water boundary. this implies the water crosses the near clip plane. + qbyte tmppvs[MAX_MAP_LEAFS/8]; + int c; + Q1BSP_LeafPVS (es->wmodel, es->leaf[0], es->pvs, sizeof(es->pvs)); + Q1BSP_LeafPVS (es->wmodel, es->leaf[1], tmppvs, sizeof(tmppvs)); + c = (es->wmodel->numclusters+31)/32; + for (i=0 ; ipvs)[i] |= ((int *)tmppvs)[i]; + pvs = es->pvs; + } + else + { + pvs = Q1BSP_LeafPVS (es->wmodel, es->leaf[0], es->pvs, sizeof(es->pvs)); + } + Surf_SimpleWorld_Q1BSP(es, pvs); + } COM_AddWork(WG_MAIN, R_GeneratedWorldEBO, es, NULL, 0, 0); } @@ -2876,52 +2960,89 @@ void Surf_DrawWorld (void) Surf_LightmapShift(cl.worldmodel); #ifdef THREADEDWORLD - if ((r_dynamic.ival < 0 || cl.worldmodel->numbatches) && !r_refdef.recurse && cl.worldmodel->type == mod_brush && cl.worldmodel->fromgame == fg_quake) + if ((r_dynamic.ival < 0 || cl.worldmodel->numbatches) && !r_refdef.recurse && cl.worldmodel->type == mod_brush) { - int i = MAX_LIGHTSTYLES; if (webostate && webostate->wmodel != cl.worldmodel) { R_DestroyWorldEBO(webostate); webostate = NULL; } - if (webostate && !webogenerating) - for (i = 0; i < MAX_LIGHTSTYLES; i++) - { - if (webostate->lightstylevalues[i] != d_lightstylevalue[i]) - break; - } - if (webostate && webostate->leaf[0] == r_viewleaf && webostate->leaf[1] == r_viewleaf2 && i == MAX_LIGHTSTYLES) + if (qrenderer != QR_OPENGL && qrenderer != QR_VULKAN) + ; + else if (cl.worldmodel->fromgame == fg_quake) { - } - else - { - if (!webogenerating) - { - int i; - if (!cl.worldmodel->numbatches) - { - int sortid; - batch_t *batch; - cl.worldmodel->numbatches = 0; - for (sortid = 0; sortid < SHADER_SORT_COUNT; sortid++) - for (batch = cl.worldmodel->batches[sortid]; batch != NULL; batch = batch->next) - { - batch->ebobatch = cl.worldmodel->numbatches; - cl.worldmodel->numbatches++; - } - } - webogeneratingstate = true; - webogenerating = BZ_Malloc(sizeof(*webogenerating) + sizeof(webogenerating->batches[0]) * (cl.worldmodel->numbatches-1)); - webogenerating->wmodel = cl.worldmodel; - webogenerating->leaf[0] = r_viewleaf; - webogenerating->leaf[1] = r_viewleaf2; + int i = MAX_LIGHTSTYLES; + if (webostate && !webogenerating) for (i = 0; i < MAX_LIGHTSTYLES; i++) - webogenerating->lightstylevalues[i] = d_lightstylevalue[i]; - Q_strncpyz(webogenerating->dbgid, "webostate", sizeof(webogenerating->dbgid)); - COM_AddWork(WG_LOADER, R_GenWorldEBO, webogenerating, NULL, 0, 0); + { + if (webostate->lightstylevalues[i] != d_lightstylevalue[i]) + break; + } + if (webostate && webostate->leaf[0] == r_viewleaf && webostate->leaf[1] == r_viewleaf2 && i == MAX_LIGHTSTYLES) + { + } + else + { + if (!webogenerating) + { + int i; + if (!cl.worldmodel->numbatches) + { + int sortid; + batch_t *batch; + cl.worldmodel->numbatches = 0; + for (sortid = 0; sortid < SHADER_SORT_COUNT; sortid++) + for (batch = cl.worldmodel->batches[sortid]; batch != NULL; batch = batch->next) + { + batch->ebobatch = cl.worldmodel->numbatches; + cl.worldmodel->numbatches++; + } + } + webogeneratingstate = true; + webogenerating = BZ_Malloc(sizeof(*webogenerating) + sizeof(webogenerating->batches[0]) * (cl.worldmodel->numbatches-1)); + webogenerating->wmodel = cl.worldmodel; + webogenerating->leaf[0] = r_viewleaf; + webogenerating->leaf[1] = r_viewleaf2; + for (i = 0; i < MAX_LIGHTSTYLES; i++) + webogenerating->lightstylevalues[i] = d_lightstylevalue[i]; + Q_strncpyz(webogenerating->dbgid, "webostate", sizeof(webogenerating->dbgid)); + COM_AddWork(WG_LOADER, R_GenWorldEBO, webogenerating, NULL, 0, 0); + } } } + else if (cl.worldmodel->fromgame == fg_quake3) + { + if (webostate && webostate->cluster[0] == r_viewcluster && webostate->cluster[1] == r_viewcluster2) + { + } + else + { + if (!webogenerating) + { + if (!cl.worldmodel->numbatches) + { + int sortid; + batch_t *batch; + cl.worldmodel->numbatches = 0; + for (sortid = 0; sortid < SHADER_SORT_COUNT; sortid++) + for (batch = cl.worldmodel->batches[sortid]; batch != NULL; batch = batch->next) + { + batch->ebobatch = cl.worldmodel->numbatches; + cl.worldmodel->numbatches++; + } + } + webogeneratingstate = true; + webogenerating = BZ_Malloc(sizeof(*webogenerating) + sizeof(webogenerating->batches[0]) * (cl.worldmodel->numbatches-1)); + webogenerating->wmodel = cl.worldmodel; + webogenerating->cluster[0] = r_viewcluster; + webogenerating->cluster[1] = r_viewcluster2; + Q_strncpyz(webogenerating->dbgid, "webostate", sizeof(webogenerating->dbgid)); + COM_AddWork(WG_LOADER, R_GenWorldEBO, webogenerating, NULL, 0, 0); + } + } + } + if (webostate) { entvis = surfvis = webostate->pvs; diff --git a/engine/client/renderer.c b/engine/client/renderer.c index 1f042048..ff91e445 100644 --- a/engine/client/renderer.c +++ b/engine/client/renderer.c @@ -7,6 +7,10 @@ #include +#define DEFAULT_WIDTH 640 +#define DEFAULT_HEIGHT 480 +#define DEFAULT_BPP 32 + refdef_t r_refdef; vec3_t r_origin, vpn, vright, vup; entity_t r_worldentity; @@ -21,6 +25,7 @@ int rspeeds[RSPEED_MAX]; int rquant[RQUANT_MAX]; void R_InitParticleTexture (void); +void R_RestartRenderer (rendererstate_t *newr); qboolean vid_isfullscreen; @@ -406,7 +411,8 @@ cvar_t r_shadow_heightscale_bumpmap = CVARD ("r_shadow_heightscale_bumpmap", cvar_t r_glsl_offsetmapping = CVARFD ("r_glsl_offsetmapping", "0", CVAR_ARCHIVE|CVAR_SHADERSYSTEM, "Enables the use of paralax mapping, adding fake depth to textures."); cvar_t r_glsl_offsetmapping_scale = CVAR ("r_glsl_offsetmapping_scale", "0.04"); cvar_t r_glsl_offsetmapping_reliefmapping = CVARFD("r_glsl_offsetmapping_reliefmapping", "0", CVAR_ARCHIVE|CVAR_SHADERSYSTEM, "Changes the paralax sampling mode to be a bit nicer, but noticably more expensive at high resolutions. r_glsl_offsetmapping must be set."); -cvar_t r_glsl_turbscale = CVARFD ("r_glsl_turbscale", "1", CVAR_ARCHIVE, "Controls the strength of water ripples (used by the altwater glsl code)."); +cvar_t r_glsl_turbscale_reflect = CVARFD ("r_glsl_turbscale_reflect", "1", CVAR_ARCHIVE, "Controls the strength of the water reflection ripples (used by the altwater glsl code)."); +cvar_t r_glsl_turbscale_refract = CVARFD ("r_glsl_turbscale_refract", "1", CVAR_ARCHIVE, "Controls the strength of the underwater ripples (used by the altwater glsl code)."); cvar_t r_fastturbcolour = CVARFD ("r_fastturbcolour", "0.1 0.2 0.3", CVAR_ARCHIVE, "The colour to use for water surfaces draw with r_waterstyle 0.\n"); cvar_t r_waterstyle = CVARFD ("r_waterstyle", "1", CVAR_ARCHIVE|CVAR_SHADERSYSTEM, "Changes how water, and teleporters are drawn. Possible values are:\n0: fastturb-style block colour.\n1: regular q1-style water.\n2: refraction(ripply and transparent)\n3: refraction with reflection at an angle\n4: ripplemapped without reflections (requires particle effects)\n5: ripples+reflections"); @@ -424,16 +430,16 @@ cvar_t vid_desktopgamma = CVARFD ("vid_desktopgamma", "0", cvar_t r_fog_exp2 = CVARD ("r_fog_exp2", "1", "Expresses how fog fades with distance. 0 (matching DarkPlaces's default) is typically more realistic, while 1 (matching FitzQuake and others) is more common."); -#ifdef VKQUAKE -cvar_t vk_stagingbuffers = CVARD ("vk_stagingbuffers", "", "Configures which dynamic buffers are copied into gpu memory for rendering, instead of reading from shared memory. Empty for default settings.\nAccepted chars are u, e, v, 0."); -cvar_t vk_submissionthread = CVARD ("vk_submissionthread", "", "Execute submits+presents on a thread dedicated to executing them. This may be a significant speedup on certain drivers."); -cvar_t vk_debug = CVARD ("vk_debug", "0", "Register a debug handler to display driver/layer messages. 2 enables the standard validation layers."); -cvar_t vk_loadglsl = CVARD ("vk_loadglsl", "", "Enable direct loading of glsl, where supported by drivers. Do not use in combination with vk_debug 2 (vk_debug should be 1 if you want to see any errors). Don't forget to do a vid_restart after."); -#endif - extern cvar_t gl_dither; cvar_t gl_screenangle = SCVAR("gl_screenangle", "0"); +#endif +#ifdef VKQUAKE +cvar_t vk_stagingbuffers = CVARD ("vk_stagingbuffers", "", "Configures which dynamic buffers are copied into gpu memory for rendering, instead of reading from shared memory. Empty for default settings.\nAccepted chars are u, e, v, 0."); +cvar_t vk_submissionthread = CVARD ("vk_submissionthread", "", "Execute submits+presents on a thread dedicated to executing them. This may be a significant speedup on certain drivers."); +cvar_t vk_debug = CVARD ("vk_debug", "0", "Register a debug handler to display driver/layer messages. 2 enables the standard validation layers."); +cvar_t vk_loadglsl = CVARD ("vk_loadglsl", "", "Enable direct loading of glsl, where supported by drivers. Do not use in combination with vk_debug 2 (vk_debug should be 1 if you want to see any glsl compile errors). Don't forget to do a vid_restart after."); +cvar_t vk_dualqueue = CVARD ("vk_dualqueue", "", "Attempt to use a separate queue for presentation. Blank for default."); #endif #if defined(D3DQUAKE) @@ -595,6 +601,51 @@ void R_ListSkyBoxes_f(void) void R_SetRenderer_f (void); void R_ReloadRenderer_f (void); +void R_ToggleFullscreen_f(void) +{ + double time; + rendererstate_t newr; + + if (currentrendererstate.renderer == NULL) + { + Con_Printf("vid_toggle: no renderer currently set\n"); + return; + } + //vid toggle makes no sense with these two... + if (currentrendererstate.renderer->rtype == QR_HEADLESS || currentrendererstate.renderer->rtype == QR_NONE) + return; + + Cvar_ApplyLatches(CVAR_RENDERERLATCH); + + newr = currentrendererstate; + newr.fullscreen = newr.fullscreen?0:2; + if (newr.fullscreen) + { + int dbpp, dheight, dwidth, drate; + if (!Sys_GetDesktopParameters(&dwidth, &dheight, &dbpp, &drate)) + { + dwidth = DEFAULT_WIDTH; + dheight = DEFAULT_HEIGHT; + dbpp = DEFAULT_BPP; + drate = 0; + } + + newr.width = dwidth; + newr.height = dheight; + } + else + { + newr.width = DEFAULT_WIDTH; + newr.height = DEFAULT_HEIGHT; + } + + time = Sys_DoubleTime(); + R_RestartRenderer(&newr); + Con_DPrintf("main thread video restart took %f secs\n", Sys_DoubleTime() - time); +// COM_WorkerFullSync(); +// Con_Printf("full video restart took %f secs\n", Sys_DoubleTime() - time); +} + void Renderer_Init(void) { #ifdef AVAIL_JPEGLIB @@ -611,6 +662,7 @@ void Renderer_Init(void) Cmd_AddCommand("setrenderer", R_SetRenderer_f); Cmd_AddCommand("vid_restart", R_RestartRenderer_f); Cmd_AddCommand("vid_reload", R_ReloadRenderer_f); + Cmd_AddCommand("vid_toggle", R_ToggleFullscreen_f); #ifdef RTLIGHTS Cmd_AddCommand ("r_editlights_reload", R_ReloadRTLights_f); @@ -758,7 +810,8 @@ void Renderer_Init(void) Cvar_Register (&r_glsl_offsetmapping, GRAPHICALNICETIES); Cvar_Register (&r_glsl_offsetmapping_scale, GRAPHICALNICETIES); Cvar_Register (&r_glsl_offsetmapping_reliefmapping, GRAPHICALNICETIES); - Cvar_Register (&r_glsl_turbscale, GRAPHICALNICETIES); + Cvar_Register (&r_glsl_turbscale_reflect, GRAPHICALNICETIES); + Cvar_Register (&r_glsl_turbscale_refract, GRAPHICALNICETIES); Cvar_Register(&scr_viewsize, SCREENOPTIONS); Cvar_Register(&scr_fov, SCREENOPTIONS); @@ -860,6 +913,7 @@ void Renderer_Init(void) Cvar_Register (&vk_submissionthread, VKRENDEREROPTIONS); Cvar_Register (&vk_debug, VKRENDEREROPTIONS); Cvar_Register (&vk_loadglsl, VKRENDEREROPTIONS); + Cvar_Register (&vk_dualqueue, VKRENDEREROPTIONS); #endif // misc @@ -1572,10 +1626,6 @@ void R_ReloadRenderer_f (void) R_ApplyRenderer_Load(NULL); } -#define DEFAULT_WIDTH 640 -#define DEFAULT_HEIGHT 480 -#define DEFAULT_BPP 32 - //use Cvar_ApplyLatches(CVAR_RENDERERLATCH) beforehand. qboolean R_BuildRenderstate(rendererstate_t *newr, char *rendererstring) { diff --git a/engine/client/sbar.c b/engine/client/sbar.c index e64e7f69..047a6dcf 100644 --- a/engine/client/sbar.c +++ b/engine/client/sbar.c @@ -944,6 +944,7 @@ void Sbar_Flush (void) void Sbar_Start (void) //if one of these fails, skip the entire status bar. { int i; + size_t lumpsize; if (sbar_loaded) return; @@ -967,7 +968,7 @@ void Sbar_Start (void) //if one of these fails, skip the entire status bar. #ifdef HEXEN2 sbar_hexen2 = false; - if (W_SafeGetLumpName("tinyfont")) + if (W_SafeGetLumpName("tinyfont", &lumpsize)) sbar_hexen2 = true; // if (sb_nums[0][0] && sb_nums[0][0]->width < 13) // sbar_hexen2 = true; @@ -1048,7 +1049,7 @@ void Sbar_Start (void) //if one of these fails, skip the entire status bar. sb_scorebar = Sbar_PicFromWad ("scorebar"); //try to detect rogue wads, and thus the stats we will be getting from the server. - sbar_rogue = COM_CheckParm("-rogue") || !!W_SafeGetLumpName("r_lava"); + sbar_rogue = COM_CheckParm("-rogue") || !!W_SafeGetLumpName("r_lava", &lumpsize); if (sbar_rogue) { rsb_invbar[0] = Sbar_PicFromWad ("r_invbar1"); @@ -1070,7 +1071,7 @@ void Sbar_Start (void) //if one of these fails, skip the entire status bar. rsb_ammo[2] = Sbar_PicFromWad ("r_ammoplasma"); } - sbar_hipnotic = COM_CheckParm("-hipnotic") || !!W_SafeGetLumpName("inv_mjolnir"); + sbar_hipnotic = COM_CheckParm("-hipnotic") || !!W_SafeGetLumpName("inv_mjolnir", &lumpsize); if (sbar_hipnotic) { hsb_weapons[0][0] = Sbar_PicFromWad ("inv_laser"); @@ -3193,6 +3194,7 @@ ping time frags name ================== */ +#define NOFILL //for reference: //define COLUMN(title, width, code) @@ -3202,21 +3204,21 @@ ping time frags name if (p < 0 || p > 999) p = 999; \ sprintf(num, "%4i", p); \ Draw_FunStringWidth(x, y, num, 4*8, false, false); \ -},) +},NOFILL) #define COLUMN_PL COLUMN(pl, 2*8, \ { \ int p = s->pl; \ sprintf(num, "%2i", p); \ Draw_FunStringWidth(x, y, num, 2*8, false, false); \ -},) +},NOFILL) #define COLUMN_TIME COLUMN(time, 4*8, \ { \ total = realtime - s->realentertime; \ minutes = (int)total/60; \ sprintf (num, "%4i", minutes); \ Draw_FunStringWidth(x, y, num, 4*8, false, false); \ -},) +},NOFILL) #define COLUMN_FRAGS COLUMN(frags, 5*8, \ { \ int cx; int cy; \ @@ -3262,14 +3264,14 @@ ping time frags name { \ Draw_FunStringWidth(x, y, s->team, 4*8, false, false); \ } \ -},) -#define COLUMN_NAME COLUMN(name, namesize, {Draw_FunStringWidth(x, y, s->name, namesize, false, false);},) -#define COLUMN_KILLS COLUMN(kils, 4*8, {Draw_FunStringWidth(x, y, va("%4i", Stats_GetKills(k)), 4*8, false, false);},) -#define COLUMN_TKILLS COLUMN(tkil, 4*8, {Draw_FunStringWidth(x, y, va("%4i", Stats_GetTKills(k)), 4*8, false, false);},) -#define COLUMN_DEATHS COLUMN(dths, 4*8, {Draw_FunStringWidth(x, y, va("%4i", Stats_GetDeaths(k)), 4*8, false, false);},) -#define COLUMN_TOUCHES COLUMN(tchs, 4*8, {Draw_FunStringWidth(x, y, va("%4i", Stats_GetTouches(k)), 4*8, false, false);},) -#define COLUMN_CAPS COLUMN(caps, 4*8, {Draw_FunStringWidth(x, y, va("%4i", Stats_GetCaptures(k)), 4*8, false, false);},) -#define COLUMN_AFK COLUMN(, 0, {int cs = atoi(Info_ValueForKey(s->userinfo, "chat")); if (cs)Draw_FunStringWidth(x+4, y, (cs&2)?"afk":"msg", 4*8, false, false);},) +},NOFILL) +#define COLUMN_NAME COLUMN(name, namesize, {Draw_FunStringWidth(x, y, s->name, namesize, false, false);},NOFILL) +#define COLUMN_KILLS COLUMN(kils, 4*8, {Draw_FunStringWidth(x, y, va("%4i", Stats_GetKills(k)), 4*8, false, false);},NOFILL) +#define COLUMN_TKILLS COLUMN(tkil, 4*8, {Draw_FunStringWidth(x, y, va("%4i", Stats_GetTKills(k)), 4*8, false, false);},NOFILL) +#define COLUMN_DEATHS COLUMN(dths, 4*8, {Draw_FunStringWidth(x, y, va("%4i", Stats_GetDeaths(k)), 4*8, false, false);},NOFILL) +#define COLUMN_TOUCHES COLUMN(tchs, 4*8, {Draw_FunStringWidth(x, y, va("%4i", Stats_GetTouches(k)), 4*8, false, false);},NOFILL) +#define COLUMN_CAPS COLUMN(caps, 4*8, {Draw_FunStringWidth(x, y, va("%4i", Stats_GetCaptures(k)), 4*8, false, false);},NOFILL) +#define COLUMN_AFK COLUMN(afk, 0, {int cs = atoi(Info_ValueForKey(s->userinfo, "chat")); if (cs)Draw_FunStringWidth(x+4, y, (cs&2)?"afk":"msg", 4*8, false, false);},NOFILL) //columns are listed here in display order diff --git a/engine/client/snd_al.c b/engine/client/snd_al.c index 5467fb83..910c5c5a 100644 --- a/engine/client/snd_al.c +++ b/engine/client/snd_al.c @@ -931,8 +931,7 @@ static qboolean OpenAL_InitLibrary(void) static qboolean OpenAL_Init(soundcardinfo_t *sc, const char *devname) { - oalinfo_t *oali = Z_Malloc(sizeof(oalinfo_t)); - sc->handle = oali; + oalinfo_t *oali; if (!OpenAL_InitLibrary()) { @@ -943,46 +942,43 @@ static qboolean OpenAL_Init(soundcardinfo_t *sc, const char *devname) return false; } - if (oali->OpenAL_Context) - { - Con_Printf(SDRVNAME": only able to load one device at a time\n"); - return false; - } - if (!devname || !*devname) devname = palcGetString(NULL, ALC_DEFAULT_DEVICE_SPECIFIER); Q_snprintfz(sc->name, sizeof(sc->name), "%s", devname); Con_Printf("Initiating "SDRVNAME": %s.\n", devname); + oali = Z_Malloc(sizeof(oalinfo_t)); + sc->handle = oali; + oali->OpenAL_Device = palcOpenDevice(devname); if (oali->OpenAL_Device == NULL) - { PrintALError("Could not init a sound device\n"); - return false; - } - - oali->OpenAL_Context = palcCreateContext(oali->OpenAL_Device, NULL); - if (!oali->OpenAL_Context) + else { - PrintALError("Could not init a sound context\n"); - return false; + oali->OpenAL_Context = palcCreateContext(oali->OpenAL_Device, NULL); + if (!oali->OpenAL_Context) + PrintALError("Could not init a sound context\n"); + else + { + palcMakeContextCurrent(oali->OpenAL_Context); + // palcProcessContext(oali->OpenAL_Context); + + //S_Info(); + + //fixme... + memset(oali->source, 0, sizeof(oali->source)); + PrintALError("alGensources for normal sources"); + + palListenerfv(AL_POSITION, oali->ListenPos); + palListenerfv(AL_VELOCITY, oali->ListenVel); + palListenerfv(AL_ORIENTATION, oali->ListenOri); + + return true; + } + palcCloseDevice(oali->OpenAL_Device); } - - palcMakeContextCurrent(oali->OpenAL_Context); -// palcProcessContext(oali->OpenAL_Context); - - //S_Info(); - - //fixme... - memset(oali->source, 0, sizeof(oali->source)); - PrintALError("alGensources for normal sources"); - - - palListenerfv(AL_POSITION, oali->ListenPos); - palListenerfv(AL_VELOCITY, oali->ListenVel); - palListenerfv(AL_ORIENTATION, oali->ListenOri); - - return true; + Z_Free(oali); + return false; } //called when some al-specific cvar has changed that is linked to openal state. diff --git a/engine/client/sys_npfte.c b/engine/client/sys_npfte.c index e14f397c..2b1a5d27 100644 --- a/engine/client/sys_npfte.c +++ b/engine/client/sys_npfte.c @@ -13,7 +13,7 @@ #include #endif -#include "libs/npapi/npupp.h" +#include "../libs/npapi/npupp.h" #include "sys_plugfte.h" /*work around absolute crapness in the npapi headers*/ diff --git a/engine/client/sys_plugfte.c b/engine/client/sys_plugfte.c index 0976bec5..ad6bbea6 100644 --- a/engine/client/sys_plugfte.c +++ b/engine/client/sys_plugfte.c @@ -18,6 +18,10 @@ void *globalmutex; # endif #endif +#ifndef INVALID_FILE_ATTRIBUTES +#define INVALID_FILE_ATTRIBUTES ~0 +#endif + #ifdef _WIN32 dllhandle_t *Sys_LoadLibrary(const char *name, dllfunction_t *funcs) { diff --git a/engine/client/sys_sdl.c b/engine/client/sys_sdl.c index e31905a6..b979b507 100644 --- a/engine/client/sys_sdl.c +++ b/engine/client/sys_sdl.c @@ -717,7 +717,7 @@ void Sys_Sleep (double seconds) #ifdef HAVEAUTOUPDATE int Sys_GetAutoUpdateSetting(void) { - return -1; + return UPD_UNSUPPORTED; } void Sys_SetAutoUpdateSetting(int newval) { diff --git a/engine/client/sys_win.c b/engine/client/sys_win.c index c5160c7b..41b8371d 100644 --- a/engine/client/sys_win.c +++ b/engine/client/sys_win.c @@ -295,8 +295,10 @@ int Sys_EnumerateFiles (const char *gpath, const char *match, int (QDECL *func)( #endif #if defined(_DEBUG) || defined(DEBUG) +#if !defined(_MSC_VER) || _MSC_VER > 1200 #define CATCHCRASH #endif +#endif #if !defined(CLIENTONLY) && !defined(SERVERONLY) qboolean isDedicated = false; @@ -1061,12 +1063,18 @@ qboolean Sys_Rename (char *oldfname, char *newfname) return !rename(oldfname, newfname); } +#ifdef _MSC_VER +#define ULL(x) x##ui64 +#else +#define ULL(x) x##ull +#endif + static time_t Sys_FileTimeToTime(FILETIME ft) { - ULARGE_INTEGER ull; - ull.LowPart = ft.dwLowDateTime; - ull.HighPart = ft.dwHighDateTime; - return ull.QuadPart / 10000000ULL - 11644473600ULL; + ULARGE_INTEGER ull; + ull.LowPart = ft.dwLowDateTime; + ull.HighPart = ft.dwHighDateTime; + return ull.QuadPart / ULL(10000000) - ULL(11644473600); } static int Sys_EnumerateFiles_9x (const char *match, int matchstart, int neststart, int (QDECL *func)(const char *fname, qofs_t fsize, time_t mtime, void *parm, searchpathfuncs_t *spath), void *parm, searchpathfuncs_t *spath) @@ -2123,10 +2131,6 @@ void Sys_SendKeyEvents (void) { MSG msg; -#ifdef _MSC_VER -#define strtoull _strtoui64 -#endif - if (isPlugin) { DWORD avail; @@ -2164,7 +2168,7 @@ void Sys_SendKeyEvents (void) sys_parenttop = strtoul(Cmd_Argv(2), NULL, 0); sys_parentwidth = strtoul(Cmd_Argv(3), NULL, 0); sys_parentheight = strtoul(Cmd_Argv(4), NULL, 0); - sys_parentwindow = (HWND)(intptr_t)strtoull(Cmd_Argv(5), NULL, 16); + sys_parentwindow = (HWND)(qintptr_t)strtoull(Cmd_Argv(5), NULL, 16); } #if !defined(CLIENTONLY) || defined(CSQC_DAT) || defined(MENU_DAT) else if (QCExternalDebuggerCommand(text)) @@ -2261,9 +2265,19 @@ HINSTANCE global_hInstance; int global_nCmdShow; HWND hwnd_dialog; - +static const IID qIID_IShellLinkW = {0x000214F9L, 0, 0, {0xc0,0,0,0,0,0,0,0x46}}; +static const IID qIID_IPersistFile = {0x0000010BL, 0, 0, {0xc0,0,0,0,0,0,0,0x46}}; #include +#if defined(_MSC_VER) && _MSC_VER <= 1200 +#define pSHBrowseForFolderW SHBrowseForFolderW +#define pSHGetPathFromIDListW SHGetPathFromIDListW +#define pSHGetSpecialFolderPathW SHGetSpecialFolderPathW +#define pShell_NotifyIconW Shell_NotifyIconW +void Win7_Init(void) +{ +} +#else typedef struct qSHARDAPPIDINFOLINK { IShellLinkW *psl; @@ -2425,9 +2439,6 @@ typedef struct qICustomDestinationList static const IID qIID_ICustomDestinationList = {0x6332debf, 0x87b5, 0x4670, {0x90,0xc0,0x5e,0x57,0xb4,0x08,0xa4,0x9e}}; static const CLSID qCLSID_DestinationList = {0x77f10cf0, 0x3db5, 0x4966, {0xb5,0x20,0xb7,0xc5,0x4f,0xd3,0x5e,0xd6}}; -static const IID qIID_IShellLinkW = {0x000214F9L, 0, 0, {0xc0,0,0,0,0,0,0,0x46}}; -static const IID qIID_IPersistFile = {0x0000010BL, 0, 0, {0xc0,0,0,0,0,0,0,0x46}}; - #define WIN7_APPNAME L"FTEQuake" static IShellLinkW *CreateShellLink(char *command, char *target, char *title, char *desc) @@ -2604,6 +2615,7 @@ void Win7_TaskListInit(void) cdl->lpVtbl->Release(cdl); } } +#endif BOOL CopyFileU(const char *src, const char *dst, BOOL bFailIfExists) { @@ -2843,12 +2855,12 @@ void Update_Check(void) static qboolean doneupdatecheck; //once per run struct dl_download *dl; - if (sys_autoupdatesetting < 2) //not if disabled (do it once it does get enabled) + if (sys_autoupdatesetting <= UPD_OFF) //not if disabled (do it once it does get enabled) return; if (!doneupdatecheck) { - char *updateroot = (sys_autoupdatesetting>=3)?UPDATE_URL_NIGHTLY:UPDATE_URL_TESTED; + char *updateroot = (sys_autoupdatesetting>=UPD_TESTING)?UPDATE_URL_NIGHTLY:UPDATE_URL_TESTED; doneupdatecheck = true; dl = HTTP_CL_Get(va(UPDATE_URL_VERSION, updateroot), NULL, Update_Versioninfo_Available); dl->file = FS_OpenTemp(); @@ -2883,7 +2895,13 @@ BOOL MoveFileU(const char *src, const char *dst) { wchar_t wide1[2048]; wchar_t wide2[2048]; - return MoveFileW(widen(wide1, sizeof(wide1), src), widen(wide2, sizeof(wide2), dst)); + return MoveFileExW(widen(wide1, sizeof(wide1), src), widen(wide2, sizeof(wide2), dst), MOVEFILE_COPY_ALLOWED); +} + +void Sys_SetUpdatedBinary(const char *binary) +{ + //downloads menu has provided a new binary to use + MyRegSetValue(HKEY_CURRENT_USER, "Software\\"FULLENGINENAME, "pending" UPD_BUILDTYPE EXETYPE, REG_SZ, binary, strlen(binary)+1); } qboolean Sys_CheckUpdated(char *bindir, size_t bindirsize) @@ -2896,11 +2914,11 @@ qboolean Sys_CheckUpdated(char *bindir, size_t bindirsize) char *e; strtoul(SVNREVISIONSTR, &e, 10); if (!*SVNREVISIONSTR || *e) //svn revision didn't parse as an exact number. this implies it has an 'M' in it to mark it as modified, or a - to mean unknown. either way, its bad and autoupdates when we don't know what we're updating from is a bad idea. - sys_autoupdatesetting = -1; + sys_autoupdatesetting = UPD_UNSUPPORTED; else if (COM_CheckParm("-noupdate") || COM_CheckParm("--noupdate") || COM_CheckParm("-noautoupdate") || COM_CheckParm("--noautoupdate")) - sys_autoupdatesetting = 0; + sys_autoupdatesetting = UPD_REVERT; else if (COM_CheckParm("-autoupdate") || COM_CheckParm("--autoupdate")) - sys_autoupdatesetting = 3; + sys_autoupdatesetting = UPD_TESTING; else { //favour 'tested' @@ -2909,7 +2927,7 @@ qboolean Sys_CheckUpdated(char *bindir, size_t bindirsize) if (!strcmp(SVNREVISIONSTR, "-")) return false; //no revision info in this build, meaning its custom built and thus cannot check against the available updated versions. - else if (sys_autoupdatesetting == 0) + else if (sys_autoupdatesetting == UPD_REVERT || sys_autoupdatesetting == UPD_UNSUPPORTED) return false; else if (isPlugin == 1) { @@ -2989,6 +3007,9 @@ int Sys_GetAutoUpdateSetting(void) void Sys_SetAutoUpdateSetting(int newval) { } +void Sys_SetUpdatedBinary(const char *binary) +{ +} #endif qboolean Sys_CheckUpdated(char *bindir, size_t bindirsize) { @@ -3094,7 +3115,7 @@ void Sys_DoFileAssociations(int elevated) if (!ok && elevated < 2) { HINSTANCE ch = ShellExecute(mainwindow, "runas", com_argv[0], va("-register_types %i", elevated+1), NULL, SW_SHOWNORMAL); - if ((intptr_t)ch <= 32) + if ((qintptr_t)ch <= 32) Sys_DoFileAssociations(2); return; } @@ -3277,7 +3298,16 @@ static BOOL microsoft_accessU(LPCSTR pszFolder, DWORD dwAccessDesired) return microsoft_accessW(widen(wpath, sizeof(wpath), pszFolder), dwAccessDesired); } - +#ifndef GWLP_WNDPROC +#define GWLP_WNDPROC GWL_WNDPROC +#define SetWindowLongPtr SetWindowLong +#define LONG_PTR LONG +#endif +#ifndef BIF_NEWDIALOGSTYLE +#define BIF_NEWDIALOGSTYLE 0x00000040 //v5 +#define BFFM_SETOKTEXT (WM_USER + 105) //v6 +#define BFFM_SETEXPANDED (WM_USER + 106) //v6 +#endif static WNDPROC omgwtfwhyohwhy; static LRESULT CALLBACK stoopidstoopidstoopid(HWND w, UINT m, WPARAM wp, LPARAM lp) @@ -3632,7 +3662,7 @@ qboolean Sys_RunInstaller(void) { GetModuleFileName(NULL, exepath, sizeof(exepath)); ch = ShellExecute(mainwindow, "runas", com_argv[0], va("%s -doinstall", COM_Parse(GetCommandLine())), NULL, SW_SHOWNORMAL); - if ((intptr_t)ch > 32) + if ((qintptr_t)ch > 32) return true; //succeeded. should quit out. return Sys_DoInstall(); //if it failed, try doing it with the current privileges } @@ -3898,11 +3928,7 @@ int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLin memset(&parms, 0, sizeof(parms)); -// #ifndef MINGW -// #if _MSC_VER > 1200 - Win7_Init(); -// #endif -// #endif + Win7_Init(); #ifdef _MSC_VER #if _M_IX86_FP >= 1 @@ -4356,7 +4382,7 @@ HCURSOR hArrowCursor, hCustomCursor; void *WIN_CreateCursor(const char *filename, float hotx, float hoty, float scale) { int width, height; - BITMAPV5HEADER bi; + BITMAPV4HEADER bi; DWORD x,y; HCURSOR hAlphaCursor = NULL; ICONINFO ii; @@ -4393,20 +4419,20 @@ void *WIN_CreateCursor(const char *filename, float hotx, float hoty, float scale rgbadata_start = nd; } - memset(&bi,0, sizeof(BITMAPV5HEADER)); - bi.bV5Size = sizeof(BITMAPV5HEADER); - bi.bV5Width = width; - bi.bV5Height = height; - bi.bV5Planes = 1; - bi.bV5BitCount = 32; - bi.bV5Compression = BI_BITFIELDS; + memset(&bi,0, sizeof(bi)); + bi.bV4Size = sizeof(bi); + bi.bV4Width = width; + bi.bV4Height = height; + bi.bV4Planes = 1; + bi.bV4BitCount = 32; + bi.bV4V4Compression = BI_BITFIELDS; // The following mask specification specifies a supported 32 BPP // alpha format for Windows XP. //FIXME: can we not just specify it as RGBA? meh. - bi.bV5RedMask = 0x00FF0000; - bi.bV5GreenMask = 0x0000FF00; - bi.bV5BlueMask = 0x000000FF; - bi.bV5AlphaMask = 0xFF000000; + bi.bV4RedMask = 0x00FF0000; + bi.bV4GreenMask = 0x0000FF00; + bi.bV4BlueMask = 0x000000FF; + bi.bV4AlphaMask = 0xFF000000; // Create the DIB section with an alpha channel. maindc = GetDC(mainwindow); diff --git a/engine/client/wad.c b/engine/client/wad.c index beafb7b5..0e05a97f 100644 --- a/engine/client/wad.c +++ b/engine/client/wad.c @@ -124,7 +124,7 @@ void W_LoadWadFile (char *filename) W_GetLumpinfo ============= */ -lumpinfo_t *W_GetLumpinfo (char *name) +/*lumpinfo_t *W_GetLumpinfo (char *name) { int i; lumpinfo_t *lump_p; @@ -140,9 +140,9 @@ lumpinfo_t *W_GetLumpinfo (char *name) Sys_Error ("W_GetLumpinfo: %s not found", name); return NULL; -} +}*/ -void *W_SafeGetLumpName (const char *name) +void *W_SafeGetLumpName (const char *name, size_t *size) { int i; lumpinfo_t *lump_p; @@ -153,21 +153,24 @@ void *W_SafeGetLumpName (const char *name) for (lump_p=wad_lumps, i=0 ; iname)) + { + *size = lump_p->disksize; return (void *)(wad_base+lump_p->filepos); + } } return NULL; } -void *W_GetLumpName (char *name) +/*void *W_GetLumpName (char *name) { lumpinfo_t *lump; lump = W_GetLumpinfo (name); return (void *)(wad_base + lump->filepos); -} +}*/ -void *W_GetLumpNum (int num) +/*void *W_GetLumpNum (int num) { lumpinfo_t *lump; @@ -177,7 +180,7 @@ void *W_GetLumpNum (int num) lump = wad_lumps + num; return (void *)(wad_base + lump->filepos); -} +}*/ /* ============================================================================= @@ -470,22 +473,53 @@ qbyte *W_GetTexture(const char *name, int *width, int *height, qboolean *usesalp miptex_t *tex; qbyte *data; - if ((!strncmp(name, "gfx/", 4) || !strncmp(name, "wad/", 4)) && strcmp(name, "gfx/conchars")) + if (!strncmp(name, "gfx/", 4) || !strncmp(name, "wad/", 4)) { qpic_t *p; - p = W_SafeGetLumpName(name+4); + size_t lumpsize; + p = W_SafeGetLumpName(name+4, &lumpsize); if (p) { - *width = p->width; - *height = p->height; - *usesalpha = false; + if (!strcmp(name+4, "conchars") && lumpsize==128*128) + { //conchars has no header. + qbyte *lump = (qbyte*)p; + extern cvar_t con_ocranaleds; - data = BZ_Malloc(p->width * p->height * 4); - for (i = 0; i < p->width * p->height; i++) - { - ((unsigned int*)data)[i] = d_8to24rgbtable[p->data[i]]; + if (con_ocranaleds.ival) + { + if (con_ocranaleds.ival != 2 || QCRC_Block(lump, 128*128) == 798) + AddOcranaLEDsIndexed (lump, 128, 128); + } + + *width = 128; + *height = 128; + *usesalpha = false; + + data = BZ_Malloc(128 * 128 * 4); + for (i = 0; i < 128 * 128; i++) + { + qbyte b = lump[i]; + if (b == 0) + ((unsigned int*)data)[i] = 0; + else + ((unsigned int*)data)[i] = d_8to24rgbtable[lump[i]] | 0xff000000; + } + + return data; + } + else if (lumpsize == 8+p->width*p->height) + { + *width = p->width; + *height = p->height; + *usesalpha = false; + + data = BZ_Malloc(p->width * p->height * 4); + for (i = 0; i < p->width * p->height; i++) + { + ((unsigned int*)data)[i] = d_8to24rgbtable[p->data[i]]; + } + return data; } - return data; } } diff --git a/engine/client/wad.h b/engine/client/wad.h index fbb6d497..b91c5b74 100644 --- a/engine/client/wad.h +++ b/engine/client/wad.h @@ -88,10 +88,10 @@ extern qbyte *wad_base; void W_Shutdown (void); void W_LoadWadFile (char *filename); void W_CleanupName (const char *in, char *out); -lumpinfo_t *W_GetLumpinfo (char *name); -void *W_GetLumpName (char *name); -void *W_SafeGetLumpName (const char *name); -void *W_GetLumpNum (int num); +//lumpinfo_t *W_GetLumpinfo (char *name); +//void *W_GetLumpName (char *name); +void *W_SafeGetLumpName (const char *name, size_t *size); +//void *W_GetLumpNum (int num); void Wads_Flush (void); extern void *wadmutex; diff --git a/engine/client/zqtp.c b/engine/client/zqtp.c index 3cc60b06..40e3255b 100644 --- a/engine/client/zqtp.c +++ b/engine/client/zqtp.c @@ -2132,7 +2132,7 @@ static void TP_EnemyColor_f (void) void TP_NewMap (void) { static char last_map[MAX_QPATH]; - char locname[MAX_OSPATH]; + char locname[MAX_QPATH]; memset (&vars, 0, sizeof(vars)); TP_FindModelNumbers (); @@ -3509,7 +3509,7 @@ qbool TP_CheckSoundTrigger (char *str) { int i, j; int start, length; - char soundname[MAX_OSPATH]; + char soundname[MAX_QPATH]; if (!*str) return false; diff --git a/engine/common/bothdefs.h b/engine/common/bothdefs.h index dd75a553..7fd9789d 100644 --- a/engine/common/bothdefs.h +++ b/engine/common/bothdefs.h @@ -106,7 +106,9 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #if !defined(MINIMAL) && !defined(NPFTE) && !defined(NPQTV) #if defined(_WIN32) && !defined(FTE_SDL) && !defined(WINRT) - #define HAVE_WINSSPI //built in component, checks against windows' root ca database and revocations etc. + #if !defined(_MSC_VER) || _MSC_VER > 1200 + #define HAVE_WINSSPI //built in component, checks against windows' root ca database and revocations etc. + #endif #elif defined(__linux__) || defined(__CYGWIN__) #define HAVE_GNUTLS //currently disabled as it does not validate the server's certificate, beware the mitm attack. #endif @@ -130,8 +132,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #define D3DQUAKE #endif -#if defined(_MSC_VER) //too lazy to fix up the makefile -//#define BOTLIB_STATIC +#if defined(_MSC_VER) && !defined(BOTLIB_STATIC) //too lazy to fix up the makefile +#define BOTLIB_STATIC #endif #ifdef NO_OPENAL @@ -633,7 +635,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. //I'm making my own restrict, because msvc's headers can't cope if I #define restrict to __restrict, and quite possibly other platforms too #if __STDC_VERSION__ >= 199901L #define fte_restrict restrict -#elif defined(_MSC_VER) +#elif defined(_MSC_VER) && _MSC_VER >= 1400 #define fte_restrict __restrict #else #define fte_restrict diff --git a/engine/common/bspfile.h b/engine/common/bspfile.h index 81d065d5..03969124 100644 --- a/engine/common/bspfile.h +++ b/engine/common/bspfile.h @@ -316,64 +316,6 @@ typedef struct //============================================================================ -#ifndef QUAKE_GAME - -// the utilities get to be lazy and just use large static arrays - -extern int nummodels; -extern dmodel_t dmodels[MAX_MAP_MODELS]; - -extern int visdatasize; -extern qbyte dvisdata[MAX_MAP_VISIBILITY]; - -extern int lightdatasize; -extern qbyte dlightdata[MAX_MAP_LIGHTING]; - -extern int texdatasize; -extern qbyte dtexdata[MAX_MAP_MIPTEX]; // (dmiptexlump_t) - -extern int entdatasize; -extern char dentdata[MAX_MAP_ENTSTRING]; - -extern int numleafs; -extern dleaf_t dleafs[MAX_MAP_LEAFS]; - -extern int numplanes; -extern dplane_t dplanes[MAX_MAP_PLANES]; - -extern int numvertexes; -extern dvertex_t dvertexes[MAX_MAP_VERTS]; - -extern int numnodes; -extern dnode_t dnodes[MAX_MAP_NODES]; - -extern int numtexinfo; -extern texinfo_t texinfo[MAX_MAP_TEXINFO]; - -extern int numfaces; -extern dface_t dfaces[MAX_MAP_FACES]; - -extern int numclipnodes; -extern dclipnode_t dclipnodes[MAX_MAP_CLIPNODES]; - -extern int numedges; -extern dedge_t dedges[MAX_MAP_EDGES]; - -extern int nummarksurfaces; -extern unsigned short dmarksurfaces[MAX_MAP_MARKSURFACES]; - -extern int numsurfedges; -extern int dsurfedges[MAX_MAP_SURFEDGES]; - - - -void LoadBSPFile (char *filename); -void WriteBSPFile (char *filename); -void PrintBSPFileSizes (void); - -#endif - - diff --git a/engine/common/cmd.c b/engine/common/cmd.c index c3d3c2d6..df7cfeb8 100644 --- a/engine/common/cmd.c +++ b/engine/common/cmd.c @@ -417,8 +417,9 @@ void Cbuf_ExecuteLevel (int level) { int i; char *text; - char line[1024]; - qboolean quotes, comment; + char line[65536]; + qboolean comment; + int quotes; while (cmd_text[level].buf.cursize) { @@ -437,13 +438,37 @@ void Cbuf_ExecuteLevel (int level) { if (text[i] == '\n') break; - if (text[i] == '"') + + if (quotes) { - quotes++; + if (text[i] == '"') + { + quotes=false; + } + if (text[i] == '\\' && quotes==2) + { + //skip over both chars if its something embedded. + if (text[i+1] == '\"' || text[i+1] == '\\') + { + i++; + continue; + } + } + continue; + } + else if (text[i] == '"') + { //simple quoted string + quotes = true; + continue; + } + else if (text[i] == '\\' && text[i+1] == '\"') + { //escaped quoted string. + quotes = 2; + i++; continue; } - if (comment || (quotes&1)) + if (comment) continue; if (text[i] == '/' && i+1 < cmd_text[level].buf.cursize && text[i+1] == '/') @@ -541,7 +566,7 @@ void Cmd_StuffCmds (void) { if (!com_argv[i]) continue; // NEXTSTEP nulls out -NXHost - if (strchr(com_argv[i], ' ') || strchr(com_argv[i], '\t') || strchr(com_argv[i], '@')) + if (strchr(com_argv[i], ' ') || strchr(com_argv[i], '\t') || strchr(com_argv[i], '@') || strchr(com_argv[i], '/') || strchr(com_argv[i], '\\')) { Q_strcat (text,"\""); Q_strcat (text,com_argv[i]); @@ -593,10 +618,12 @@ void Cmd_Exec_f (void) { char *f, *s; char name[256]; + char buf[512]; flocation_t loc; qboolean untrusted; vfsfile_t *file; size_t l; + unsigned int level; if (Cmd_Argc () != 2) { @@ -636,7 +663,7 @@ void Cmd_Exec_f (void) Con_TPrintf ("couldn't exec %s. check permissions.\n", name); return; } - if (cl_warncmd.ival || developer.ival) + if (cl_warncmd.ival || developer.ival || cvar_watched) Con_TPrintf ("execing %s\n",name); l = VFS_GETLEN(file); @@ -644,7 +671,9 @@ void Cmd_Exec_f (void) f[l] = 0; VFS_READ(file, f, l); VFS_CLOSE(file); + untrusted = !!(loc.search->flags&SPF_UNTRUSTED); + level = ((Cmd_FromGamecode() || untrusted) ? RESTRICT_INSECURE : Cmd_ExecLevel); s = f; if (s[0] == '\xef' && s[1] == '\xbb' && s[2] == '\xbf') @@ -660,7 +689,7 @@ void Cmd_Exec_f (void) int cfgdepth = COM_FDepthFile(name, true); int defdepth = COM_FDepthFile("default.cfg", true); if (defdepth < cfgdepth) - Cbuf_InsertText("exec default.cfg\n", ((Cmd_FromGamecode() || untrusted) ? RESTRICT_INSECURE : Cmd_ExecLevel), false); + Cbuf_InsertText("exec default.cfg\n", level, false); //hack to work around the more insideous hacks of other engines. //namely: vid_restart at the end of config.cfg is evil, and NOT desired in FTE as it generally means any saved video settings are wrong. @@ -676,10 +705,20 @@ void Cmd_Exec_f (void) } f[l] = 0; } + + if (*loc.rawname) + COM_QuotedString(loc.rawname, buf, sizeof(buf), false); + else + COM_QuotedString(va("%s/%s", loc.search->logicalpath, name), buf, sizeof(buf), false); + + if (cvar_watched) + Cbuf_InsertText (va("echo END %s", buf), level, true); // don't execute anything if it was from server (either the stuffcmd/localcmd, or the file) if (!strcmp(name, "default.cfg") && !(Cmd_FromGamecode() || untrusted)) - Cbuf_InsertText ("\ncvar_lockdefaults 1\n", ((Cmd_FromGamecode() || untrusted) ? RESTRICT_INSECURE : Cmd_ExecLevel), false); - Cbuf_InsertText (s, ((Cmd_FromGamecode() || untrusted) ? RESTRICT_INSECURE : Cmd_ExecLevel), true); + Cbuf_InsertText ("\ncvar_lockdefaults 1\n", level, false); + Cbuf_InsertText (s, level, true); + if (cvar_watched) + Cbuf_InsertText (va("echo BEGIN %s", buf), level, true); BZ_Free(f); } @@ -786,7 +825,7 @@ Creates a new command that executes a command string (possibly ; seperated) void Cmd_Alias_f (void) { cmdalias_t *a, *b; - char cmd[1024]; + char cmd[65536]; int i, c; char *s; qboolean multiline; @@ -914,39 +953,41 @@ void Cmd_Alias_f (void) if (multiline) { //fun! MULTILINE ALIASES!!!! a->value = Cmd_ParseMultiline(false); - return; } - + else + { // copy the rest of the command line - cmd[0] = 0; // start out with a null string - c = Cmd_Argc(); - for (i=2 ; i< c ; i++) - { - strcat (cmd, Cmd_Argv(i)); - if (i != c-1) - strcat (cmd, " "); - } - - if (!*cmd) //someone wants to wipe it. let them - { - if (a == cmd_alias) + cmd[0] = 0; // start out with a null string + c = Cmd_Argc(); + for (i=2 ; i< c ; i++) { - cmd_alias = a->next; - Z_Free(a); - return; + strcat (cmd, Cmd_Argv(i)); + if (i != c-1) + strcat (cmd, " "); } - else + + if (!*cmd) //someone wants to wipe it. let them { - for (b = cmd_alias ; b ; b=b->next) + if (a == cmd_alias) { - if (b->next == a) + cmd_alias = a->next; + Z_Free(a); + return; + } + else + { + for (b = cmd_alias ; b ; b=b->next) { - b->next = a->next; - Z_Free(a); - return; + if (b->next == a) + { + b->next = a->next; + Z_Free(a); + return; + } } } } + a->value = Z_StrDup (cmd); } if (Cmd_FromGamecode()) { @@ -958,7 +999,6 @@ void Cmd_Alias_f (void) a->execlevel = 0; //run at users exec level a->restriction = 1; //this is possibly a security risk if the admin also changes execlevel } - a->value = Z_StrDup (cmd); } void Cmd_DeleteAlias(char *name) @@ -1084,10 +1124,10 @@ void Cmd_AliasList_f (void) void Alias_WriteAliases (vfsfile_t *f) { - char *s; + const char *s; cmdalias_t *cmd; int num=0; - char buf[2048]; + char buf[65536]; for (cmd=cmd_alias ; cmd ; cmd=cmd->next) { // if ((cmd->restriction?cmd->restriction:rcon_level.ival) > Cmd_ExecLevel) @@ -1099,8 +1139,11 @@ void Alias_WriteAliases (vfsfile_t *f) s = va("\n//////////////////\n//Aliases\n"); VFS_WRITE(f, s, strlen(s)); } - s = va("alias %s %s\n", cmd->name, COM_QuotedString(cmd->value, buf, sizeof(buf), false)); + s = va("alias %s ", cmd->name); VFS_WRITE(f, s, strlen(s)); + s = COM_QuotedString(cmd->value, buf, sizeof(buf), false); + VFS_WRITE(f, s, strlen(s)); + VFS_WRITE(f, "\n", 1); if (cmd->restriction != 1) //1 is default { s = va("restrict %s %i\n", cmd->name, cmd->restriction); @@ -2296,6 +2339,7 @@ void Cmd_ExecuteString (char *text, int level) if (!level) { + //teamplay macros run at level 0, and are restricted to much fewer commands char *tpcmds[] = { "if", "wait", /*would be nice to include alias in here*/ @@ -2310,6 +2354,13 @@ void Cmd_ExecuteString (char *text, int level) if (!strcmp(cmd_argv[0], tpcmds[level])) { int olev = Cmd_ExecLevel; + if (cmd->restriction && cmd->restriction > 0) + { //warning, these commands would normally be considered to be run at restrict_local, but they're running at a much lower level + //which means that if there's ANY restriction on them then they'll fail. + //this means we have to ignore the default restriction levels and just do it anyway. + Con_TPrintf("'%s' was restricted.\n", cmd_argv[0]); + return; + } Cmd_ExecLevel = 0; if (!cmd->function) Cmd_ForwardToServer (); @@ -3231,11 +3282,82 @@ void Cvar_Inc_f (void) Cvar_SetValue (var, var->value + delta); } +void Cvar_ParseWatches(void) +{ + const char *cvarname; + int i; + cvar_t *var; + for (i=1 ; iflags |= CVAR_WATCHED; + cvar_watched = true; + + i++; + } +} + +void Cvar_Watch_f(void) +{ + char *cvarname = Cmd_Argv(1); + cvar_t *var; + cvar_group_t *grp; + extern cvar_group_t *cvar_groups; + + if (!strcmp(cvarname, "")) + { + for (grp=cvar_groups ; grp ; grp=grp->next) + for (var=grp->cvars ; var ; var=var->next) + { + if (var->flags & CVAR_WATCHED) + Con_Printf("Watching %s\n", var->name); + } + return; + } + else if (!strcmp(cvarname, "off")) + { + cvar_watched = false; + Con_Printf("Disabling all cvar watches\n"); + for (grp=cvar_groups ; grp ; grp=grp->next) + for (var=grp->cvars ; var ; var=var->next) + var->flags &= ~CVAR_WATCHED; + return; + } + else if (!strcmp(cvarname, "all")) + { + cvar_watched = 2; + Con_Printf("Notifying for ALL cvar changes\n"); + return; + } + else + { + var = Cvar_FindVar (cvarname); + if (!var) + { + Con_Printf ("cvar \"%s\" is not defined yet\n", cvarname); + return; + } + var->flags |= CVAR_WATCHED; + cvar_watched |= true; + } +} + void Cmd_WriteConfig_f(void) { vfsfile_t *f; char *filename; - char fname[MAX_OSPATH]; + char fname[MAX_QPATH]; char sysname[MAX_OSPATH]; qboolean all = true; extern cvar_t cfg_save_all; @@ -3263,7 +3385,7 @@ void Cmd_WriteConfig_f(void) { if (strstr(filename, "..")) { - Con_Printf ("Couldn't write config %s\n",filename); + Con_Printf (CON_ERROR "Couldn't write config %s\n",filename); return; } snprintf(fname, sizeof(fname), "configs/%s", filename); @@ -3277,7 +3399,7 @@ void Cmd_WriteConfig_f(void) } if (!f) { - Con_Printf ("Couldn't write config %s\n", sysname); + Con_Printf (CON_ERROR "Couldn't write config %s\n", sysname); return; } @@ -3334,7 +3456,7 @@ void Cmd_Condump_f(void) f = FS_OpenVFS (filename, "wb", FS_GAME); if (!f) { - Con_Printf ("Couldn't write console dump %s\n",filename); + Con_Printf (CON_ERROR "Couldn't write console dump %s\n",filename); return; } @@ -3516,6 +3638,7 @@ void Cmd_Init (void) Cmd_AddCommand ("macrolist", Cmd_MacroList_f); Cmd_AddCommand ("cvarlist", Cvar_List_f); Cmd_AddCommand ("cvarreset", Cvar_Reset_f); + Cmd_AddCommandD ("cvarwatch", Cvar_Watch_f, "Prints a notification when the named cvar is changed. Also displays the start/end of configs. Alternatively, use '-watch foo' on the commandline."); Cmd_AddCommand ("cvar_lockdefaults", Cvar_LockDefaults_f); Cmd_AddCommand ("cvar_purgedefaults", Cvar_PurgeDefaults_f); Cmd_AddCommand ("fs_flush", COM_RefreshFSCache_f); diff --git a/engine/common/common.c b/engine/common/common.c index 5757ccbb..e0f11d29 100644 --- a/engine/common/common.c +++ b/engine/common/common.c @@ -4346,11 +4346,12 @@ void COM_ParsePlusSets (qboolean docbuf) { if (!strcmp(com_argv[i], "+set") || !strcmp(com_argv[i], "+seta")) { + char buf[8192]; Cbuf_AddText(com_argv[i]+1, RESTRICT_LOCAL); Cbuf_AddText(" ", RESTRICT_LOCAL); - Cbuf_AddText(com_argv[i+1], RESTRICT_LOCAL); + Cbuf_AddText(COM_QuotedString(com_argv[i+1], buf, sizeof(buf), false), RESTRICT_LOCAL); Cbuf_AddText(" ", RESTRICT_LOCAL); - Cbuf_AddText(com_argv[i+2], RESTRICT_LOCAL); + Cbuf_AddText(COM_QuotedString(com_argv[i+2], buf, sizeof(buf), false), RESTRICT_LOCAL); Cbuf_AddText("\n", RESTRICT_LOCAL); } } diff --git a/engine/common/common.h b/engine/common/common.h index e236bbb8..6a8e3d3e 100644 --- a/engine/common/common.h +++ b/engine/common/common.h @@ -51,7 +51,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #define qint64_t __int64 #define quint64_t unsigned __int64 #elif defined(_WIN32) - #ifndef _MSC_VER + #if !defined(_MSC_VER) || _MSC_VER < 1300 #define __w64 #endif typedef __int32 __w64 qintptr_t; //add __w64 if you need msvc to shut up about unsafe type conversions @@ -90,6 +90,16 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #endif #endif +#ifdef _MSC_VER + #if _MSC_VER >= 1310 + #define strtoull _strtoui64 + #else + #define strtoull strtoul //hopefully this won't cause too many issues + #define DWORD_PTR DWORD //32bit only + #define ULONG_PTR ULONG + #endif +#endif + typedef unsigned char qbyte; @@ -420,14 +430,16 @@ extern char com_configdir[MAX_OSPATH]; //dir to put cfg_save configs in //qofs_Make is used to 'construct' a variable of qofs_t type. this is so the code can merge two 32bit ints on old systems and use a long long type internally without generating warnings about bit shifts when qofs_t is only 32bit instead. #if 1//defined(__amd64__) || defined(_AMD64_) || __WORDSIZE == 64 - #define FS_64BIT + #if !defined(_MSC_VER) || _MSC_VER > 1200 + #define FS_64BIT + #endif #endif #ifdef FS_64BIT typedef quint64_t qofs_t; //type to use for a file offset #define qofs_Make(low,high) (low | (((qofs_t)(high))<<32)) #define qofs_Low(o) ((o)&0xffffffffu) #define qofs_High(o) ((o)>>32) - #define qofs_Error(o) ((o) == ~0ull) + #define qofs_Error(o) ((o) == ~(quint64_t)0u) #else typedef quint32_t qofs_t; //type to use for a file offset #define qofs_Make(low,high) (low) @@ -481,7 +493,7 @@ char *FS_GetPackageDownloadFilename(flocation_t *loc); qboolean FS_GetPackageDownloadable(const char *package); char *FS_GetPackHashes(char *buffer, int buffersize, qboolean referencedonly); char *FS_GetPackNames(char *buffer, int buffersize, int referencedonly, qboolean ext); -qboolean FS_GenCachedPakName(char *pname, char *crc, char *local, int llen); //returns false if the name is invalid. +qboolean FS_GenCachedPakName(const char *pname, const char *crc, char *local, int llen); //returns false if the name is invalid. void FS_ReferenceControl(unsigned int refflag, unsigned int resetflags); #define COM_FDepthFile(filename,ignorepacks) FS_FLocateFile(filename,FSLF_DONTREFERENCE|FSLF_DEEPONFAILURE|(ignorepacks?0:FSLF_DEPTH_INEXPLICIT), NULL) @@ -602,6 +614,7 @@ typedef struct char *installation; //optional hardcoded commercial name, used for scanning the registry to find existing installs. char *formalname; //the commercial name of the game. you'll get FULLENGINENAME otherwise. char *downloadsurl; //optional installable files (menu) + char *installupd; //which download/updated package to install. char *protocolname; //the name used for purposes of dpmaster char *defaultexec; //execed after cvars are reset, to give game-specific defaults. char *eula; //when running as an installer, the user will be presented with this as a prompt @@ -624,6 +637,7 @@ typedef struct } ftemanifest_t; void FS_Manifest_Free(ftemanifest_t *man); ftemanifest_t *FS_Manifest_Parse(const char *fname, const char *data); +void PM_Shutdown(void); void COM_InitFilesystem (void); //does not set up any gamedirs. qboolean FS_DownloadingPackage(void); diff --git a/engine/common/cvar.c b/engine/common/cvar.c index b6ae1b53..89213c9f 100644 --- a/engine/common/cvar.c +++ b/engine/common/cvar.c @@ -26,6 +26,7 @@ cvar_group_t *cvar_groups; hashtable_t cvar_hash; bucket_t *cvar_buckets[1024]; +int cvar_watched; //cvar_t *cvar_vars; static char *cvar_null_string = ""; @@ -709,6 +710,9 @@ cvar_t *Cvar_SetCore (cvar_t *var, const char *value, qboolean force) if (!var) return NULL; + if ((var->flags & CVAR_WATCHED) || cvar_watched == 2) + Con_Printf("Cvar Set: %s to %s\n", var->name, value); + if ((var->flags & CVAR_NOSET) && !force) { Con_Printf ("variable %s is readonly\n", var->name); @@ -1171,21 +1175,10 @@ qboolean Cvar_Register (cvar_t *variable, const char *groupname) cvar_t *Cvar_Get2(const char *name, const char *defaultvalue, int flags, const char *description, const char *group) { cvar_t *var; - int old; var = Cvar_FindVar(name); if (var) - { - //allow this to change all < cvar_latch values. - //this allows q2 dlls to apply different flags to a cvar without destroying our important ones (like cheat). - old = var->flags; - var->flags = (var->flags & ~(CVAR_NOSET)) | (flags & (CVAR_NOSET|CVAR_SERVERINFO|CVAR_USERINFO|CVAR_ARCHIVE)); - if (old != var->flags) - { - Cvar_Set(var, var->string); - } return var; - } if (!description) description = ""; diff --git a/engine/common/cvar.h b/engine/common/cvar.h index c044fdc6..67dd55f3 100644 --- a/engine/common/cvar.h +++ b/engine/common/cvar.h @@ -143,6 +143,8 @@ typedef struct cvar_group_s #define CVAR_NORESET (1<<20) //cvar is not reset by various things. #define CVAR_TEAMPLAYTAINT (1<<21) //current value contains the evaluation of a teamplay macro. +#define CVAR_WATCHED (1<<22) //report any attempts to change this cvar. + #define CVAR_LASTFLAG CVAR_SHADERSYSTEM #define CVAR_LATCHMASK (CVAR_LATCH|CVAR_RENDERERLATCH|CVAR_SERVEROVERRIDE|CVAR_CHEAT|CVAR_SEMICHEAT) //you're only allowed one of these. @@ -174,6 +176,9 @@ qboolean Cvar_UnsavedArchive(void); void Cvar_Saved(void); void Cvar_ConfigChanged(void); +extern int cvar_watched; //so that cmd.c knows that it should add messages when configs are execed +void Cvar_ParseWatches(void); //parse -watch args + int Cvar_ApplyLatches(int latchflag); //sets vars to their latched values diff --git a/engine/common/fs.c b/engine/common/fs.c index f17d450a..05eaff39 100644 --- a/engine/common/fs.c +++ b/engine/common/fs.c @@ -41,7 +41,7 @@ static void QDECL fs_game_callback(cvar_t *var, char *oldvalue) if (runaway) return; //ignore that runaway = true; - Cmd_ExecuteString(va("gamedir %s\n", COM_QuotedString(var->string, buf, sizeof(buf), false)), Cmd_ExecLevel); + Cmd_ExecuteString(va("gamedir %s\n", COM_QuotedString(var->string, buf, sizeof(buf), false)), RESTRICT_LOCAL); runaway = false; } @@ -206,6 +206,7 @@ void FS_Manifest_Free(ftemanifest_t *man) Z_Free(man->installation); Z_Free(man->formalname); Z_Free(man->downloadsurl); + Z_Free(man->installupd); Z_Free(man->protocolname); Z_Free(man->eula); Z_Free(man->defaultexec); @@ -238,6 +239,8 @@ static ftemanifest_t *FS_Manifest_Clone(ftemanifest_t *oldm) newm->formalname = Z_StrDup(oldm->formalname); if (oldm->downloadsurl) newm->downloadsurl = Z_StrDup(oldm->downloadsurl); + if (oldm->installupd) + newm->installupd = Z_StrDup(oldm->installupd); if (oldm->protocolname) newm->protocolname = Z_StrDup(oldm->protocolname); if (oldm->eula) @@ -282,6 +285,8 @@ void FS_Manifest_Print(ftemanifest_t *man) Con_Printf("name %s\n", COM_QuotedString(man->formalname, buffer, sizeof(buffer), false)); if (man->downloadsurl) Con_Printf("downloadsurl %s\n", COM_QuotedString(man->downloadsurl, buffer, sizeof(buffer), false)); + if (man->installupd) + Con_Printf("install %s\n", COM_QuotedString(man->installupd, buffer, sizeof(buffer), false)); if (man->protocolname) Con_Printf("protocolname %s\n", COM_QuotedString(man->protocolname, buffer, sizeof(buffer), false)); if (man->defaultexec) @@ -511,6 +516,11 @@ static qboolean FS_Manifest_ParseTokens(ftemanifest_t *man) Z_Free(man->downloadsurl); man->downloadsurl = Z_StrDup(Cmd_Argv(1)); } + else if (!Q_strcasecmp(cmd, "install")) + { + Z_Free(man->installupd); + man->installupd = Z_StrDup(Cmd_Argv(1)); + } else if (!Q_strcasecmp(cmd, "protocolname")) { Z_Free(man->protocolname); @@ -671,12 +681,13 @@ COM_Path_f */ static void COM_PathLine(searchpath_t *s) { - Con_Printf(U8("%s")" %s%s%s%s%s%s\n", s->logicalpath, + Con_Printf(U8("%s")" %s%s%s%s%s%s%s\n", s->logicalpath, (s->flags & SPF_REFERENCED)?"^[(ref)\\tip\\Referenced\\desc\\Package will auto-download to clients^]":"", (s->flags & SPF_TEMPORARY)?"^[(temp)\\tip\\Temporary\\desc\\Flushed on map change^]":"", (s->flags & SPF_COPYPROTECTED)?"^[(c)\\tip\\Copyrighted\\desc\\Copy-Protected and is not downloadable^]":"", (s->flags & SPF_EXPLICIT)?"^[(e)\\tip\\Explicit\\desc\\Loaded explicitly by the gamedir^]":"", (s->flags & SPF_UNTRUSTED)?"^[(u)\\tip\\Untrusted\\desc\\Configs and scripts will not be given access to passwords^]":"", + (s->flags & SPF_WRITABLE)?"^[(w)\\tip\\Writable\\desc\\We can probably write here^]":"", (s->handle->GeneratePureCRC)?va("^[(h)\\tip\\Hash: %x^]", s->handle->GeneratePureCRC(s->handle, 0, 0)):""); } void COM_Path_f (void) @@ -2260,110 +2271,134 @@ 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, const char *prefix)) +// +void FS_AddHashedPackage(searchpath_t **oldpaths, const char *parentpath, const char *logicalpaths, searchpath_t *search, unsigned int loadstuff, const char *pakpath, const char *qhash, const char *pakprefix) +{ + searchpathfuncs_t *handle; + searchpath_t *oldp; + char pname[MAX_OSPATH]; + char lname[MAX_OSPATH]; + char lname2[MAX_OSPATH]; + unsigned int keptflags; + flocation_t loc; + int fmt; + char ext[8]; + int ptlen = strlen(parentpath); + + COM_FileExtension(pakpath, ext, sizeof(ext)); + + //figure out which file format its meant to be. + for (fmt = 0; fmt < sizeof(searchpathformats)/sizeof(searchpathformats[0]); fmt++) + { + if (!searchpathformats[fmt].extension || !searchpathformats[fmt].OpenNew)// || !searchpathformats[i].loadscan) + continue; + if ((loadstuff & (1<next) + { + if (strcmp(oldp->prefix, pakprefix?pakprefix:"")) //probably will only happen from typos, but should be correct. + continue; + if (!Q_strcasecmp(oldp->purepath, pakpath)) + break; + if (!Q_strcasecmp(oldp->logicalpath, lname)) + break; + if (!Q_strcasecmp(oldp->logicalpath, lname2)) + break; + } + if (!oldp) + { + //see if we can get an old archive handle from before whatever fs_restart + handle = FS_GetOldPath(oldpaths, lname2, &keptflags); + if (handle) + snprintf (lname, sizeof(lname), "%s", lname2); + else + { + handle = FS_GetOldPath(oldpaths, lname, &keptflags); + + //seems new, load it. + if (!handle) + { + vfsfile_t *vfs = NULL; + if (search) + { + if (search->handle->FindFile(search->handle, &loc, pakpath+ptlen+1, NULL)) + { + vfs = search->handle->OpenVFS(search->handle, &loc, "r"); + snprintf (lname, sizeof(lname), "%s", lname2); + } + else if (search->handle->FindFile(search->handle, &loc, pname+ptlen+1, NULL)) + vfs = search->handle->OpenVFS(search->handle, &loc, "r"); + } + else + { + vfs = FS_OpenVFS(pakpath, "rb", FS_ROOT); + if (vfs) + snprintf (lname, sizeof(lname), "%s", lname2); + else + vfs = FS_OpenVFS(pname, "rb", FS_ROOT); + } + + if (vfs) + handle = searchpathformats[fmt].OpenNew (vfs, lname, pakprefix?pakprefix:""); + if (!handle && vfs) + VFS_CLOSE(vfs); //erk + } + } + + //insert it into our path lists. + if (handle && qhash) + { + int truecrc = handle->GeneratePureCRC(handle, 0, false); + if (truecrc != (int)strtoul(qhash, NULL, 0)) + { + Con_Printf(CON_ERROR "File \"%s\" has hash %#x (required: %s). Please delete it or move it away\n", lname, truecrc, qhash); + handle->ClosePath(handle); + handle = NULL; + } + } + if (handle) + FS_AddPathHandle(oldpaths, pakpath, lname, handle, pakprefix, SPF_COPYPROTECTED|SPF_UNTRUSTED|keptflags, (unsigned int)-1); + } + return; + } + } +} + +static void FS_AddManifestPackages(searchpath_t **oldpaths, const char *purepath, const char *logicalpaths, searchpath_t *search, unsigned int loadstuff) { 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)) + char qhash[16]; + if (!fs_manifest->package[i].path) + continue; + + 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)) { - 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 (strcmp(oldp->prefix, fs_manifest->package[i].prefix?fs_manifest->package[i].prefix:"")) //probably will only happen from typos, but should be correct. - continue; - 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) - snprintf (lname, sizeof(lname), "%s", lname2); - else - { - 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, fs_manifest->package[i].prefix?fs_manifest->package[i].prefix:""); - } - } - 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, fs_manifest->package[i].prefix, SPF_COPYPROTECTED|SPF_UNTRUSTED|keptflags, (unsigned int)-1); - } - } + Q_snprintfz(qhash, sizeof(qhash), "%#x", fs_manifest->package[i].crc); + FS_AddHashedPackage(oldpaths,purepath,logicalpaths,search,loadstuff, fs_manifest->package[i].path,fs_manifest->package[i].crcknown?qhash:NULL,fs_manifest->package[i].prefix); } } } 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); } } + + PM_LoadPackages(oldpaths, purepath, logicalpaths, search, loadstuff, 1000, 0x7fffffff); } static searchpath_t *FS_AddPathHandle(searchpath_t **oldpaths, const char *purepath, const char *logicalpath, searchpathfuncs_t *handle, const char *prefix, unsigned int flags, unsigned int loadstuff) @@ -2609,20 +2639,23 @@ void FS_AddGameDirectory (searchpath_t **oldpaths, const char *puredir, const ch for (search = com_searchpaths; search; search = search->next) { if (!Q_strcasecmp(search->logicalpath, dir)) + { + search->flags |= flags & SPF_WRITABLE; return; //already loaded (base paths?) + } } if (!(flags & SPF_PRIVATE)) { if ((p = strrchr(dir, '/')) != NULL) - strcpy(pubgamedirfile, ++p); + Q_strncpyz(pubgamedirfile, ++p, sizeof(pubgamedirfile)); else - strcpy(pubgamedirfile, dir); + Q_strncpyz(pubgamedirfile, dir, sizeof(pubgamedirfile)); } if ((p = strrchr(dir, '/')) != NULL) - strcpy(gamedirfile, ++p); + Q_strncpyz(gamedirfile, ++p, sizeof(gamedirfile)); else - strcpy(gamedirfile, dir); + Q_strncpyz(gamedirfile, dir, sizeof(gamedirfile)); // // add the directory to the search path @@ -2801,7 +2834,7 @@ void COM_Gamedir (const char *dir, const struct gamepacks *packagespaths) //don't allow leading dots, hidden files are evil. //don't allow complex paths. those are evil too. if (*dir == '.' || !strcmp(dir, ".") || strstr(dir, "..") || strstr(dir, "/") - || strstr(dir, "\\") || strstr(dir, ":") ) + || strstr(dir, "\\") || strstr(dir, ":") || strstr(dir, "\"") ) { Con_Printf ("Gamedir should be a single filename, not a path\n"); return; @@ -2963,9 +2996,9 @@ const gamemode_info_t gamemode_info[] = { {NULL} }; -qboolean FS_GenCachedPakName(char *pname, char *crc, char *local, int llen) +qboolean FS_GenCachedPakName(const char *pname, const char *crc, char *local, int llen) { - char *fn; + const char *fn; char hex[16]; if (strstr(pname, "dlcache")) { @@ -2996,7 +3029,7 @@ qboolean FS_GenCachedPakName(char *pname, char *crc, char *local, int llen) Q_strncpyz(local, pname, min((fn - pname) + 1, llen)); Q_strncatz(local, "dlcache/", llen); Q_strncatz(local, fn, llen); - if (*crc) + if (crc && *crc) { Q_strncatz(local, ".", llen); snprintf(hex, sizeof(hex), "%x", (unsigned int)strtoul(crc, NULL, 0)); @@ -3544,7 +3577,7 @@ void FS_UnloadPackFiles(void) { if (Sys_LockMutex(fs_thread_mutex)) { - FS_ReloadPackFilesFlags(1); + FS_ReloadPackFilesFlags(0); Sys_UnlockMutex(fs_thread_mutex); } } @@ -3572,7 +3605,7 @@ void FS_ReloadPackFiles_f(void) { if (Sys_LockMutex(fs_thread_mutex)) { - if (atoi(Cmd_Argv(1))) + if (*Cmd_Argv(1)) FS_ReloadPackFilesFlags(atoi(Cmd_Argv(1))); else FS_ReloadPackFilesFlags(~0); @@ -3637,7 +3670,7 @@ static INT CALLBACK StupidBrowseCallbackProc(HWND hwnd, UINT uMsg, LPARAM lp, LP case BFFM_VALIDATEFAILEDW: break; //FIXME: validate that the gamedir contains what its meant to case BFFM_SELCHANGED: - if (pSHGetPathFromIDListW((LPITEMIDLIST) lp, szDir)) + if (SHGetPathFromIDListW((LPITEMIDLIST) lp, szDir)) { wchar_t statustxt[MAX_OSPATH]; while((foo = wcschr(szDir, '\\'))) @@ -3682,10 +3715,10 @@ qboolean Sys_DoDirectoryPrompt(char *basepath, size_t basepathsize, const char * bi.lParam = 0;//(LPARAM)poshname; bi.iImage = 0; - il = pSHBrowseForFolderW?pSHBrowseForFolderW(&bi):NULL; + il = SHBrowseForFolderW(&bi); if (il) { - pSHGetPathFromIDListW(il, resultpath); + SHGetPathFromIDListW(il, resultpath); CoTaskMemFree(il); narrowen(basepath, basepathsize, resultpath); if (savedname) @@ -4015,7 +4048,6 @@ static int FS_IdentifyDefaultGame(char *newbase, int sizeof_newbase, qboolean fi //allowed to modify newbasedir if fixedbasedir isn't set static ftemanifest_t *FS_GenerateLegacyManifest(char *newbasedir, int sizeof_newbasedir, qboolean fixedbasedir, int game) { - int i; ftemanifest_t *man; if (gamemode_info[game].manifestfile) @@ -4031,49 +4063,57 @@ static ftemanifest_t *FS_GenerateLegacyManifest(char *newbasedir, int sizeof_new Cmd_TokenizeString(va("name \"%s\"", gamemode_info[game].poshname), false, false); FS_Manifest_ParseTokens(man); } - - i = COM_CheckParm ("-basegame"); - if (i) - { - do - { - Cmd_TokenizeString(va("basegame \"%s\"", com_argv[i+1]), false, false); - FS_Manifest_ParseTokens(man); - - i = COM_CheckNextParm ("-basegame", i); - } - while (i && i < com_argc-1); - } - - i = COM_CheckParm ("-game"); - if (i) - { - do - { - Cmd_TokenizeString(va("gamedir \"%s\"", com_argv[i+1]), false, false); - FS_Manifest_ParseTokens(man); - - i = COM_CheckNextParm ("-game", i); - } - while (i && i < com_argc-1); - } - - i = COM_CheckParm ("+gamedir"); - if (i) - { - do - { - Cmd_TokenizeString(va("gamedir \"%s\"", com_argv[i+1]), false, false); - FS_Manifest_ParseTokens(man); - - i = COM_CheckNextParm ("+gamedir", i); - } - while (i && i < com_argc-1); - } } return man; } +static void FS_AppendManifestGameArguments(ftemanifest_t *man) +{ + int i; + + if (!man) + return; + + i = COM_CheckParm ("-basegame"); + if (i) + { + do + { + Cmd_TokenizeString(va("basegame \"%s\"", com_argv[i+1]), false, false); + FS_Manifest_ParseTokens(man); + + i = COM_CheckNextParm ("-basegame", i); + } + while (i && i < com_argc-1); + } + + i = COM_CheckParm ("-game"); + if (i) + { + do + { + Cmd_TokenizeString(va("gamedir \"%s\"", com_argv[i+1]), false, false); + FS_Manifest_ParseTokens(man); + + i = COM_CheckNextParm ("-game", i); + } + while (i && i < com_argc-1); + } + + i = COM_CheckParm ("+gamedir"); + if (i) + { + do + { + Cmd_TokenizeString(va("gamedir \"%s\"", com_argv[i+1]), false, false); + FS_Manifest_ParseTokens(man); + + i = COM_CheckNextParm ("+gamedir", i); + } + while (i && i < com_argc-1); + } +} + #ifdef WEBCLIENT static char *FS_RelativeURL(char *base, char *file, char *buffer, int bufferlen) { @@ -4739,6 +4779,8 @@ ftemanifest_t *FS_ReadDefaultManifest(char *newbasedir, size_t newbasedirsize, q if (game != -1) man = FS_GenerateLegacyManifest(newbasedir, newbasedirsize, fixedbasedir, game); } + + FS_AppendManifestGameArguments(man); return man; } @@ -5463,6 +5505,9 @@ void COM_InitFilesystem (void) usehome = false; + //assume the home directory is the working directory. + *com_homepath = '\0'; + #if defined(_WIN32) && !defined(FTE_SDL) && !defined(WINRT) { //win32 sucks. HRESULT (WINAPI *dSHGetFolderPathW) (HWND hwndOwner, int nFolder, HANDLE hToken, DWORD dwFlags, wchar_t *pszPath) = NULL; @@ -5565,8 +5610,6 @@ void COM_InitFilesystem (void) Q_snprintfz(com_homepath, sizeof(com_homepath), "%s/.fte/", ev); usehome = true; // always use home on unix unless told not to } - else - *com_homepath = '\0'; #endif com_homepathusable = usehome; diff --git a/engine/common/fs.h b/engine/common/fs.h index a1cb4eda..3ae45841 100644 --- a/engine/common/fs.h +++ b/engine/common/fs.h @@ -66,6 +66,10 @@ int FS_RegisterFileSystemType(void *module, const char *extension, searchpathfun void FS_UnRegisterFileSystemType(int idx); void FS_UnRegisterFileSystemModule(void *module); +void FS_AddHashedPackage(searchpath_t **oldpaths, const char *parent_pure, const char *parent_logical, searchpath_t *search, unsigned int loadstuff, const char *pakpath, const char *qhash, const char *pakprefix); +void PM_LoadPackages(searchpath_t **oldpaths, const char *parent_pure, const char *parent_logical, searchpath_t *search, unsigned int loadstuff, int minpri, int maxpri); +void Menu_Download_Update(void); + void FS_EnumerateKnownGames(qboolean (*callback)(void *usr, ftemanifest_t *man), void *usr); #define SPF_REFERENCED 1 //something has been loaded from this path. should filter out client references... diff --git a/engine/common/fs_win32.c b/engine/common/fs_win32.c index f7b2c6e7..317bbc13 100644 --- a/engine/common/fs_win32.c +++ b/engine/common/fs_win32.c @@ -544,7 +544,9 @@ static unsigned int QDECL VFSW32_FLocate(searchpathfuncs_t *handle, flocation_t if (f) { LARGE_INTEGER wsize; - GetFileSizeEx(f, &wsize); + wsize.LowPart = GetFileSize(f, &wsize.HighPart); + if (wsize.LowPart == INVALID_FILE_SIZE && GetLastError()!=NO_ERROR) + wsize.LowPart = wsize.HighPart = 0; CloseHandle(f); len = qofs_Make(wsize.LowPart, wsize.HighPart); } diff --git a/engine/common/fs_xz.c b/engine/common/fs_xz.c index e2d2a943..b4534784 100644 --- a/engine/common/fs_xz.c +++ b/engine/common/fs_xz.c @@ -16,7 +16,15 @@ #else # include + +#if __STDC_VERSION__ >= 199901L || defined(__GNUC__) # include +#else +#define uint8_t unsigned char +#define uint16_t unsigned short +#define uint32_t unsigned int +#define uint64_t quint64_t +#endif //BEGIN xz.h @@ -38,7 +46,7 @@ # include #else # include -# include +//# include #endif #ifdef __cplusplus diff --git a/engine/common/fs_zip.c b/engine/common/fs_zip.c index b62caa03..b773097c 100644 --- a/engine/common/fs_zip.c +++ b/engine/common/fs_zip.c @@ -1380,6 +1380,7 @@ static qboolean FSZIP_ReadCentralEntry(zipfile_t *zip, qbyte *data, struct zipce extra += 4; } break; +#if !defined(_MSC_VER) || _MSC_VER > 1200 case 0x000a: //NTFS extra field //0+4: reserved //4+2: subtag(must be 1, for times) @@ -1393,6 +1394,7 @@ static qboolean FSZIP_ReadCentralEntry(zipfile_t *zip, qbyte *data, struct zipce Con_Printf("zip: unsupported ntfs subchunk %x\n", extrachunk_tag); extra += extrachunk_len; break; +#endif case 0x5455: if (extra[0] & 1) entry->mtime = LittleU4FromPtr(extra+1); diff --git a/engine/common/log.c b/engine/common/log.c index 0c88648e..3a85126c 100644 --- a/engine/common/log.c +++ b/engine/common/log.c @@ -169,8 +169,8 @@ void Log_String (logtype_t lognum, char *s) if (x > (int)log_rotate_size.value) { - char newf[MAX_OSPATH]; - char oldf[MAX_OSPATH]; + char newf[MAX_QPATH]; + char oldf[MAX_QPATH]; i = log_rotate_files.value; @@ -289,7 +289,7 @@ void Log_Logfile_f (void) /* void SV_Fraglogfile_f (void) { - char name[MAX_OSPATH]; + char name[MAX_QPATH]; int i; if (sv_fraglogfile) diff --git a/engine/common/net_wins.c b/engine/common/net_wins.c index 48a2a0ef..d9e311cf 100644 --- a/engine/common/net_wins.c +++ b/engine/common/net_wins.c @@ -2753,7 +2753,7 @@ ftenet_generic_connection_t *FTENET_Generic_EstablishConnection(int adrfamily, i setsockopt(newsocket, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&_true, sizeof(_true)); #endif -#ifdef _WIN32 +#if defined(_WIN32) && defined(SO_EXCLUSIVEADDRUSE) //win32 is so fucked up setsockopt(newsocket, SOL_SOCKET, SO_EXCLUSIVEADDRUSE, (char *)&_true, sizeof(_true)); #endif @@ -3423,14 +3423,14 @@ handshakeerror: if (payoffs + 8 > st->inlen) break; ullpaylen = - (quint64_t)((unsigned char*)st->inbuffer)[payoffs+0]<<56ull | - (quint64_t)((unsigned char*)st->inbuffer)[payoffs+1]<<48ull | - (quint64_t)((unsigned char*)st->inbuffer)[payoffs+2]<<40ull | - (quint64_t)((unsigned char*)st->inbuffer)[payoffs+3]<<32ull | - (quint64_t)((unsigned char*)st->inbuffer)[payoffs+4]<<24ull | - (quint64_t)((unsigned char*)st->inbuffer)[payoffs+5]<<16ull | - (quint64_t)((unsigned char*)st->inbuffer)[payoffs+6]<< 8ull | - (quint64_t)((unsigned char*)st->inbuffer)[payoffs+7]<< 0ull; + (quint64_t)((unsigned char*)st->inbuffer)[payoffs+0]<<56u | + (quint64_t)((unsigned char*)st->inbuffer)[payoffs+1]<<48u | + (quint64_t)((unsigned char*)st->inbuffer)[payoffs+2]<<40u | + (quint64_t)((unsigned char*)st->inbuffer)[payoffs+3]<<32u | + (quint64_t)((unsigned char*)st->inbuffer)[payoffs+4]<<24u | + (quint64_t)((unsigned char*)st->inbuffer)[payoffs+5]<<16u | + (quint64_t)((unsigned char*)st->inbuffer)[payoffs+6]<< 8u | + (quint64_t)((unsigned char*)st->inbuffer)[payoffs+7]<< 0u; if (ullpaylen < 0x10000) { Con_Printf ("%s: payload size (%"PRIu64") encoded badly\n", NET_AdrToString (adr, sizeof(adr), &st->remoteaddr), ullpaylen); diff --git a/engine/common/plugin.c b/engine/common/plugin.c index 28f718a3..0931789e 100644 --- a/engine/common/plugin.c +++ b/engine/common/plugin.c @@ -1170,7 +1170,7 @@ qintptr_t VARGS Plug_FS_Seek(void *offset, quintptr_t mask, const qintptr_t *arg stream = &pluginstreamarray[handle]; if (stream->type != STREAM_VFS) return -1; - VFS_SEEK(stream->vfs, low | ((unsigned long long)high<<32)); + VFS_SEEK(stream->vfs, low | ((quint64_t)high<<32)); return VFS_TELL(stream->vfs); } diff --git a/engine/common/pmove.c b/engine/common/pmove.c index 9e84e9d1..eedd64f5 100644 --- a/engine/common/pmove.c +++ b/engine/common/pmove.c @@ -867,7 +867,7 @@ void PM_CategorizePosition (void) // VectorMA(point, 48, forward, point); // trace = PM_TraceLine(pmove.origin, point); // trace.fraction = 1; - if (1)//trace.fraction == 1) +// if (1)//trace.fraction == 1) { //getting desparate VectorMA(pmove.origin, -48, up, point); VectorMA(point, 48, forward, point); diff --git a/engine/common/pr_bgcmd.c b/engine/common/pr_bgcmd.c index 4fa82feb..a82c2cc5 100644 --- a/engine/common/pr_bgcmd.c +++ b/engine/common/pr_bgcmd.c @@ -1751,9 +1751,9 @@ void pf_hash_purge(void) //restart command was used. revert to the state at the typedef struct { char name[256]; char *data; - int bufferlen; - int len; - int ofs; + size_t bufferlen; + size_t len; + size_t ofs; int accessmode; pubprogfuncs_t *prinst; } pf_fopen_files_t; @@ -2010,6 +2010,13 @@ void QCBUILTIN PF_fgets (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals max = o + sizeof(pr_string_temp)-1; s = pf_fopen_files[fnum].data+pf_fopen_files[fnum].ofs; eof = pf_fopen_files[fnum].data+pf_fopen_files[fnum].len; + + if (s >= eof) + { + G_INT(OFS_RETURN) = 0; //EOF + return; + } + while(s < eof) { c = *s++; @@ -2036,14 +2043,42 @@ void QCBUILTIN PF_fgets (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals pf_fopen_files[fnum].ofs = s - pf_fopen_files[fnum].data; - if (!pr_string_temp[0] && s >= eof) - G_INT(OFS_RETURN) = 0; //EOF - else - RETURN_TSTRING(pr_string_temp); + RETURN_TSTRING(pr_string_temp); } } -static int PF_fwrite_internal (pubprogfuncs_t *prinst, int fnum, char *msg, int len) +//ensures that the buffer is at least big enough. +static qboolean PF_fresizebuffer_internal (pf_fopen_files_t *f, size_t newlen) +{ + switch(f->accessmode) + { + default: + return false; + case FRIK_FILE_MMAP_RW: + //mmap cannot change the buffer size/allocation. + if (newlen > f->bufferlen) + return false; + break; + case FRIK_FILE_APPEND: + case FRIK_FILE_WRITE: + if (f->bufferlen < newlen) + { + char *newbuf; + size_t newbuflen = max(newlen, newlen*2+1024); + newbuf = BZF_Malloc(newbuflen); + if (!newbuf) + return false; + memcpy(newbuf, f->data, f->bufferlen); + memset(newbuf+f->bufferlen, 0, newbuflen - f->bufferlen); + BZ_Free(f->data); + f->data = newbuf; + f->bufferlen = newbuflen; + } + break; + } + return true; +} +static int PF_fwrite_internal (pubprogfuncs_t *prinst, int fnum, char *msg, size_t len) { if (fnum < 0 || fnum >= MAX_QC_FILES) { @@ -2063,22 +2098,21 @@ static int PF_fwrite_internal (pubprogfuncs_t *prinst, int fnum, char *msg, int return 0; //this just isn't ours. } + if (pf_fopen_files[fnum].ofs + len < pf_fopen_files[fnum].ofs) + { + PF_Warningf(prinst, "PF_fwrite: size overflow\n"); + return 0; + } + switch(pf_fopen_files[fnum].accessmode) { default: return 0; case FRIK_FILE_APPEND: case FRIK_FILE_WRITE: - //UTF-8-FIXME: de-modify utf-8 - if (pf_fopen_files[fnum].bufferlen < pf_fopen_files[fnum].ofs + len) - { - char *newbuf; - pf_fopen_files[fnum].bufferlen = pf_fopen_files[fnum].bufferlen*2 + len; - newbuf = BZF_Malloc(pf_fopen_files[fnum].bufferlen); - memcpy(newbuf, pf_fopen_files[fnum].data, pf_fopen_files[fnum].len); - BZ_Free(pf_fopen_files[fnum].data); - pf_fopen_files[fnum].data = newbuf; - } + case FRIK_FILE_MMAP_RW: + PF_fresizebuffer_internal(&pf_fopen_files[fnum], pf_fopen_files[fnum].ofs+len); + len = min(len, pf_fopen_files[fnum].bufferlen-pf_fopen_files[fnum].ofs); memcpy(pf_fopen_files[fnum].data + pf_fopen_files[fnum].ofs, msg, len); if (pf_fopen_files[fnum].len < pf_fopen_files[fnum].ofs + len) @@ -2088,7 +2122,7 @@ static int PF_fwrite_internal (pubprogfuncs_t *prinst, int fnum, char *msg, int } } -static int PF_fread_internal (pubprogfuncs_t *prinst, int fnum, char *msg, int len) +static int PF_fread_internal (pubprogfuncs_t *prinst, int fnum, char *msg, size_t len) { if (fnum < 0 || fnum >= MAX_QC_FILES) { @@ -2158,6 +2192,60 @@ void QCBUILTIN PF_fread (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals G_INT(OFS_PARM1) = PF_fread_internal (prinst, fnum, prinst->stringtable + ptr, size); } +void QCBUILTIN PF_fseek (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) +{ + int fnum = G_FLOAT(OFS_PARM0) - FIRST_QC_FILE_INDEX; + G_INT(OFS_PARM1) = 0; + if (fnum < 0 || fnum >= MAX_QC_FILES) + { + PF_Warningf(prinst, "PF_fread: File out of range\n"); + return; //out of range + } + if (!pf_fopen_files[fnum].data) + { + PF_Warningf(prinst, "PF_fread: File is not open\n"); + return; //not open + } + if (pf_fopen_files[fnum].prinst != prinst) + { + PF_Warningf(prinst, "PF_fread: File is from wrong instance\n"); + return; //this just isn't ours. + } + + G_INT(OFS_PARM1) = pf_fopen_files[fnum].ofs; + if (prinst->callargc>1 && G_INT(OFS_PARM0) >= 0) + { + pf_fopen_files[fnum].ofs = G_INT(OFS_PARM0); + } +} +void QCBUILTIN PF_fsize (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) +{ + int fnum = G_FLOAT(OFS_PARM0) - FIRST_QC_FILE_INDEX; + G_INT(OFS_PARM1) = 0; + if (fnum < 0 || fnum >= MAX_QC_FILES) + { + PF_Warningf(prinst, "PF_fsize: File out of range\n"); + return; //out of range + } + if (!pf_fopen_files[fnum].data) + { + PF_Warningf(prinst, "PF_fsize: File is not open\n"); + return; //not open + } + if (pf_fopen_files[fnum].prinst != prinst) + { + PF_Warningf(prinst, "PF_fsize: File is from wrong instance\n"); + return; //this just isn't ours. + } + + G_INT(OFS_PARM1) = pf_fopen_files[fnum].len; + if (prinst->callargc>1 && G_INT(OFS_PARM0) >= 0) + { + size_t newlen = G_INT(OFS_PARM0); + PF_fresizebuffer_internal(&pf_fopen_files[fnum], newlen); + pf_fopen_files[fnum].len = min(pf_fopen_files[fnum].bufferlen, newlen); + } +} void PF_fcloseall (pubprogfuncs_t *prinst) { diff --git a/engine/common/pr_common.h b/engine/common/pr_common.h index 445d0d5d..644bb574 100644 --- a/engine/common/pr_common.h +++ b/engine/common/pr_common.h @@ -144,6 +144,8 @@ void QCBUILTIN PF_fputs (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals void QCBUILTIN PF_fgets (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals); void QCBUILTIN PF_fwrite (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals); void QCBUILTIN PF_fread (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals); +void QCBUILTIN PF_fseek (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals); +void QCBUILTIN PF_fsize (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals); void QCBUILTIN PF_normalize (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals); void QCBUILTIN PF_vlen (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals); void QCBUILTIN PF_vhlen (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals); @@ -527,7 +529,7 @@ pbool QDECL ED_CanFree (edict_t *ed); #define MOVETYPE_6DOF 30 // flightsim mode #define MOVETYPE_WALLWALK 31 // walks up walls and along ceilings #define MOVETYPE_PHYSICS 32 -#define MOVETYPE_FLY_WORLDONLY 33 +#define MOVETYPE_FLY_WORLDONLY 33 //fly that collides only with world, keeping spectators within the world but free to pass through doors. avoids pvs issues with q3map2. // edict->solid values #define SOLID_NOT 0 // no interaction with other objects diff --git a/engine/common/q1bsp.c b/engine/common/q1bsp.c index 62838b65..42ec9e5b 100644 --- a/engine/common/q1bsp.c +++ b/engine/common/q1bsp.c @@ -507,7 +507,7 @@ nextbrush: } static void Q1BSP_InsertBrush(mnode_t *node, mbrush_t *brush, vec3_t bmins, vec3_t bmaxs) { - vec3_t near, far; + vec3_t nearp, farp; float nd, fd; int i; while(1) @@ -523,18 +523,18 @@ static void Q1BSP_InsertBrush(mnode_t *node, mbrush_t *brush, vec3_t bmins, vec3 { if (node->plane->normal[i] > 0) { - near[i] = bmins[i]; - far[i] = bmaxs[i]; + nearp[i] = bmins[i]; + farp[i] = bmaxs[i]; } else { - near[i] = bmaxs[i]; - far[i] = bmins[i]; + nearp[i] = bmaxs[i]; + farp[i] = bmins[i]; } } - nd = DotProduct(node->plane->normal, near) - node->plane->dist; - fd = DotProduct(node->plane->normal, far) - node->plane->dist; + nd = DotProduct(node->plane->normal, nearp) - node->plane->dist; + fd = DotProduct(node->plane->normal, farp) - node->plane->dist; /*if its fully on either side, continue walking*/ if (nd < 0 && fd < 0) diff --git a/engine/common/q3common.c b/engine/common/q3common.c index ac687687..a7621968 100644 --- a/engine/common/q3common.c +++ b/engine/common/q3common.c @@ -10,14 +10,14 @@ typedef struct { char name[256]; char *data; int bufferlen; - int len; - int ofs; + qofs_t len; + qofs_t ofs; int accessmode; int owner; } vm_fopen_files_t; vm_fopen_files_t vm_fopen_files[MAX_VM_FILES]; //FIXME: why does this not use the VFS system? -int VM_fopen (char *name, int *handle, int fmode, int owner) +qofs_t VM_fopen (const char *name, int *handle, int fmode, int owner) { int i; size_t insize; @@ -128,7 +128,7 @@ int VM_FRead (char *dest, int quantity, int fnum, int owner) return quantity; } -int VM_FWrite (char *dest, int quantity, int fnum, int owner) +int VM_FWrite (const char *dest, int quantity, int fnum, int owner) { /* int fnum = G_FLOAT(OFS_PARM0); @@ -160,15 +160,15 @@ int VM_FWrite (char *dest, int quantity, int fnum, int owner) */ return 0; } -void VM_FSeek (int fnum, int offset, int seektype, int owner) +qboolean VM_FSeek (int fnum, qofs_t offset, int seektype, int owner) { fnum--; if (fnum < 0 || fnum >= MAX_VM_FILES) - return; //out of range + return false; //out of range if (vm_fopen_files[fnum].owner != owner) - return; //cgs? + return false; //cgs? if (!vm_fopen_files[fnum].data) - return; //not open + return false; //not open switch(seektype) { @@ -182,13 +182,14 @@ void VM_FSeek (int fnum, int offset, int seektype, int owner) //offset = 0 + offset; break; } - if (offset < 0) - offset = 0; +// if (offset < 0) +// offset = 0; if (offset > vm_fopen_files[fnum].len) offset = vm_fopen_files[fnum].len; vm_fopen_files[fnum].ofs = offset; + return true; } -int VM_FTell (int fnum, int owner) +qofs_t VM_FTell (int fnum, int owner) { fnum--; if (fnum < 0 || fnum >= MAX_VM_FILES) @@ -318,7 +319,7 @@ static int QDECL VMEnumMods(const char *match, qofs_t size, time_t modtime, void return true; } -int VM_GetFileList(char *path, char *ext, char *output, int buffersize) +int VM_GetFileList(const char *path, const char *ext, char *output, int buffersize) { vmsearch_t vms; vms.initialbuffer = vms.buffer = output; diff --git a/engine/common/sys.h b/engine/common/sys.h index de4625ee..4d98f2a5 100644 --- a/engine/common/sys.h +++ b/engine/common/sys.h @@ -168,15 +168,23 @@ qboolean NPQTV_Sys_Startup(int argc, char *argv[]); void NPQTV_Sys_MainLoop(void); #endif +#define UPD_UNSUPPORTED -1 +#define UPD_REVERT 0 +#define UPD_OFF 1 +#define UPD_STABLE 2 +#define UPD_TESTING 3 + #if defined(WEBCLIENT) && defined(_WIN32) int StartLocalServer(int close); #define HAVEAUTOUPDATE int Sys_GetAutoUpdateSetting(void); void Sys_SetAutoUpdateSetting(int newval); +void Sys_SetUpdatedBinary(const char *fname); #else -#define Sys_GetAutoUpdateSetting() -1 +#define Sys_GetAutoUpdateSetting() UPD_UNSUPPORTED #define Sys_SetAutoUpdateSetting(n) +#define Sys_SetUpdatedBinary(n) #endif void Sys_Init (void); diff --git a/engine/common/sys_win_threads.c b/engine/common/sys_win_threads.c index 2be82f8a..f62c4049 100644 --- a/engine/common/sys_win_threads.c +++ b/engine/common/sys_win_threads.c @@ -25,7 +25,9 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include #if (defined(_DEBUG) || defined(DEBUG)) && !defined(NPFTE) +#if !defined(_MSC_VER) || _MSC_VER > 1200 #define CATCHCRASH +#endif #ifdef _MSC_VER #define MSVC_SEH DWORD CrashExceptionHandler (qboolean iswatchdog, DWORD exceptionCode, LPEXCEPTION_POINTERS exceptionInfo); diff --git a/engine/common/vm.h b/engine/common/vm.h index e0875e95..3084d2d7 100644 --- a/engine/common/vm.h +++ b/engine/common/vm.h @@ -88,14 +88,14 @@ void Script_Get_File_And_Line(int handle, char *filename, int *line); #define VM_FS_WRITE 1 #define VM_FS_APPEND 2 #define VM_FS_APPEND2 3 //I don't know, don't ask me. look at q3 source -int VM_fopen (char *name, int *handle, int fmode, int owner); +qofs_t VM_fopen (const char *name, int *handle, int fmode, int owner); int VM_FRead (char *dest, int quantity, int fnum, int owner); -int VM_FWrite (char *dest, int quantity, int fnum, int owner); -void VM_FSeek (int fnum, int offset, int seektype, int owner); -int VM_FTell (int fnum, int owner); +int VM_FWrite (const char *dest, int quantity, int fnum, int owner); +qboolean VM_FSeek (int fnum, qofs_t offset, int seektype, int owner); +qofs_t VM_FTell (int fnum, int owner); void VM_fclose (int fnum, int owner); void VM_fcloseall (int owner); -int VM_GetFileList(char *path, char *ext, char *output, int buffersize); +int VM_GetFileList(const char *path, const char *ext, char *output, int buffersize); #ifdef VM_CG void CG_Stop (void); diff --git a/engine/dotnet2005/ftequake.sln b/engine/dotnet2005/ftequake.sln index c36a05fd..fb571455 100644 --- a/engine/dotnet2005/ftequake.sln +++ b/engine/dotnet2005/ftequake.sln @@ -716,7 +716,6 @@ Global {75D91BDE-CC30-4C53-BF33-5F69EF13A61B}.GLRelease|Win32.Build.0 = Release|Win32 {75D91BDE-CC30-4C53-BF33-5F69EF13A61B}.GLRelease|x64.ActiveCfg = Release|Win32 {75D91BDE-CC30-4C53-BF33-5F69EF13A61B}.MDebug|Win32.ActiveCfg = Debug|Win32 - {75D91BDE-CC30-4C53-BF33-5F69EF13A61B}.MDebug|Win32.Build.0 = Debug|Win32 {75D91BDE-CC30-4C53-BF33-5F69EF13A61B}.MDebug|x64.ActiveCfg = Debug|Win32 {75D91BDE-CC30-4C53-BF33-5F69EF13A61B}.MinGLDebug|Win32.ActiveCfg = Debug|Win32 {75D91BDE-CC30-4C53-BF33-5F69EF13A61B}.MinGLDebug|x64.ActiveCfg = Debug|Win32 diff --git a/engine/dotnet2005/ftequake.vcproj b/engine/dotnet2005/ftequake.vcproj index bbe65d4f..4c9345b2 100644 --- a/engine/dotnet2005/ftequake.vcproj +++ b/engine/dotnet2005/ftequake.vcproj @@ -1461,7 +1461,7 @@ $(OUTDIR)\$(InputName).spp - ..\gas2masm\debug\gas2masm < $(OUTDIR)\$(InputName).spp > $(OUTDIR)\$(InputName).asm - ml /c /Cp /coff /Fo$(OUTDIR)\$(InputName).obj /Zm /Zi $(OUTDIR)\$(InputName).asm - del $(OUTDIR)\$(InputName).spp - -# End Custom Build - !ELSEIF "$(CFG)" == "npqtv - Win32 Debug" -# Begin Custom Build -OutDir=.\npqtv___Win32_Debug -InputPath=..\common\math.s -InputName=math - -"$(OUTDIR)\$(InputName).obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" - cl /EP /I ..\common $(InputPath) > $(OUTDIR)\$(InputName).spp - ..\gas2masm\debug\gas2masm < $(OUTDIR)\$(InputName).spp > $(OUTDIR)\$(InputName).asm - ml /c /Cp /coff /Fo$(OUTDIR)\$(InputName).obj /Zm /Zi $(OUTDIR)\$(InputName).asm - del $(OUTDIR)\$(InputName).spp - -# End Custom Build +# SUBTRACT CPP /YX /Yc /Yu !ENDIF # End Source File # Begin Source File -SOURCE=..\client\sys_wina.s +SOURCE=..\client\sys_plugfte.c !IF "$(CFG)" == "npqtv - Win32 Release" -# Begin Custom Build -OutDir=.\Release -InputPath=..\client\sys_wina.s -InputName=sys_wina - -"$(OUTDIR)\$(InputName).obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" - cl /EP /I ..\common $(InputPath) > $(OUTDIR)\$(InputName).spp - ..\gas2masm\debug\gas2masm < $(OUTDIR)\$(InputName).spp > $(OUTDIR)\$(InputName).asm - ml /c /Cp /coff /Fo$(OUTDIR)\$(InputName).obj /Zm /Zi $(OUTDIR)\$(InputName).asm - del $(OUTDIR)\$(InputName).spp - -# End Custom Build - !ELSEIF "$(CFG)" == "npqtv - Win32 Debug" -# Begin Custom Build -OutDir=.\npqtv___Win32_Debug -InputPath=..\client\sys_wina.s -InputName=sys_wina - -"$(OUTDIR)\$(InputName).obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" - cl /EP /I ..\common $(InputPath) > $(OUTDIR)\$(InputName).spp - ..\gas2masm\debug\gas2masm < $(OUTDIR)\$(InputName).spp > $(OUTDIR)\$(InputName).asm - ml /c /Cp /coff /Fo$(OUTDIR)\$(InputName).obj /Zm /Zi $(OUTDIR)\$(InputName).asm - del $(OUTDIR)\$(InputName).spp - -# End Custom Build +# SUBTRACT CPP /YX /Yc /Yu !ENDIF # End Source File # Begin Source File -SOURCE=..\server\worlda.s - -!IF "$(CFG)" == "npqtv - Win32 Release" - -# Begin Custom Build -OutDir=.\Release -InputPath=..\server\worlda.s -InputName=worlda - -"$(OUTDIR)\$(InputName).obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" - cl /EP /I ..\common $(InputPath) > $(OUTDIR)\$(InputName).spp - ..\gas2masm\debug\gas2masm < $(OUTDIR)\$(InputName).spp > $(OUTDIR)\$(InputName).asm - ml /c /Cp /coff /Fo$(OUTDIR)\$(InputName).obj /Zm /Zi $(OUTDIR)\$(InputName).asm - del $(OUTDIR)\$(InputName).spp - -# End Custom Build - -!ELSEIF "$(CFG)" == "npqtv - Win32 Debug" - -# Begin Custom Build -OutDir=.\npqtv___Win32_Debug -InputPath=..\server\worlda.s -InputName=worlda - -"$(OUTDIR)\$(InputName).obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" - cl /EP /I ..\common $(InputPath) > $(OUTDIR)\$(InputName).spp - ..\gas2masm\debug\gas2masm < $(OUTDIR)\$(InputName).spp > $(OUTDIR)\$(InputName).asm - ml /c /Cp /coff /Fo$(OUTDIR)\$(InputName).obj /Zm /Zi $(OUTDIR)\$(InputName).asm - del $(OUTDIR)\$(InputName).spp - -# End Custom Build - -!ENDIF - -# End Source File -# End Group -# Begin Group "server" - -# PROP Default_Filter "" -# Begin Source File - -SOURCE=..\server\net_preparse.c - -!IF "$(CFG)" == "npqtv - Win32 Release" - -!ELSEIF "$(CFG)" == "npqtv - Win32 Debug" - -# ADD CPP /Yu"qwsvdef.h" - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\server\pr_cmds.c - -!IF "$(CFG)" == "npqtv - Win32 Release" - -!ELSEIF "$(CFG)" == "npqtv - Win32 Debug" - -# ADD CPP /Yu"qwsvdef.h" - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\server\pr_q1qvm.c - -!IF "$(CFG)" == "npqtv - Win32 Release" - -!ELSEIF "$(CFG)" == "npqtv - Win32 Debug" - -# ADD CPP /Yu"qwsvdef.h" - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\server\savegame.c - -!IF "$(CFG)" == "npqtv - Win32 Release" - -!ELSEIF "$(CFG)" == "npqtv - Win32 Debug" - -# ADD CPP /Yu"qwsvdef.h" - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\server\sv_ccmds.c - -!IF "$(CFG)" == "npqtv - Win32 Release" - -!ELSEIF "$(CFG)" == "npqtv - Win32 Debug" - -# ADD CPP /Yu"qwsvdef.h" - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\server\sv_chat.c - -!IF "$(CFG)" == "npqtv - Win32 Release" - -!ELSEIF "$(CFG)" == "npqtv - Win32 Debug" - -# ADD CPP /Yu"qwsvdef.h" - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\server\sv_demo.c - -!IF "$(CFG)" == "npqtv - Win32 Release" - -!ELSEIF "$(CFG)" == "npqtv - Win32 Debug" - -# ADD CPP /Yu"qwsvdef.h" - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\server\sv_ents.c - -!IF "$(CFG)" == "npqtv - Win32 Release" - -!ELSEIF "$(CFG)" == "npqtv - Win32 Debug" - -# ADD CPP /Yu"qwsvdef.h" - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\server\sv_init.c - -!IF "$(CFG)" == "npqtv - Win32 Release" - -!ELSEIF "$(CFG)" == "npqtv - Win32 Debug" - -# ADD CPP /Yu"qwsvdef.h" - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\server\sv_main.c - -!IF "$(CFG)" == "npqtv - Win32 Release" - -!ELSEIF "$(CFG)" == "npqtv - Win32 Debug" - -# ADD CPP /Yu"qwsvdef.h" - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\server\sv_master.c - -!IF "$(CFG)" == "npqtv - Win32 Release" - -!ELSEIF "$(CFG)" == "npqtv - Win32 Debug" - -# ADD CPP /Yu"qwsvdef.h" - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\server\sv_move.c - -!IF "$(CFG)" == "npqtv - Win32 Release" - -!ELSEIF "$(CFG)" == "npqtv - Win32 Debug" - -# ADD CPP /Yu"qwsvdef.h" - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\server\sv_mvd.c - -!IF "$(CFG)" == "npqtv - Win32 Release" - -!ELSEIF "$(CFG)" == "npqtv - Win32 Debug" - -# ADD CPP /Yu"qwsvdef.h" - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\server\sv_nchan.c - -!IF "$(CFG)" == "npqtv - Win32 Release" - -!ELSEIF "$(CFG)" == "npqtv - Win32 Debug" - -# ADD CPP /Yu"qwsvdef.h" - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\server\sv_phys.c - -!IF "$(CFG)" == "npqtv - Win32 Release" - -!ELSEIF "$(CFG)" == "npqtv - Win32 Debug" - -# ADD CPP /Yu"qwsvdef.h" - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\server\sv_rankin.c - -!IF "$(CFG)" == "npqtv - Win32 Release" - -!ELSEIF "$(CFG)" == "npqtv - Win32 Debug" - -# ADD CPP /Yu"qwsvdef.h" - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\server\sv_send.c - -!IF "$(CFG)" == "npqtv - Win32 Release" - -!ELSEIF "$(CFG)" == "npqtv - Win32 Debug" - -# ADD CPP /Yu"qwsvdef.h" - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\server\sv_user.c - -!IF "$(CFG)" == "npqtv - Win32 Release" - -!ELSEIF "$(CFG)" == "npqtv - Win32 Debug" - -# ADD CPP /Yu"qwsvdef.h" - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\server\svhl_game.c - -!IF "$(CFG)" == "npqtv - Win32 Release" - -!ELSEIF "$(CFG)" == "npqtv - Win32 Debug" - -# ADD CPP /Yu"qwsvdef.h" - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\server\svhl_phys.c - -!IF "$(CFG)" == "npqtv - Win32 Release" - -!ELSEIF "$(CFG)" == "npqtv - Win32 Debug" - -# ADD CPP /Yu"qwsvdef.h" - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\server\svhl_world.c - -!IF "$(CFG)" == "npqtv - Win32 Release" - -!ELSEIF "$(CFG)" == "npqtv - Win32 Debug" - -# ADD CPP /Yu"qwsvdef.h" - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\server\svmodel.c - -!IF "$(CFG)" == "npqtv - Win32 Release" - -!ELSEIF "$(CFG)" == "npqtv - Win32 Debug" - -# ADD CPP /Yu"qwsvdef.h" - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\server\svq2_ents.c - -!IF "$(CFG)" == "npqtv - Win32 Release" - -!ELSEIF "$(CFG)" == "npqtv - Win32 Debug" - -# ADD CPP /Yu"qwsvdef.h" - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\server\svq2_game.c - -!IF "$(CFG)" == "npqtv - Win32 Release" - -!ELSEIF "$(CFG)" == "npqtv - Win32 Debug" - -# ADD CPP /Yu"qwsvdef.h" - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\server\svq3_game.c - -!IF "$(CFG)" == "npqtv - Win32 Release" - -!ELSEIF "$(CFG)" == "npqtv - Win32 Debug" - -# ADD CPP /Yu"qwsvdef.h" - -!ENDIF - -# End Source File -# Begin Source File - -SOURCE=..\server\world.c - -!IF "$(CFG)" == "npqtv - Win32 Release" - -!ELSEIF "$(CFG)" == "npqtv - Win32 Debug" - -# ADD CPP /Yu"qwsvdef.h" - -!ENDIF - -# End Source File -# End Group -# Begin Source File - -SOURCE=.\npapi.def -# End Source File -# Begin Source File - -SOURCE=..\client\sys_npqtv.c - -!IF "$(CFG)" == "npqtv - Win32 Release" - -!ELSEIF "$(CFG)" == "npqtv - Win32 Debug" - -# ADD CPP /Yu - -!ENDIF - +SOURCE=..\common\sys_win_threads.c # End Source File # End Group # Begin Group "Header Files" @@ -1040,5 +155,9 @@ SOURCE=..\client\sys_npqtv.c SOURCE=.\npplug.rc # End Source File # End Group +# Begin Source File + +SOURCE=.\npapi.def +# End Source File # End Target # End Project diff --git a/engine/gl/gl_font.c b/engine/gl/gl_font.c index 31ddf3b9..b9113961 100644 --- a/engine/gl/gl_font.c +++ b/engine/gl/gl_font.c @@ -613,12 +613,13 @@ static struct charcache_s *Font_TryLoadGlyph(font_t *f, CHARIDXTYPE charidx) int x, y; unsigned int stepx, stepy; unsigned int srcx, srcy; + size_t lumpsize = 0; if (charidx-0xe100 >= sizeof(imgs)/sizeof(imgs[0])) wadimg = NULL; else - wadimg = W_SafeGetLumpName(imgs[charidx-0xe100]); - if (wadimg) + wadimg = W_SafeGetLumpName(imgs[charidx-0xe100], &lumpsize); + if (wadimg && lumpsize == 8+wadimg->height*wadimg->width) { nh = wadimg->height; nw = wadimg->width; @@ -964,7 +965,7 @@ static texid_t Font_LoadReplacementConchars(void) } static texid_t Font_LoadQuakeConchars(void) { - unsigned int i; + /*unsigned int i; qbyte *lump; lump = W_SafeGetLumpName ("conchars"); if (lump) @@ -981,7 +982,7 @@ static texid_t Font_LoadQuakeConchars(void) lump[i] = 255; // proper transparent color return R_LoadTexture8("charset", 128, 128, (void*)lump, IF_LOADNOW|IF_UIPIC|IF_NOMIPMAP|IF_NOGAMMA, 1); - } + }*/ return r_nulltex; } @@ -1330,8 +1331,9 @@ struct font_s *Font_LoadFont(float vheight, const char *fontfilename) { unsigned int *img; int x, y; - unsigned char *w = W_SafeGetLumpName(fontfilename+4); - if (!w) + size_t lumpsize; + unsigned char *w = W_SafeGetLumpName(fontfilename+4, &lumpsize); + if (!w || lumpsize != 5) { Z_Free(f); return NULL; diff --git a/engine/gl/gl_rlight.c b/engine/gl/gl_rlight.c index 46f549b6..ad1230c4 100644 --- a/engine/gl/gl_rlight.c +++ b/engine/gl/gl_rlight.c @@ -878,6 +878,10 @@ qboolean R_ImportRTLights(char *entlump) return okay; } } + else if (entnum == 0 && !strcmp("lightmapbright", key)) + { + //tenebrae compat. this overrides r_shadow_realtime_world_lightmap + } } if (!islight) continue; @@ -983,7 +987,23 @@ qboolean R_LoadRTLights(void) while(*file == ' ' || *file == '\t') file++; - if (*file == '!') + if (*file == '#') + { + file++; + while(*file == ' ' || *file == '\t') + file++; + file = COM_Parse(file); + if (!Q_strcasecmp(com_token, "lightmaps")) + { + file = COM_Parse(file); + //foo = atoi(com_token); + } + else + Con_DPrintf("Unknown directive: %s\n", com_token); + file = end+1; + continue; + } + else if (*file == '!') { flags = LFLAG_NOSHADOWS; file++; @@ -1110,6 +1130,9 @@ void R_SaveRTLights_f(void) Con_Printf("couldn't open %s\n", fname); return; } + +// VFS_PUTS(f, va("#lightmap %f\n", foo)); + for (light = cl_dlights+rtlights_first, i=rtlights_first; idie) diff --git a/engine/gl/gl_shader.c b/engine/gl/gl_shader.c index df24c908..8b93eeec 100644 --- a/engine/gl/gl_shader.c +++ b/engine/gl/gl_shader.c @@ -221,6 +221,16 @@ enum shaderparsemode_e static struct { enum shaderparsemode_e mode; + + qboolean forceprogramify; + //for dpwater compat, used to generate a program + float reflectmin; + float reflectmax; + float reflectfactor; + float refractfactor; + vec3_t refractcolour; + vec3_t reflectcolour; + float wateralpha; } parsestate; typedef struct shaderkey_s @@ -1095,7 +1105,7 @@ static qboolean Shader_LoadPermutations(char *name, program_t *prog, char *scrip #ifdef VKQUAKE if (qrenderer == QR_VULKAN && (qrtype == QR_VULKAN || qrtype == QR_OPENGL)) - { + { //vulkan can potentially load glsl, f it has the extensions enabled. if (qrtype == QR_VULKAN && VK_LoadBlob(prog, script, name)) return true; } @@ -1395,6 +1405,8 @@ static qboolean Shader_LoadPermutations(char *name, program_t *prog, char *scrip end = strchr(start, '#'); if (!end) end = start + strlen(start); + if (end-start == 7 && !Q_strncasecmp(start, "usemods", 7)) + prog->nofixedcompat = false; if (nummodifiers < MAXMODIFIERS) { permutationdefines[nummodifiers] = d = BZ_Malloc(10 + end - start); @@ -1658,7 +1670,7 @@ static void Shader_LoadGeneric(sgeneric_t *g, int qrtype) FS_LoadFile(basicname, &file); *blobname = 0; } - else + else if (ruleset_allow_shaders.ival) { //renderer-specific files if (sh_config.progpath) { @@ -1672,6 +1684,11 @@ static void Shader_LoadGeneric(sgeneric_t *g, int qrtype) else *blobname = 0; } + else + { + file = NULL; + *blobname = 0; + } if (sh_config.pDeleteProg) { @@ -1690,7 +1707,7 @@ static void Shader_LoadGeneric(sgeneric_t *g, int qrtype) int ver; for (i = 0; *sbuiltins[i].name; i++) { - if (sbuiltins[i].qrtype == qrenderer && !strcmp(sbuiltins[i].name, basicname)) + if (sbuiltins[i].qrtype == qrtype && !strcmp(sbuiltins[i].name, basicname)) { ver = sbuiltins[i].apiver; @@ -1698,7 +1715,7 @@ static void Shader_LoadGeneric(sgeneric_t *g, int qrtype) if (!(qrenderer==QR_OPENGL&&ver==110&&sh_config.maxver==100)) continue; - g->failed = !Shader_LoadPermutations(g->name, &g->prog, sbuiltins[i].body, sbuiltins[i].qrtype, ver, blobname); + g->failed = !Shader_LoadPermutations(g->name, &g->prog, sbuiltins[i].body, qrtype, ver, blobname); if (g->failed) continue; @@ -2211,6 +2228,32 @@ static void Shader_DP_Camera(shader_t *shader, shaderpass_t *pass, char **ptr) { shader->sort = SHADER_SORT_PORTAL; } +static void Shader_DP_Water(shader_t *shader, shaderpass_t *pass, char **ptr) +{ + parsestate.forceprogramify = true; + + parsestate.reflectmin = Shader_ParseFloat(shader, ptr, 0); + parsestate.reflectmax = Shader_ParseFloat(shader, ptr, 0); + parsestate.refractfactor = Shader_ParseFloat(shader, ptr, 0); + parsestate.reflectfactor = Shader_ParseFloat(shader, ptr, 0); + Shader_ParseVector(shader, ptr, parsestate.refractcolour); + Shader_ParseVector(shader, ptr, parsestate.reflectcolour); + parsestate.wateralpha = Shader_ParseFloat(shader, ptr, 0); +} +static void Shader_DP_Reflect(shader_t *shader, shaderpass_t *pass, char **ptr) +{ + parsestate.forceprogramify = true; + + parsestate.reflectfactor = Shader_ParseFloat(shader, ptr, 0); + Shader_ParseVector(shader, ptr, parsestate.reflectcolour); +} +static void Shader_DP_Refract(shader_t *shader, shaderpass_t *pass, char **ptr) +{ + parsestate.forceprogramify = true; + + parsestate.refractfactor = Shader_ParseFloat(shader, ptr, 0); + Shader_ParseVector(shader, ptr, parsestate.refractcolour); +} static void Shader_BEMode(shader_t *shader, shaderpass_t *pass, char **ptr) { @@ -2334,8 +2377,11 @@ static shaderkey_t shaderkeys[] = {"reflectmask", Shader_ReflectMask, "fte"}, //dp compat - {"camera", Shader_DP_Camera, "dp"}, {"reflectcube", Shader_ReflectCube, "dp"}, + {"camera", Shader_DP_Camera, "dp"}, + {"water", Shader_DP_Water, "dp"}, + {"reflect", Shader_DP_Reflect, "dp"}, + {"refract", Shader_DP_Refract, "dp"}, /*doom3 compat*/ {"diffusemap", Shader_DiffuseMap, "doom3"}, //macro for "{\nstage diffusemap\nmap \n}" @@ -3923,6 +3969,7 @@ const char *Shader_AlphaMaskProgArgs(shader_t *s) void Shader_Programify (shader_t *s) { + qboolean reflectrefract = false; char *prog = NULL; const char *mask; /* enum @@ -3955,7 +4002,29 @@ void Shader_Programify (shader_t *s) return;*/ } - if (modellighting) + if (parsestate.refractfactor || parsestate.reflectfactor) + { + prog = va("altwater#REFLECT#USEMODS#FRESNEL_EXP=2.0" + //variable parts + "#STRENGTH_REFR=%g#STRENGTH_REFL=%g" + "#TINT_REFR=%g,%g,%g" + "#TINT_REFL=%g,%g,%g" + "#FRESNEL_MIN=%g#FRESNEL_RANGE=%g" + "#ALPHA=%g", + //those args + parsestate.refractfactor*0.01, parsestate.reflectfactor*0.01, + parsestate.refractcolour[0],parsestate.refractcolour[1],parsestate.refractcolour[2], + parsestate.reflectcolour[0],parsestate.reflectcolour[1],parsestate.reflectcolour[2], + parsestate.reflectmin, parsestate.reflectmax-parsestate.reflectmin, + parsestate.wateralpha + ); + //clear out blending and force regular depth. + s->passes[0].shaderbits &= ~(SBITS_BLEND_BITS|SBITS_MISC_NODEPTHTEST|SBITS_MISC_DEPTHEQUALONLY|SBITS_MISC_DEPTHCLOSERONLY); + s->passes[0].shaderbits |= SBITS_MISC_DEPTHWRITE; + + reflectrefract = true; + } + else if (modellighting) { pass = modellighting; prog = "defaultskin"; @@ -3983,8 +4052,25 @@ void Shader_Programify (shader_t *s) if (s->prog) { s->numpasses = 0; - s->passes[s->numpasses++].texgen = T_GEN_DIFFUSE; - s->flags |= SHADER_HASDIFFUSE; + if (reflectrefract) + { + if (s->passes[0].numtcmods > 0 && s->passes[0].tcmods[0].type == SHADER_TCMOD_SCALE) + { //crappy workaround for DP bug. + s->passes[0].tcmods[0].args[0] *= 4; + s->passes[0].tcmods[0].args[1] *= 4; + } + s->passes[s->numpasses++].texgen = T_GEN_REFRACTION; + s->passes[s->numpasses++].texgen = T_GEN_REFLECTION; +// s->passes[s->numpasses++].texgen = T_GEN_RIPPLEMAP; +// s->passes[s->numpasses++].texgen = T_GEN_REFRACTIONDEPTH; + s->flags |= SHADER_HASREFRACT; + s->flags |= SHADER_HASREFLECT; + } + else + { + s->passes[s->numpasses++].texgen = T_GEN_DIFFUSE; + s->flags |= SHADER_HASDIFFUSE; + } } } @@ -4354,7 +4440,7 @@ done:; "}\n"); } - if (!s->prog && sh_config.progs_supported && r_forceprogramify.ival) + if (!s->prog && sh_config.progs_supported && (r_forceprogramify.ival || parsestate.forceprogramify)) { Shader_Programify(s); if (r_forceprogramify.ival >= 2) @@ -4693,9 +4779,9 @@ void QDECL R_BuildDefaultTexnums(texnums_t *src, shader_t *shader) if ((shader->flags & SHADER_HASFULLBRIGHT) && r_fb_bmodels.value && gl_load24bit.value) { if (!TEXVALID(tex->fullbright) && *mapname) - tex->fullbright = R_LoadHiResTexture(va("%s_luma", mapname), NULL, imageflags); + tex->fullbright = R_LoadHiResTexture(va("%s_luma:%s_glow", mapname, mapname), NULL, imageflags); if (!TEXVALID(tex->fullbright)) - tex->fullbright = R_LoadHiResTexture(va("%s_luma", imagename), subpath, imageflags); + tex->fullbright = R_LoadHiResTexture(va("%s_luma:%s_glow", imagename, imagename), subpath, imageflags); } } } @@ -4874,7 +4960,7 @@ void QDECL R_BuildLegacyTexnums(shader_t *shader, const char *fallbackname, cons if (mipdata[0][s] >= 256-vid.fullbright) break; } - tex->fullbright = Image_GetTexture(va("%s_luma", imagename), subpath, imageflags, (s>=0)?mipdata[0]:NULL, palette, width, height, TF_TRANS8_FULLBRIGHT); + tex->fullbright = Image_GetTexture(va("%s_luma:%s_glow", imagename,imagename), subpath, imageflags, (s>=0)?mipdata[0]:NULL, palette, width, height, TF_TRANS8_FULLBRIGHT); } } } diff --git a/engine/gl/gl_shadow.c b/engine/gl/gl_shadow.c index a634ebce..3922579d 100644 --- a/engine/gl/gl_shadow.c +++ b/engine/gl/gl_shadow.c @@ -1667,11 +1667,8 @@ static qboolean Sh_ScissorForSphere(vec3_t center, float radius, vrect_t *rect) /*return false to say that its fully offscreen*/ float v[4], tempv[4]; - extern cvar_t temp1; int i; vrect_t r; - - radius *= temp1.value; rect->x = 0; rect->y = 0; diff --git a/engine/gl/gl_vidlinuxglx.c b/engine/gl/gl_vidlinuxglx.c index ec958683..fb72242d 100644 --- a/engine/gl/gl_vidlinuxglx.c +++ b/engine/gl/gl_vidlinuxglx.c @@ -1933,11 +1933,11 @@ qboolean X11VID_Init (rendererstate_t *info, unsigned char *palette, int psl) #ifdef VKQUAKE case PSL_VULKAN: #ifdef VK_USE_PLATFORM_XLIB_KHR - if (VK_Init(info, VK_KHR_XLIB_SURFACE_EXTENSION_NAME, XVK_SetupSurface_XLib)) + if (VK_Init(info, VK_KHR_XLIB_SURFACE_EXTENSION_NAME, XVK_SetupSurface_XLib, NULL)) break; #endif #ifdef VK_USE_PLATFORM_XCB_KHR - if (x11xcb_initlib() && VK_Init(info, VK_KHR_XCB_SURFACE_EXTENSION_NAME, XVK_SetupSurface_XCB)) + if (x11xcb_initlib() && VK_Init(info, VK_KHR_XCB_SURFACE_EXTENSION_NAME, XVK_SetupSurface_XCB, NULL)) break; #endif Con_Printf("Failed to create a vulkan context.\n"); diff --git a/engine/gl/gl_vidnt.c b/engine/gl/gl_vidnt.c index 022bbcfe..12cad6c9 100644 --- a/engine/gl/gl_vidnt.c +++ b/engine/gl/gl_vidnt.c @@ -983,12 +983,15 @@ static qboolean VID_SetFullDIBMode (rendererstate_t *info) gdevmode.dmFields |= DM_BITSPERPEL; if (info->rate) gdevmode.dmFields |= DM_DISPLAYFREQUENCY; - gdevmode.dmBitsPerPel = info->bpp; - if (info->bpp && (gdevmode.dmBitsPerPel < 15)) - { + if (info->bpp && (info->bpp < 15)) + { //low values get you a warning. otherwise only 16 and 32bit are allowed. Con_Printf("Forcing at least 15bpp\n"); gdevmode.dmBitsPerPel = 16; } + else if (info->bpp == 16) + gdevmode.dmBitsPerPel = 16; + else + gdevmode.dmBitsPerPel = 32; gdevmode.dmDisplayFrequency = info->rate; gdevmode.dmPelsWidth = info->width; gdevmode.dmPelsHeight = info->height; @@ -1318,14 +1321,23 @@ int GLVID_SetMode (rendererstate_t *info, unsigned char *palette) // fix the leftover Alt from any Alt-Tab or the like that switched us away ClearAllStates (); + gammaworks = FALSE; if (vid_desktopgamma.value) { HDC hDC = GetDC(GetDesktopWindow()); - gammaworks = qGetDeviceGammaRamp(hDC, originalgammaramps); + if (qGetDeviceGammaRamp(hDC, originalgammaramps)) + gammaworks = qSetDeviceGammaRamp(hDC, originalgammaramps); ReleaseDC(GetDesktopWindow(), hDC); } else - gammaworks = qGetDeviceGammaRamp(maindc, originalgammaramps); + { + if (qGetDeviceGammaRamp(maindc, originalgammaramps)) + gammaworks = qSetDeviceGammaRamp(maindc, originalgammaramps); + } + if (!gammaworks) + Con_Printf("Hardware gamma is not supported\n"); + else + Con_DPrintf("Hardware gamma appears to work\n"); return true; } @@ -1710,10 +1722,6 @@ void GLVID_Recenter_f(void) //int nx = 0; //int ny = 0; -#ifdef _MSC_VER -#define strtoull _strtoui64 -#endif - if (Cmd_Argc() > 1) sys_parentleft = atoi(Cmd_Argv(1)); if (Cmd_Argc() > 2) diff --git a/engine/gl/r_bishaders.h b/engine/gl/r_bishaders.h index b00f47ff..d259ffea 100644 --- a/engine/gl/r_bishaders.h +++ b/engine/gl/r_bishaders.h @@ -352,28 +352,74 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND #endif #ifdef GLQUAKE {QR_OPENGL, 110, "altwater", -"!!cvarf r_glsl_turbscale\n" -//modifier: REFLECT (s_t2 is a reflection instead of diffusemap) -//modifier: STRENGTH (0.1 = fairly gentle, 0.2 = big waves) -//modifier: FRESNEL (5=water) -//modifier: TXSCALE (0.2 - wave strength) -//modifier: RIPPLEMAP (s_t3 contains a ripplemap -//modifier: TINT (some colour value) +"!!cvardf r_glsl_turbscale_reflect=1 //simpler scaler\n" +"!!cvardf r_glsl_turbscale_refract=1 //simpler scaler\n" +"!!samps 4 diffuse\n" +"#include \"sys/defs.h\"\n" + +//modifier: REFLECT (s_t2 is a reflection instead of diffusemap) +//modifier: STRENGTH_REFL (distortion strength - 0.1 = fairly gentle, 0.2 = big waves) +//modifier: STRENGTH_REFL (distortion strength - 0.1 = fairly gentle, 0.2 = big waves) +//modifier: FRESNEL_EXP (5=water) +//modifier: TXSCALE (wave size - 0.2) +//modifier: RIPPLEMAP (s_t3 contains a ripplemap +//modifier: TINT_REFR (some colour value) +//modifier: TINT_REFL (some colour value) +//modifier: ALPHA (mix in the normal water texture over the top) +//modifier: USEMODS (use single-texture scrolling via tcmods - note, also forces the engine to actually use tcmod etc) + +//a few notes on DP compat: +//'dpwater' makes numerous assumptions about DP internals +//by default there is a single pass that uses the pass's normal tcmods +//the fresnel has a user-supplied min+max rather than an exponent +//both parts are tinted individually +//if alpha is enabled, the regular water texture is blended over the top, again using the same crappy tcmods... + +//legacy crap "#ifndef FRESNEL\n" "#define FRESNEL 5.0\n" "#endif\n" +"#ifndef TINT\n" +"#define TINT 0.7,0.8,0.7\n" +"#endif\n" "#ifndef STRENGTH\n" "#define STRENGTH 0.1\n" "#endif\n" "#ifndef TXSCALE\n" "#define TXSCALE 0.2\n" "#endif\n" -"#ifndef TINT\n" -"#define TINT vec3(0.7, 0.8, 0.7)\n" + +//current values (referring to legacy defaults where needed) +"#ifndef FRESNEL_EXP\n" +"#define FRESNEL_EXP 5.0\n" +"#endif\n" +"#ifndef FRESNEL_MIN\n" +"#define FRESNEL_MIN 0.0\n" +"#endif\n" +"#ifndef FRESNEL_RANGE\n" +"#define FRESNEL_RANGE 1.0\n" +"#endif\n" +"#ifndef STRENGTH_REFL\n" +"#define STRENGTH_REFL STRENGTH\n" +"#endif\n" +"#ifndef STRENGTH_REFR\n" +"#define STRENGTH_REFR STRENGTH\n" +"#endif\n" +"#ifndef TXSCALE1\n" +"#define TXSCALE1 TXSCALE\n" +"#endif\n" +"#ifndef TXSCALE2\n" +"#define TXSCALE2 TXSCALE\n" +"#endif\n" +"#ifndef TINT_REFR\n" +"#define TINT_REFR TINT\n" +"#endif\n" +"#ifndef TINT_REFL\n" +"#define TINT_REFL 1.0,1.0,1.0\n" "#endif\n" "#ifndef FOGTINT\n" -"#define FOGTINT vec3(0.2, 0.3, 0.2)\n" +"#define FOGTINT 0.2,0.3,0.2\n" "#endif\n" "varying vec2 tc;\n" @@ -381,9 +427,6 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND "varying vec3 norm;\n" "varying vec3 eye;\n" "#ifdef VERTEX_SHADER\n" -"attribute vec2 v_texcoord;\n" -"attribute vec3 v_normal;\n" -"uniform vec3 e_eyepos;\n" "void main (void)\n" "{\n" "tc = v_texcoord.st;\n" @@ -394,45 +437,48 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND "}\n" "#endif\n" "#ifdef FRAGMENT_SHADER\n" +"#ifdef ALPHA\n" +"#include \"sys/fog.h\"\n" +"#endif\n" + + "#define s_refract s_t0\n" "#define s_reflect s_t1\n" "#define s_ripplemap s_t2\n" "#define s_refractdepth s_t3\n" -"uniform float cvar_r_glsl_turbscale;\n" -"uniform sampler2D s_normalmap;\n" -"uniform sampler2D s_diffuse;\n" -"uniform sampler2D s_refract; //refract\n" -"uniform sampler2D s_reflect; //reflection\n" -"uniform sampler2D s_refractdepth; //refraction depth\n" -"uniform sampler2D s_ripplemap; //ripplemap\n" - -"uniform float e_time;\n" "void main (void)\n" "{\n" -"vec2 stc, ntc;\n" +"vec2 stc; //screen tex coords\n" +"vec2 ntc; //normalmap/diffuse tex coords\n" "vec3 n, refr, refl;\n" "float fres;\n" "float depth;\n" "stc = (1.0 + (tf.xy / tf.w)) * 0.5;\n" -//hack the texture coords slightly so that there are no obvious gaps +//hack the texture coords slightly so that there are less obvious gaps "stc.t -= 1.5*norm.z/1080.0;\n" +"#if 0//def USEMODS\n" +"ntc = tc;\n" +"n = texture2D(s_normalmap, ntc).xyz - 0.5;\n" +"#else\n" //apply q1-style warp, just for kicks "ntc.s = tc.s + sin(tc.t+e_time)*0.125;\n" "ntc.t = tc.t + sin(tc.s+e_time)*0.125;\n" //generate the two wave patterns from the normalmap -"n = (texture2D(s_normalmap, TXSCALE*tc + vec2(e_time*0.1, 0.0)).xyz);\n" -"n += (texture2D(s_normalmap, TXSCALE*tc - vec2(0, e_time*0.097)).xyz);\n" +"n = (texture2D(s_normalmap, vec2(TXSCALE1)*tc + vec2(e_time*0.1, 0.0)).xyz);\n" +"n += (texture2D(s_normalmap, vec2(TXSCALE2)*tc - vec2(0, e_time*0.097)).xyz);\n" "n -= 1.0 - 4.0/256.0;\n" +"#endif\n" "#ifdef RIPPLEMAP\n" "n += texture2D(s_ripplemap, stc).rgb*3.0;\n" "#endif\n" +"n = normalize(n);\n" //the fresnel term decides how transparent the water should be -"fres = pow(1.0-abs(dot(normalize(n), normalize(eye))), float(FRESNEL));\n" +"fres = pow(1.0-abs(dot(n, normalize(eye))), float(FRESNEL_EXP)) * float(FRESNEL_RANGE) + float(FRESNEL_MIN);\n" "#ifdef DEPTH\n" "float far = #include \"cvar/gl_maxdist\";\n" @@ -465,22 +511,30 @@ YOU SHOULD NOT EDIT THIS FILE BY HAND //refraction image (and water fog, if possible) -"refr = texture2D(s_refract, stc + n.st*STRENGTH*cvar_r_glsl_turbscale).rgb * TINT;\n" +"refr = texture2D(s_refract, stc + n.st*float(STRENGTH_REFR)*float(r_glsl_turbscale_refract)).rgb * vec3(TINT_REFR);\n" "#ifdef DEPTH\n" -"refr = mix(refr, FOGTINT, min(depth/4096.0, 1.0));\n" +"refr = mix(refr, vec3(FOGTINT), min(depth/4096.0, 1.0));\n" "#endif\n" //reflection/diffuse "#ifdef REFLECT\n" -"refl = texture2D(s_reflect, stc - n.st*STRENGTH*cvar_r_glsl_turbscale).rgb;\n" +"refl = texture2D(s_reflect, stc - n.st*float(STRENGTH_REFL)*float(r_glsl_turbscale_reflect)).rgb * vec3(TINT_REFL);\n" "#else\n" -"refl = texture2D(s_diffuse, ntc).xyz;\n" +"refl = texture2D(s_diffuse, ntc).xyz * vec3(TINT_REFL);\n" "#endif\n" -//FIXME: add specular - //interplate by fresnel "refr = mix(refr, refl, fres);\n" + + + + +"#ifdef ALPHA\n" +"vec4 ts = texture2D(s_diffuse, ntc);\n" +"vec4 surf = fog4blend(vec4(ts.rgb, float(ALPHA)*ts.a));\n" +"refr = mix(refr, surf.rgb, surf.a);\n" +"#endif\n" + //done "gl_FragColor = vec4(refr, 1.0);\n" "}\n" diff --git a/engine/http/ftpserver.c b/engine/http/ftpserver.c index 325a67b8..2c8df090 100644 --- a/engine/http/ftpserver.c +++ b/engine/http/ftpserver.c @@ -859,7 +859,7 @@ unsigned int WINAPI BlockingClient(FTPclient_t *cl) unsigned long _false = false; if (ioctlsocket (cl->controlsock, FIONBIO, &_false) == -1) { - IWebPrintf ("FTP_ServerRun: blocking error: %s\n", strerror(qerrno)); + IWebPrintf ("FTP_ServerRun: blocking error: %s\n", strerror(neterrno())); return 0; } diff --git a/engine/http/httpclient.c b/engine/http/httpclient.c index de469ea7..e7b62a35 100644 --- a/engine/http/httpclient.c +++ b/engine/http/httpclient.c @@ -1425,6 +1425,19 @@ qboolean DL_CreateThread(struct dl_download *dl, vfsfile_t *file, void (*NotifyF return true; } +#else +qboolean DL_CreateThread(struct dl_download *dl, vfsfile_t *file, void (*NotifyFunction)(struct dl_download *dl)) +{ + if (!dl) + return false; + + if (file) + dl->file = file; + if (NotifyFunction) + dl->notifycomplete = NotifyFunction; + + return false; +} #endif /*create a standalone download context*/ diff --git a/engine/http/httpserver.c b/engine/http/httpserver.c index 55f61ede..1d94eabc 100644 --- a/engine/http/httpserver.c +++ b/engine/http/httpserver.c @@ -523,19 +523,26 @@ cont: cl->file = IWebGenerateFile(resource+1, content, contentlen); else { + char filename[MAX_OSPATH], *q; cl->file = NULL; - if (SV_AllowDownload(resource+1)) + Q_strncpyz(filename, resource+1, sizeof(filename)); + q = strchr(filename, '?'); + if (q) *q = 0; + + if (SV_AllowDownload(filename)) { char nbuf[MAX_OSPATH]; - if (cl->acceptgzip && strlen(resource+1) < sizeof(nbuf)-4) + + if (cl->acceptgzip && strlen(filename) < sizeof(nbuf)-4) { - sprintf(nbuf, "%s.gz", resource+1); + Q_strncpyz(nbuf, filename, sizeof(nbuf)); + Q_strncatz(nbuf, ".gz", sizeof(nbuf)); cl->file = FS_OpenVFS(nbuf, "rb", FS_GAME); } if (cl->file) gzipped = true; else - cl->file = FS_OpenVFS(resource+1, "rb", FS_GAME); + cl->file = FS_OpenVFS(filename, "rb", FS_GAME); } if (!cl->file) @@ -695,7 +702,12 @@ void VARGS Q_snprintfz (char *dest, size_t size, const char *fmt, ...) { va_list args; va_start (args, fmt); +#ifdef _WIN32 +#undef _vsnprintf + _vsnprintf (dest, size-1, fmt, args); +#else vsnprintf (dest, size-1, fmt, args); +#endif va_end (args); //make sure its terminated. dest[size-1] = 0; diff --git a/engine/http/iwebiface.c b/engine/http/iwebiface.c index 5ac2a71c..5961f0e7 100644 --- a/engine/http/iwebiface.c +++ b/engine/http/iwebiface.c @@ -8,6 +8,12 @@ qboolean SV_AllowDownload (const char *name) { + if (strstr(name, "..")) + return false; + if (strchr(name, ':')) + return false; + if (*name == '/' || *name == '\\') + return false; return true; } char com_token[sizeof(com_token)]; @@ -120,12 +126,18 @@ int main(int argc, char **argv) } #ifdef _WIN32 +#ifdef _MSC_VER +#define ULL(x) x##ui64 +#else +#define ULL(x) x##ull +#endif + static time_t Sys_FileTimeToTime(FILETIME ft) { ULARGE_INTEGER ull; ull.LowPart = ft.dwLowDateTime; ull.HighPart = ft.dwHighDateTime; - return ull.QuadPart / 10000000ULL - 11644473600ULL; + return ull.QuadPart / ULL(10000000) - ULL(11644473600); } void COM_EnumerateFiles (const char *match, int (*func)(const char *, qofs_t, time_t mtime, void *, searchpathfuncs_t *f), void *parm) { diff --git a/engine/qclib/cmdlib.h b/engine/qclib/cmdlib.h index 15ea94ee..317507fd 100644 --- a/engine/qclib/cmdlib.h +++ b/engine/qclib/cmdlib.h @@ -48,7 +48,7 @@ static void VARGS QC_snprintfz (char *dest, size_t size, const char *fmt, ...) { va_list args; va_start (args, fmt); - vsnprintf (dest, size-1, fmt, args); + _vsnprintf (dest, size-1, fmt, args); va_end (args); //make sure its terminated. dest[size-1] = 0; diff --git a/engine/qclib/initlib.c b/engine/qclib/initlib.c index d3142662..102d500c 100644 --- a/engine/qclib/initlib.c +++ b/engine/qclib/initlib.c @@ -1272,13 +1272,13 @@ pbool PDECL PR_DumpProfiles (pubprogfuncs_t *ppf, pbool resetprofiles) progfuncs_t *progfuncs = (progfuncs_t*)ppf; struct progstate_s *ps; unsigned int i, f, j, s; - unsigned long long cpufrequency; + prclocks_t cpufrequency; struct { char *fname; int profile; - unsigned long long profiletime; - unsigned long long totaltime; + prclocks_t profiletime; + prclocks_t totaltime; } *sorted, t; if (!prinst.profiling) { @@ -1329,7 +1329,7 @@ pbool PDECL PR_DumpProfiles (pubprogfuncs_t *ppf, pbool resetprofiles) //print it out printf("%8s %9s %10s: %s\n", "ops", "self-time", "total-time", "function"); for (f = 0; f < s; f++) - printf("%8u %9f %10f: %s\n", sorted[f].profile, (float)(((double)sorted[f].profiletime) / cpufrequency), (float)(((double)sorted[f].totaltime) / cpufrequency), sorted[f].fname); + printf("%8u %9f %10f: %s\n", sorted[f].profile, ull2dbl(sorted[f].profiletime) / ull2dbl(cpufrequency), ull2dbl(sorted[f].totaltime) / ull2dbl(cpufrequency), sorted[f].fname); free(sorted); } return true; diff --git a/engine/qclib/pr_comp.h b/engine/qclib/pr_comp.h index 90b9f150..f4d93348 100644 --- a/engine/qclib/pr_comp.h +++ b/engine/qclib/pr_comp.h @@ -23,6 +23,14 @@ void BZ_Free(void *data); typedef int dstring_t; #define QCC_string_t dstring_t +#if defined(_MSC_VER) && _MSC_VER < 1300 +#define prclocks_t unsigned __int64 +#define ull2dbl(x) ((double)(__int64)x) +#else +#define prclocks_t unsigned long long +#define ull2dbl(x) ((double)x) +#endif + //typedef enum {ev_void, ev_string, ev_float, ev_vector, ev_entity, ev_field, ev_function, ev_pointer, ev_integer, ev_struct, ev_union} etype_t; // 0 1 2 3 4 5 6 7 8 9 10 @@ -531,8 +539,8 @@ typedef struct int locals; // total ints of parms + locals int profile; //number of qc instructions executed. - unsigned long long profiletime; //total time inside (cpu cycles) - unsigned long long profilechildtime; //time inside children (excluding builtins, cpu cycles) + prclocks_t profiletime; //total time inside (cpu cycles) + prclocks_t profilechildtime; //time inside children (excluding builtins, cpu cycles) string_t s_name; string_t s_file; // source file defined in diff --git a/engine/qclib/pr_edict.c b/engine/qclib/pr_edict.c index 7fe0af1b..e5220f78 100644 --- a/engine/qclib/pr_edict.c +++ b/engine/qclib/pr_edict.c @@ -513,7 +513,7 @@ static void VARGS QC_snprintfz (char *dest, size_t size, const char *fmt, ...) { va_list args; va_start (args, fmt); - vsnprintf (dest, size-1, fmt, args); + _vsnprintf (dest, size-1, fmt, args); va_end (args); //make sure its terminated. dest[size-1] = 0; diff --git a/engine/qclib/pr_exec.c b/engine/qclib/pr_exec.c index 1eada72d..fbb92def 100644 --- a/engine/qclib/pr_exec.c +++ b/engine/qclib/pr_exec.c @@ -4,7 +4,7 @@ #if __STDC_VERSION__ >= 199901L #define fte_restrict restrict -#elif defined(_MSC_VER) +#elif defined(_MSC_VER) && _MSC_VER >= 1400 #define fte_restrict __restrict #else #define fte_restrict @@ -36,13 +36,13 @@ #if !defined(Sys_GetClock) && defined(_WIN32) //windows has some specific functions for this (traditionally wrapping rdtsc) //note: on some systems, you may need to force cpu affinity to a single core via task manager - static unsigned long long Sys_GetClock(void) + static prclocks_t Sys_GetClock(void) { LARGE_INTEGER li; QueryPerformanceCounter(&li); return li.QuadPart; } - unsigned long long Sys_GetClockRate(void) + prclocks_t Sys_GetClockRate(void) { LARGE_INTEGER li; QueryPerformanceFrequency(&li); @@ -57,14 +57,14 @@ #if defined(_POSIX_TIMERS) && _POSIX_TIMERS >= 0 #include #ifdef CLOCK_PROCESS_CPUTIME_ID - static unsigned long long Sys_GetClock(void) + static prclocks_t Sys_GetClock(void) { struct timespec c; clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &c); return (c.tv_sec*1000000000ull) + c.tv_nsec; } #define Sys_GetClock Sys_GetClock - unsigned long long Sys_GetClockRate(void) + prclocks_t Sys_GetClockRate(void) { return 1000000000ull; } @@ -75,13 +75,13 @@ #if !defined(Sys_GetClock) && defined(__unix__) #include #define Sys_GetClock() clock() - unsigned long long Sys_GetClockRate(void) { return CLOCKS_PER_SEC; } + prclocks_t Sys_GetClockRate(void) { return CLOCKS_PER_SEC; } #endif #ifndef Sys_GetClock //other systems have no choice but to omit this feature in some way. this is just for profiling, so we can get away with stubs. #define Sys_GetClock() 0 - unsigned long long Sys_GetClockRate(void) { return 1; } + prclocks_t Sys_GetClockRate(void) { return 1; } #endif //============================================================================= @@ -157,7 +157,7 @@ static void VARGS QC_snprintfz (char *dest, size_t size, const char *fmt, ...) { va_list args; va_start (args, fmt); - vsnprintf (dest, size-1, fmt, args); + _vsnprintf (dest, size-1, fmt, args); va_end (args); //make sure its terminated. dest[size-1] = 0; @@ -548,7 +548,7 @@ int ASMCALL PR_LeaveFunction (progfuncs_t *progfuncs) if (prinst.profiling) { - unsigned long long cycles; + prclocks_t cycles; cycles = Sys_GetClock() - pr_stack[pr_depth].timestamp; if (cycles > prinst.profilingalert) printf("QC call to %s took over a second\n", PR_StringToNative(&progfuncs->funcs,pr_xfunction->s_name)); diff --git a/engine/qclib/progsint.h b/engine/qclib/progsint.h index 960b3156..2747664b 100644 --- a/engine/qclib/progsint.h +++ b/engine/qclib/progsint.h @@ -65,7 +65,7 @@ typedef struct unsigned char progsnum; int s; int pushed; - unsigned long long timestamp; + prclocks_t timestamp; } prstack_t; typedef struct @@ -134,7 +134,7 @@ typedef struct prinst_s int exitdepth; pbool profiling; - unsigned long long profilingalert; + prclocks_t profilingalert; mfunction_t *pr_xfunction; #define pr_xfunction prinst.pr_xfunction int pr_xstatement; @@ -449,7 +449,8 @@ fdef_t *PDECL ED_FieldInfo (pubprogfuncs_t *progfuncs, unsigned int *count); char *PDECL PR_UglyValueString (pubprogfuncs_t *progfuncs, etype_t type, eval_t *val); pbool PDECL ED_ParseEval (pubprogfuncs_t *progfuncs, eval_t *eval, int type, const char *s); -unsigned long long Sys_GetClockRate(void); + +prclocks_t Sys_GetClockRate(void); #endif diff --git a/engine/qclib/qcc_pr_comp.c b/engine/qclib/qcc_pr_comp.c index fbf87441..25eb3029 100644 --- a/engine/qclib/qcc_pr_comp.c +++ b/engine/qclib/qcc_pr_comp.c @@ -7451,10 +7451,10 @@ QCC_sref_t QCC_EvaluateCast(QCC_sref_t src, QCC_type_t *cast, pbool implicit) src.cast = cast; } /*cast from int->float will convert*/ - else if (totype == ev_float && src.cast->type == ev_integer) + else if (totype == ev_float && (src.cast->type == ev_integer || (src.cast->type == ev_entity && !implicit))) src = QCC_PR_Statement (&pr_opcodes[OP_CONV_ITOF], src, nullsref, NULL); /*cast from float->int will convert*/ - else if (totype == ev_integer && src.cast->type == ev_float) + else if ((totype == ev_integer || (totype == ev_entity && !implicit)) && src.cast->type == ev_float) src = QCC_PR_Statement (&pr_opcodes[OP_CONV_FTOI], src, nullsref, NULL); else if (totype == ev_entity && src.cast->type == ev_entity) { diff --git a/engine/qclib/qcc_pr_lex.c b/engine/qclib/qcc_pr_lex.c index 51ace694..ef46f9ca 100644 --- a/engine/qclib/qcc_pr_lex.c +++ b/engine/qclib/qcc_pr_lex.c @@ -1842,10 +1842,18 @@ int QCC_PR_LexInteger (void) return atoi (pr_token); } +#ifdef _MSC_VER +#define longlong __int64 +#define LL(x) x##i64 +#else +#define longlong long long +#define LL(x) x##ll +#endif + void QCC_PR_LexNumber (void) { int tokenlen = 0; - long long num=0; + longlong num=0; int base=0; int c; int sign=1; @@ -1926,7 +1934,7 @@ void QCC_PR_LexNumber (void) pr_immediate._float = num*sign; num*=sign; - if ((long long)pr_immediate._float != (long long)num) + if ((longlong)pr_immediate._float != (longlong)num) QCC_PR_ParseWarning(WARN_OVERFLOW, "numerical overflow"); return; } @@ -1939,9 +1947,9 @@ void QCC_PR_LexNumber (void) pr_immediate._int = num*sign; num*=sign; - if ((long long)pr_immediate._int != (long long)num) + if ((longlong)pr_immediate._int != (longlong)num) { - if (((long long)pr_immediate._int & 0xffffffff80000000ll) != 0xffffffff80000000ll) + if (((longlong)pr_immediate._int & LL(0xffffffff80000000)) != LL(0xffffffff80000000)) QCC_PR_ParseWarning(WARN_OVERFLOW, "numerical overflow"); } return; @@ -1973,9 +1981,9 @@ qccxhex: pr_immediate._int = num*sign; num*=sign; - if ((long long)pr_immediate._int != (long long)num) + if ((longlong)pr_immediate._int != (longlong)num) { - if (((long long)pr_immediate._int & 0xffffffff80000000ll) != 0xffffffff80000000ll) + if (((longlong)pr_immediate._int & LL(0xffffffff80000000)) != LL(0xffffffff80000000)) QCC_PR_ParseWarning(WARN_OVERFLOW, "numerical overflow"); } } @@ -1988,7 +1996,7 @@ qccxhex: pr_immediate._float = (float)(num*sign); num*=sign; - if ((long long)pr_immediate._float != (long long)num && base == 16) + if ((longlong)pr_immediate._float != (longlong)num && base == 16) QCC_PR_ParseWarning(WARN_OVERFLOW, "numerical overflow %lld will be rounded to %f", num, pr_immediate._float); } } diff --git a/engine/server/pr_cmds.c b/engine/server/pr_cmds.c index 3f090ef2..1fec0a18 100644 --- a/engine/server/pr_cmds.c +++ b/engine/server/pr_cmds.c @@ -6101,8 +6101,6 @@ void QCBUILTIN PF_sqlversion (pubprogfuncs_t *prinst, struct globalvars_s *pr_gl void PR_SQLCycle(void) { - if (!SQL_Available()) - return; SQL_ServerCycle(); } #endif @@ -8313,6 +8311,36 @@ static void QCBUILTIN PF_te_explosion2(pubprogfuncs_t *prinst, struct globalvars SV_MulticastProtExt(org, MULTICAST_PHS, pr_global_struct->dimension_send, 0, 0); } +//DP_TE_FLAMEJET +static void QCBUILTIN PF_te_flamejet(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) +{ + float *org = G_VECTOR(OFS_PARM0); + float *vel = G_VECTOR(OFS_PARM1); + float howmany = bound(0,G_FLOAT(OFS_PARM2),255); + + MSG_WriteByte (&sv.multicast, svc_temp_entity); + MSG_WriteByte (&sv.multicast, TEDP_FLAMEJET); + MSG_WriteCoord (&sv.multicast, org[0]); + MSG_WriteCoord (&sv.multicast, org[1]); + MSG_WriteCoord (&sv.multicast, org[2]); + MSG_WriteCoord (&sv.multicast, vel[0]); + MSG_WriteCoord (&sv.multicast, vel[1]); + MSG_WriteCoord (&sv.multicast, vel[2]); + MSG_WriteByte (&sv.multicast, howmany); +#ifdef NQPROT + MSG_WriteByte (&sv.nqmulticast, svc_temp_entity); + MSG_WriteByte (&sv.nqmulticast, TEDP_FLAMEJET); + MSG_WriteCoord (&sv.nqmulticast, org[0]); + MSG_WriteCoord (&sv.nqmulticast, org[1]); + MSG_WriteCoord (&sv.nqmulticast, org[2]); + MSG_WriteCoord (&sv.nqmulticast, vel[0]); + MSG_WriteCoord (&sv.nqmulticast, vel[1]); + MSG_WriteCoord (&sv.nqmulticast, vel[2]); + MSG_WriteByte (&sv.nqmulticast, howmany); +#endif + SV_MulticastProtExt(org, MULTICAST_PHS, pr_global_struct->dimension_send, 0, 0); +} + //DP_TE_STANDARDEFFECTBUILTINS //void(entity own, vector start, vector end) te_lightning1 = #428; static void QCBUILTIN PF_te_lightning1(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) @@ -9843,6 +9871,8 @@ BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs {"fputs", PF_fputs, 0, 0, 0, 113, D("void(filestream fhandle, string s, optional string s2, optional string s3, optional string s4, optional string s5, optional string s6, optional string s7)", "Writes the given string(s) into the file. For compatibility with fgets, you should ensure that the string is terminated with a \\n - this will not otherwise be done for you. It is up to the engine whether dos or unix line endings are actually written.")}, // (FRIK_FILE) {"fread", PF_fread, 0, 0, 0, 0, D("int(filestream fhandle, void *ptr, int size)", "Reads binary data out of the file. Returns truncated lengths if the read exceeds the length of the file.")}, {"fwrite", PF_fwrite, 0, 0, 0, 0, D("int(filestream fhandle, void *ptr, int size)", "Writes binary data out of the file.")}, + {"fseek", PF_fseek, 0, 0, 0, 0, D("#define ftell fseek //c compat\nint(filestream fhandle, optional int newoffset)", "Changes the current position of the file, if specified. Returns prior position, in bytes.")}, + {"fsize", PF_fsize, 0, 0, 0, 0, D("int(filestream fhandle, optional int newsize)", "Reports the total size of the file, in bytes. Can also be used to truncate/extend the file")}, {"strlen", PF_strlen, 0, 0, 0, 114, "float(string s)"}, // (FRIK_FILE) {"strcat", PF_strcat, 0, 0, 0, 115, "string(string s1, optional string s2, optional string s3, optional string s4, optional string s5, optional string s6, optional string s7, optional string s8)"}, // (FRIK_FILE) {"substring", PF_substring, 0, 0, 0, 116, "string(string s, float start, float length)"}, // (FRIK_FILE) @@ -10279,7 +10309,7 @@ BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs {"spawnclient", PF_spawnclient, 0, 0, 0, 454, "entity()"},//DP_SV_BOTCLIENT {"clienttype", PF_clienttype, 0, 0, 0, 455, "float(entity client)"},//botclient {"WriteUnterminatedString",PF_WriteString2,0, 0, 0, 456, "void(float target, string str)"}, //writestring but without the null terminator. makes things a little nicer. -// {"te_flamejet", PF_te_flamejet, 0, 0, 0, 457, "void(vector org, vector vel, float howmany)"},//DP_TE_FLAMEJET + {"te_flamejet", PF_te_flamejet, 0, 0, 0, 457, "void(vector org, vector vel, float howmany)"},//DP_TE_FLAMEJET // {"undefined", PF_Fixme, 0, 0, 0, 458, ""}, {"edict_num", PF_edict_for_num, 0, 0, 0, 459, "entity(float entnum)"},//DP_QC_EDICT_NUM {"buf_create", PF_buf_create, 0, 0, 0, 460, "strbuf()"},//DP_QC_STRINGBUFFERS diff --git a/engine/server/pr_q1qvm.c b/engine/server/pr_q1qvm.c index 06db2caa..9c0cf353 100755 --- a/engine/server/pr_q1qvm.c +++ b/engine/server/pr_q1qvm.c @@ -1436,11 +1436,11 @@ static qintptr_t QVM_NextClient (void *offset, quintptr_t mask, const qintptr_t static qintptr_t QVM_SetPause (void *offset, quintptr_t mask, const qintptr_t *arg) { int pause = VM_LONG(arg[0]); - if ((sv.paused&1) == (pause&1)) - return sv.paused&1; //nothing changed, ignore it. + if ((sv.paused&PAUSE_EXPLICIT) == (pause&PAUSE_EXPLICIT)) + return !!(sv.paused&PAUSE_EXPLICIT); //nothing changed, ignore it. sv.paused = pause; sv.pausedstart = Sys_DoubleTime(); - return sv.paused&1; + return !!(sv.paused&PAUSE_EXPLICIT); } static qintptr_t QVM_NotYetImplemented (void *offset, quintptr_t mask, const qintptr_t *arg) { diff --git a/engine/server/server.h b/engine/server/server.h index 33a1b1d9..f8ef81d9 100644 --- a/engine/server/server.h +++ b/engine/server/server.h @@ -122,8 +122,13 @@ typedef struct int framenum; int logindatabase; - qboolean paused; // are we paused? - float pausedstart; + enum + { + PAUSE_EXPLICIT = 1, //someone hit pause + PAUSE_SERVICE = 2, //we're running as a service and someone paused us rather than killing us. + PAUSE_AUTO = 4 //console is down in a singleplayer game. + } paused; + float pausedstart; //check player/eyes models for hacks unsigned model_player_checksum; diff --git a/engine/server/sv_ccmds.c b/engine/server/sv_ccmds.c index 5c6ed409..828085ef 100644 --- a/engine/server/sv_ccmds.c +++ b/engine/server/sv_ccmds.c @@ -1198,10 +1198,6 @@ char *SV_BannedReason (netadr_t *a) return reason; } -#ifdef _MSC_VER -#define strtoull _strtoui64 -#endif - static void SV_FilterIP_f (void) { bannedips_t proto; @@ -2425,36 +2421,64 @@ static void SV_Gamedir (void) SV_Gamedir_f Sets the gamedir and path to a different directory. +FIXME: should block this if we're on a server at the time ================ */ static void SV_Gamedir_f (void) { char *dir; + int argc = Cmd_Argc(); - if (Cmd_Argc() == 1) + if (argc == 1) { Con_TPrintf ("Current gamedir: %s\n", FS_GetGamedir(true)); return; } - if (Cmd_Argc() != 2) + if (argc < 2) { Con_TPrintf ("Usage: gamedir \n"); return; } - dir = Cmd_Argv(1); + if (argc == 2) + dir = Z_StrDup(Cmd_Argv(1)); + else + { + int i; + size_t l = 1; + for (i = 1; i < argc; i++) + l += strlen(Cmd_Argv(i))+1; + dir = Z_Malloc(l); + for (i = 1; i < argc; i++) + { //disgusting hack for quakespasm's "game extendedgame -missionpack" crap. + //games with a leading hypen are inserted before others, with the hyphen ignored. + if (*Cmd_Argv(i) != '-') + continue; + if (*dir) + Q_strncatz(dir, ";", l); + Q_strncatz(dir, Cmd_Argv(i)+1, l); + } + for (i = 1; i < argc; i++) + { + if (*Cmd_Argv(i) == '-') + continue; + if (*dir) + Q_strncatz(dir, ";", l); + Q_strncatz(dir, Cmd_Argv(i), l); + } + } if (strstr(dir, "..") || strstr(dir, "/") || strstr(dir, "\\") || strstr(dir, ":") ) { Con_TPrintf ("%s should be a single filename, not a path\n", Cmd_Argv(0)); - return; } - - dir = Z_StrDup(dir); - COM_Gamedir (dir, NULL); - Info_SetValueForStarKey (svs.info, "*gamedir", dir, MAX_SERVERINFO_STRING); + else + { + COM_Gamedir (dir, NULL); + Info_SetValueForStarKey (svs.info, "*gamedir", dir, MAX_SERVERINFO_STRING); + } Z_Free(dir); } diff --git a/engine/server/sv_main.c b/engine/server/sv_main.c index 2c66b835..653e8794 100644 --- a/engine/server/sv_main.c +++ b/engine/server/sv_main.c @@ -260,6 +260,7 @@ void SV_Shutdown (void) #endif Cvar_Shutdown(); Cmd_Shutdown(); + PM_Shutdown(); #ifdef WEBSERVER IWebShutdown(); @@ -764,7 +765,7 @@ void PIN_SaveMessages(void) f = FS_OpenVFS("pinned.txt", "wb", FS_GAMEONLY); if (!f) { - Con_TPrintf("couldn't write to %s\n", "pinned.txt"); + Con_TPrintf(CON_ERROR "couldn't write to %s\n", "pinned.txt"); return; } @@ -4203,7 +4204,7 @@ void SV_CheckTimeouts (void) cl->netchan.remote_address.type = NA_INVALID; //don't mess up from not knowing their address. } } - if ((sv.paused&1) && !nclients) + if ((sv.paused&PAUSE_EXPLICIT) && !nclients) { // nobody left, unpause the server if (SV_TogglePause(NULL)) @@ -4454,8 +4455,8 @@ float SV_Frame (void) /*server is effectively paused if there are no clients*/ // if (sv.spawned_client_slots == 0 && sv.spawned_observer_slots == 0 && (cls.state != ca_connected)) // isidle = true; - if ((sv.paused & 4) != ((isidle||(sv.spawned_client_slots==0&&!deathmatch.ival))?4:0)) - sv.paused ^= 4; + if ((sv.paused & PAUSE_AUTO) != ((isidle||(sv.spawned_client_slots==0&&!deathmatch.ival))?PAUSE_AUTO:0)) + sv.paused ^= PAUSE_AUTO; #endif if (oldpaused != sv.paused) @@ -5269,6 +5270,9 @@ void SV_ExecInitialConfigs(char *defaultexec) Cbuf_AddText("cvar_purgedefaults\n", RESTRICT_LOCAL); //reset cvar defaults to their engine-specified values. the tail end of 'exec default.cfg' will update non-cheat defaults to mod-specified values. Cbuf_AddText("cvarreset *\n", RESTRICT_LOCAL); //reset all cvars to their current (engine) defaults Cbuf_AddText("alias restart \"changelevel .\"\n",RESTRICT_LOCAL); + + Cbuf_AddText(va("sv_gamedir \"%s\"\n", FS_GetGamedir(true)), RESTRICT_LOCAL); + Cbuf_AddText(defaultexec, RESTRICT_LOCAL); Cbuf_AddText("\n", RESTRICT_LOCAL); @@ -5360,6 +5364,7 @@ void SV_Init (quakeparms_t *parms) Plug_Initialise(true); #endif + Cvar_ParseWatches(); host_initialized = true; diff --git a/engine/server/sv_send.c b/engine/server/sv_send.c index bb3b8fa7..69a841c7 100644 --- a/engine/server/sv_send.c +++ b/engine/server/sv_send.c @@ -1777,7 +1777,7 @@ void SV_WriteClientdataToMessage (client_t *client, sizebuf_t *msg) bits |= SU_EXTEND1; if (bits >= (1u<<24)) bits |= SU_EXTEND2; - if (bits >= (1ull<<32)) + if (bits >= ((quint64_t)1u<<32)) bits |= SU_EXTEND3; // send the data diff --git a/engine/server/sv_sql.c b/engine/server/sv_sql.c index a09a6a08..f30c929b 100644 --- a/engine/server/sv_sql.c +++ b/engine/server/sv_sql.c @@ -169,6 +169,7 @@ queryrequest_t *SQL_PullRequest(sqlserver_t *server, qboolean lock) sqlserver_t **sqlservers; int sqlservercount; int sqlavailable; +int sqlinited; #ifdef USE_SQLITE //this is to try to sandbox sqlite so it can only edit the file its originally opened with. @@ -821,6 +822,9 @@ int SQL_NewServer(const char *driver, const char **paramstr) else // invalid driver choice so we bomb out return -1; + if (!SQL_Available()) //also makes sure the drivers are actually loaded. + return -1; + if (!(sqlavailable & (1u<prespawn_idx >= maxclientsupportedsounds || !sv.strings.sound_precache[client->prespawn_idx]) { + //write final-end-of-list + MSG_WriteByte (&client->netchan.message, 0); + MSG_WriteByte (&client->netchan.message, 0); + started = 0; + if (sv.strings.sound_precache[client->prespawn_idx] && !(client->plimitwarned & PLIMIT_SOUNDS)) { client->plimitwarned |= PLIMIT_SOUNDS; SV_ClientPrintf(client, PRINT_HIGH, "WARNING: Your client's network protocol only supports %i sounds. Please upgrade or enable extensions.\n", client->prespawn_idx); } - //write final-end-of-list - MSG_WriteByte (&client->netchan.message, 0); - MSG_WriteByte (&client->netchan.message, 0); - started = 0; + client->prespawn_stage++; client->prespawn_idx = 0; break; @@ -1171,15 +1173,16 @@ void SV_SendClientPrespawnInfo(client_t *client) if (client->prespawn_idx >= client->maxmodels || !sv.strings.model_precache[client->prespawn_idx]) { + //write final-end-of-list + MSG_WriteByte (&client->netchan.message, 0); + MSG_WriteByte (&client->netchan.message, 0); + started = 0; + if (sv.strings.model_precache[client->prespawn_idx] && !(client->plimitwarned & PLIMIT_MODELS)) { client->plimitwarned |= PLIMIT_MODELS; SV_ClientPrintf(client, PRINT_HIGH, "WARNING: Your client's network protocol only supports %i models. Please upgrade or enable extensions.\n", client->prespawn_idx); } - //write final-end-of-list - MSG_WriteByte (&client->netchan.message, 0); - MSG_WriteByte (&client->netchan.message, 0); - started = 0; client->prespawn_stage++; client->prespawn_idx = 0; @@ -2045,7 +2048,7 @@ void SV_Begin_f (void) ClientReliableWrite_Begin (host_client, svc_setpause, 2); ClientReliableWrite_Byte (host_client, sv.paused!=0); } - if (sv.paused&~4) + if (sv.paused&~PAUSE_AUTO) SV_ClientTPrintf(host_client, PRINT_HIGH, "server is paused\n"); } @@ -3781,7 +3784,7 @@ qboolean SV_TogglePause (client_t *initiator) { int newv; - newv = sv.paused^1; + newv = sv.paused^PAUSE_EXPLICIT; if (!PR_ShouldTogglePause(initiator, newv)) return false; @@ -3815,7 +3818,7 @@ void SV_Pause_f (void) if (SV_TogglePause(host_client)) { - if (sv.paused & 1) + if (sv.paused & PAUSE_EXPLICIT) SV_BroadcastTPrintf (PRINT_HIGH, "%s paused the game\n", host_client->name); else SV_BroadcastTPrintf (PRINT_HIGH, "%s unpaused the game\n", host_client->name); @@ -5420,7 +5423,7 @@ void SVNQ_Begin_f (void) ClientReliableWrite_Begin (host_client, svc_setpause, 2); ClientReliableWrite_Byte (host_client, sv.paused!=0); } - if (sv.paused&~4) + if (sv.paused&~PAUSE_AUTO) SV_ClientTPrintf(host_client, PRINT_HIGH, "server is paused\n"); } @@ -7238,11 +7241,6 @@ void SV_ExecuteClientMessage (client_t *cl) if (sv_antilag.ival || !*sv_antilag.string) { - /* - extern cvar_t temp1; - if (temp1.ival) - frame = &cl->frameunion.frames[(cl->netchan.incoming_acknowledged+temp1.ival) & UPDATE_MASK]; - */ #ifdef warningmsg #pragma warningmsg("FIXME: make antilag optionally support non-player ents too") #endif diff --git a/engine/server/svhl_game.c b/engine/server/svhl_game.c index dcf008a0..99562f13 100644 --- a/engine/server/svhl_game.c +++ b/engine/server/svhl_game.c @@ -23,12 +23,12 @@ I think globals.maxentities is the hard cap, rather than current max like in q1. //I hope you're c99 and have a __func__ #endif -extern cvar_t temp1; +//extern cvar_t temp1; #define ignore(s) Con_DPrintf("Fixme: " s "\n") #define notimpl(l) Con_Printf("halflife sv builtin not implemented on line %i\n", l) #define notimpf(f) Con_Printf("halflife sv builtin %s not implemented\n", f) -#define bi_begin() if (temp1.ival)Con_Printf("enter %s\n", __func__) -#define bi_end() if (temp1.ival)Con_Printf("leave %s\n", __func__) +#define bi_begin() //if (temp1.ival)Con_Printf("enter %s\n", __func__) +#define bi_end() //if (temp1.ival)Con_Printf("leave %s\n", __func__) #define bi_trace() bi_begin(); bi_end() @@ -2055,7 +2055,6 @@ static void SVHL_RunCmdR(hledict_t *ed, usercmd_t *ucmd) { int i; hledict_t *other; -extern cvar_t temp1; // chop up very long commands if (ucmd->msec > 50) diff --git a/engine/server/svq2_game.c b/engine/server/svq2_game.c index fa94347e..39fac965 100644 --- a/engine/server/svq2_game.c +++ b/engine/server/svq2_game.c @@ -687,12 +687,25 @@ static int VARGS SVQ2_PointContents (vec3_t p) static cvar_t *VARGS Q2Cvar_Get (const char *var_name, const char *value, int flags) { - cvar_t *var = Cvar_Get(var_name, value, flags, "Quake2 game variables"); + cvar_t *var; + //q2 gamecode knows about these flags. anything else is probably a bug, or 3rd-party extension. + flags &= (CVAR_NOSET|CVAR_SERVERINFO|CVAR_USERINFO|CVAR_ARCHIVE|CVAR_LATCH); + + var = Cvar_Get(var_name, value, flags, "Quake2 game variables"); if (!var) { Con_Printf("Q2Cvar_Get: variable %s not creatable\n", var_name); return NULL; } + + //allow this to change all < cvar_latch values. + //this allows q2 dlls to apply different flags to a cvar without destroying our important ones (like cheat). + flags |= var->flags; + if (flags != var->flags) + { + var->flags = flags; + Cvar_Set(var, var->string); + } return var; } diff --git a/engine/server/svq3_game.c b/engine/server/svq3_game.c index e345e75e..1c977c19 100644 --- a/engine/server/svq3_game.c +++ b/engine/server/svq3_game.c @@ -18,7 +18,7 @@ #define Z_TAG_BOTLIB 221726 -botlib_export_t *FTE_GetBotLibAPI(int apiVersion, botlib_import_t *import) +static botlib_export_t *FTE_GetBotLibAPI(int apiVersion, botlib_import_t *import) { //a stub that will prevent botlib from loading. #ifdef BOTLIB_STATIC return GetBotLibAPI(apiVersion, import); @@ -1598,22 +1598,22 @@ static int QDECL BL_FOpenFile(const char *name, fileHandle_t *handle, fsMode_t m { return VM_fopen((char*)name, (int*)handle, mode, Z_TAG_BOTLIB); } -static int QDECL BL_FRead( void *buffer, int len, fileHandle_t f ) +static int QDECL BL_FRead(void *buffer, int len, fileHandle_t f) { return VM_FRead(buffer, len, (int)f, Z_TAG_BOTLIB); } -//int BL_FWrite( const void *buffer, int len, fileHandle_t f ) -//{ -// return VM_FWrite(buffer, len, f, Z_TAG_BOTLIB); -//} -static void QDECL BL_FCloseFile( fileHandle_t f ) +static int QDECL BL_FWrite(const void *buffer, int len, fileHandle_t f) +{ + return VM_FWrite(buffer, len, (int)f, Z_TAG_BOTLIB); +} +static void QDECL BL_FCloseFile(fileHandle_t f) { VM_fclose((int)f, Z_TAG_BOTLIB); } -//int BL_Seek( fileHandle_t f ) -//{ -// VM_fseek(f, Z_TAG_BOTLIB) -//} +static int QDECL BL_Seek(fileHandle_t f, long offset, int seektype) +{ // on success, apparently returns 0 + return VM_FSeek((int)f, offset, seektype, Z_TAG_BOTLIB)?0:-1; +} static char *QDECL BL_BSPEntityData(void) { return sv.world.worldmodel->entities; @@ -1705,6 +1705,12 @@ static void QDECL BL_BotClientCommand(int clientnum, char *command) VM_Call(q3gamevm, GAME_CLIENT_COMMAND, clientnum); } +static int QDECL BL_DebugLineCreate(void) {return 0;} +static void QDECL BL_DebugLineDelete(int line) {} +static void QDECL BL_DebugLineShow(int line, vec3_t start, vec3_t end, int color) {} +static int QDECL BL_DebugPolygonCreate(int color, int numPoints, vec3_t *points) {return 0;} +static void QDECL BL_DebugPolygonDelete(int id) {} + #endif static void SV_InitBotLib(void) @@ -1731,15 +1737,15 @@ static void SV_InitBotLib(void) import.HunkAlloc = BL_HunkMalloc; import.FS_FOpenFile = BL_FOpenFile; import.FS_Read = BL_FRead; -// import.FS_Write = BL_FWrite; + import.FS_Write = BL_FWrite; import.FS_FCloseFile = BL_FCloseFile; -// import.FS_Seek = BL_Seek; -// import.DebugLineCreate -// import.DebugLineDelete -// import.DebugLineShow -// -// import.DebugPolygonCreate -// import.DebugPolygonDelete + import.FS_Seek = BL_Seek; + + import.DebugLineCreate = BL_DebugLineCreate; + import.DebugLineDelete = BL_DebugLineDelete; + import.DebugLineShow = BL_DebugLineShow; + import.DebugPolygonCreate= BL_DebugPolygonCreate; + import.DebugPolygonDelete = BL_DebugPolygonDelete; // Z_FreeTags(Z_TAG_BOTLIB); botlibmemoryavailable = 1024*1024*16; diff --git a/engine/shaders/glsl/altwater.glsl b/engine/shaders/glsl/altwater.glsl index 4e3a3312..ee72c3ba 100644 --- a/engine/shaders/glsl/altwater.glsl +++ b/engine/shaders/glsl/altwater.glsl @@ -1,25 +1,71 @@ -!!cvarf r_glsl_turbscale -//modifier: REFLECT (s_t2 is a reflection instead of diffusemap) -//modifier: STRENGTH (0.1 = fairly gentle, 0.2 = big waves) -//modifier: FRESNEL (5=water) -//modifier: TXSCALE (0.2 - wave strength) -//modifier: RIPPLEMAP (s_t3 contains a ripplemap -//modifier: TINT (some colour value) +!!cvardf r_glsl_turbscale_reflect=1 //simpler scaler +!!cvardf r_glsl_turbscale_refract=1 //simpler scaler +!!samps 4 diffuse +#include "sys/defs.h" + +//modifier: REFLECT (s_t2 is a reflection instead of diffusemap) +//modifier: STRENGTH_REFL (distortion strength - 0.1 = fairly gentle, 0.2 = big waves) +//modifier: STRENGTH_REFL (distortion strength - 0.1 = fairly gentle, 0.2 = big waves) +//modifier: FRESNEL_EXP (5=water) +//modifier: TXSCALE (wave size - 0.2) +//modifier: RIPPLEMAP (s_t3 contains a ripplemap +//modifier: TINT_REFR (some colour value) +//modifier: TINT_REFL (some colour value) +//modifier: ALPHA (mix in the normal water texture over the top) +//modifier: USEMODS (use single-texture scrolling via tcmods - note, also forces the engine to actually use tcmod etc) + +//a few notes on DP compat: +//'dpwater' makes numerous assumptions about DP internals +//by default there is a single pass that uses the pass's normal tcmods +//the fresnel has a user-supplied min+max rather than an exponent +//both parts are tinted individually +//if alpha is enabled, the regular water texture is blended over the top, again using the same crappy tcmods... + +//legacy crap #ifndef FRESNEL #define FRESNEL 5.0 #endif +#ifndef TINT +#define TINT 0.7,0.8,0.7 +#endif #ifndef STRENGTH #define STRENGTH 0.1 #endif #ifndef TXSCALE #define TXSCALE 0.2 #endif -#ifndef TINT -#define TINT vec3(0.7, 0.8, 0.7) + +//current values (referring to legacy defaults where needed) +#ifndef FRESNEL_EXP +#define FRESNEL_EXP 5.0 +#endif +#ifndef FRESNEL_MIN +#define FRESNEL_MIN 0.0 +#endif +#ifndef FRESNEL_RANGE +#define FRESNEL_RANGE 1.0 +#endif +#ifndef STRENGTH_REFL +#define STRENGTH_REFL STRENGTH +#endif +#ifndef STRENGTH_REFR +#define STRENGTH_REFR STRENGTH +#endif +#ifndef TXSCALE1 +#define TXSCALE1 TXSCALE +#endif +#ifndef TXSCALE2 +#define TXSCALE2 TXSCALE +#endif +#ifndef TINT_REFR +#define TINT_REFR TINT +#endif +#ifndef TINT_REFL +#define TINT_REFL 1.0,1.0,1.0 #endif #ifndef FOGTINT -#define FOGTINT vec3(0.2, 0.3, 0.2) +#define FOGTINT 0.2,0.3,0.2 #endif varying vec2 tc; @@ -27,9 +73,6 @@ varying vec4 tf; varying vec3 norm; varying vec3 eye; #ifdef VERTEX_SHADER -attribute vec2 v_texcoord; -attribute vec3 v_normal; -uniform vec3 e_eyepos; void main (void) { tc = v_texcoord.st; @@ -40,45 +83,48 @@ void main (void) } #endif #ifdef FRAGMENT_SHADER +#ifdef ALPHA +#include "sys/fog.h" +#endif + + #define s_refract s_t0 #define s_reflect s_t1 #define s_ripplemap s_t2 #define s_refractdepth s_t3 -uniform float cvar_r_glsl_turbscale; -uniform sampler2D s_normalmap; -uniform sampler2D s_diffuse; -uniform sampler2D s_refract; //refract -uniform sampler2D s_reflect; //reflection -uniform sampler2D s_refractdepth; //refraction depth -uniform sampler2D s_ripplemap; //ripplemap - -uniform float e_time; void main (void) { - vec2 stc, ntc; + vec2 stc; //screen tex coords + vec2 ntc; //normalmap/diffuse tex coords vec3 n, refr, refl; float fres; float depth; stc = (1.0 + (tf.xy / tf.w)) * 0.5; - //hack the texture coords slightly so that there are no obvious gaps + //hack the texture coords slightly so that there are less obvious gaps stc.t -= 1.5*norm.z/1080.0; +#if 0//def USEMODS + ntc = tc; + n = texture2D(s_normalmap, ntc).xyz - 0.5; +#else //apply q1-style warp, just for kicks ntc.s = tc.s + sin(tc.t+e_time)*0.125; ntc.t = tc.t + sin(tc.s+e_time)*0.125; //generate the two wave patterns from the normalmap - n = (texture2D(s_normalmap, TXSCALE*tc + vec2(e_time*0.1, 0.0)).xyz); - n += (texture2D(s_normalmap, TXSCALE*tc - vec2(0, e_time*0.097)).xyz); + n = (texture2D(s_normalmap, vec2(TXSCALE1)*tc + vec2(e_time*0.1, 0.0)).xyz); + n += (texture2D(s_normalmap, vec2(TXSCALE2)*tc - vec2(0, e_time*0.097)).xyz); n -= 1.0 - 4.0/256.0; +#endif #ifdef RIPPLEMAP n += texture2D(s_ripplemap, stc).rgb*3.0; #endif + n = normalize(n); //the fresnel term decides how transparent the water should be - fres = pow(1.0-abs(dot(normalize(n), normalize(eye))), float(FRESNEL)); + fres = pow(1.0-abs(dot(n, normalize(eye))), float(FRESNEL_EXP)) * float(FRESNEL_RANGE) + float(FRESNEL_MIN); #ifdef DEPTH float far = #include "cvar/gl_maxdist"; @@ -111,22 +157,30 @@ void main (void) //refraction image (and water fog, if possible) - refr = texture2D(s_refract, stc + n.st*STRENGTH*cvar_r_glsl_turbscale).rgb * TINT; + refr = texture2D(s_refract, stc + n.st*float(STRENGTH_REFR)*float(r_glsl_turbscale_refract)).rgb * vec3(TINT_REFR); #ifdef DEPTH - refr = mix(refr, FOGTINT, min(depth/4096.0, 1.0)); + refr = mix(refr, vec3(FOGTINT), min(depth/4096.0, 1.0)); #endif //reflection/diffuse #ifdef REFLECT - refl = texture2D(s_reflect, stc - n.st*STRENGTH*cvar_r_glsl_turbscale).rgb; + refl = texture2D(s_reflect, stc - n.st*float(STRENGTH_REFL)*float(r_glsl_turbscale_reflect)).rgb * vec3(TINT_REFL); #else - refl = texture2D(s_diffuse, ntc).xyz; + refl = texture2D(s_diffuse, ntc).xyz * vec3(TINT_REFL); #endif - //FIXME: add specular - //interplate by fresnel refr = mix(refr, refl, fres); + + + + +#ifdef ALPHA + vec4 ts = texture2D(s_diffuse, ntc); + vec4 surf = fog4blend(vec4(ts.rgb, float(ALPHA)*ts.a)); + refr = mix(refr, surf.rgb, surf.a); +#endif + //done gl_FragColor = vec4(refr, 1.0); } diff --git a/engine/sw/sw.h b/engine/sw/sw.h index 691ea38d..503558ad 100644 --- a/engine/sw/sw.h +++ b/engine/sw/sw.h @@ -148,7 +148,7 @@ void SWRast_Sync(struct workqueue_s *wq); qboolean SW_VID_Init(rendererstate_t *info, unsigned char *palette); void SW_VID_DeInit(void); -qboolean SW_VID_ApplyGammaRamps (unsigned short *ramps); +qboolean SW_VID_ApplyGammaRamps (unsigned int rampcount, unsigned short *ramps); char *SW_VID_GetRGBInfo(int *truevidwidth, int *truevidheight, enum uploadfmt *fmt); void SW_VID_SetWindowCaption(const char *msg); void SW_VID_SwapBuffers(void); diff --git a/engine/vk/vk_backend.c b/engine/vk/vk_backend.c index f1af8b68..d126b4cb 100644 --- a/engine/vk/vk_backend.c +++ b/engine/vk/vk_backend.c @@ -1484,14 +1484,6 @@ void VKBE_InitFramePools(struct vkframe *frame) VkAssert(vkAllocateCommandBuffers(vk.device, &cbai, &frame->cbuf)); } - { - VkSemaphoreCreateInfo seminfo = {VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO}; -#ifndef THREADACQUIRE - VkAssert(vkCreateSemaphore(vk.device, &seminfo, vkallocationcb, &frame->vsyncsemaphore)); -#endif - VkAssert(vkCreateSemaphore(vk.device, &seminfo, vkallocationcb, &frame->presentsemaphore)); - } - { VkFenceCreateInfo fci = {VK_STRUCTURE_TYPE_FENCE_CREATE_INFO}; fci.flags = VK_FENCE_CREATE_SIGNALED_BIT; @@ -3299,8 +3291,13 @@ static void BE_DrawMeshChain_Internal(void) for (mno = 0, vertcount = 0; mno < shaderstate.nummeshes; mno++) { m = shaderstate.meshlist[mno]; - for (i = 0; i < m->numindexes; i++) - map[i] = m->indexes[i]+vertcount; + if (!vertcount) + memcpy(map, m->indexes, sizeof(index_t)*m->numindexes); + else + { + for (i = 0; i < m->numindexes; i++) + map[i] = m->indexes[i]+vertcount; + } map += m->numindexes; vertcount += m->numvertexes; } @@ -3802,6 +3799,9 @@ void VKBE_GenBatchVBOs(vbo_t **vbochain, batch_t *firstbatch, batch_t *stopbatch } } + if (!maxvboverts || !maxvboelements) + return; + //determine array offsets. vbovdatastart = vbovdata = NULL; vbo->coord.vk.offs = vbovdata-vbovdatastart; vbovdata += sizeof(vecV_t)*maxvboverts; @@ -5687,7 +5687,10 @@ static void VK_TerminateShadowMap(void) unsigned int sbuf, i; if (vk.shadow_renderpass != VK_NULL_HANDLE) + { vkDestroyRenderPass(vk.device, vk.shadow_renderpass, vkallocationcb); + vk.shadow_renderpass = VK_NULL_HANDLE; + } for (sbuf = 0; sbuf < countof(shaderstate.shadow); sbuf++) { diff --git a/engine/vk/vk_init.c b/engine/vk/vk_init.c index 3866dd5e..beb3f2d2 100644 --- a/engine/vk/vk_init.c +++ b/engine/vk/vk_init.c @@ -9,6 +9,7 @@ extern qboolean vid_isfullscreen; extern cvar_t vk_submissionthread; extern cvar_t vk_debug; extern cvar_t vk_loadglsl; +extern cvar_t vk_dualqueue; extern cvar_t vid_srgb, vid_vsync, vid_triplebuffer, r_stereo_method; void R2D_Console_Resize(void); @@ -17,6 +18,7 @@ const char *vklayerlist[] = #if 1 "VK_LAYER_LUNARG_standard_validation" #else + //older versions of the sdk were crashing out on me, // "VK_LAYER_LUNARG_api_dump", "VK_LAYER_LUNARG_device_limits", //"VK_LAYER_LUNARG_draw_state", @@ -52,6 +54,7 @@ static void VK_Submit_DoWork(void); static void VK_DestroyRenderPass(void); static void VK_CreateRenderPass(void); +static void VK_Shutdown_PostProc(void); struct vulkaninfo_s vk; static struct vk_rendertarg postproc[4]; @@ -152,13 +155,12 @@ static void VK_DestroySwapChain(void) Sys_WaitOnThread(vk.submitthread); vk.submitthread = NULL; } -#ifdef THREADACQUIRE + vk.dopresent(NULL); while (vk.aquirenext < vk.aquirelast) { - VkAssert(vkWaitForFences(vk.device, 1, &vk.acquirefences[vk.aquirenext%ACQUIRELIMIT], VK_FALSE, UINT64_MAX)); + VkWarnAssert(vkWaitForFences(vk.device, 1, &vk.acquirefences[vk.aquirenext%ACQUIRELIMIT], VK_FALSE, UINT64_MAX)); vk.aquirenext++; } -#endif while (vk.work) { Sys_LockConditional(vk.submitcondition); @@ -197,10 +199,10 @@ static void VK_DestroySwapChain(void) VK_DestroyVkTexture(&vk.backbufs[i].depth); } -#ifdef THREADACQUIRE + vk.dopresent(NULL); while (vk.aquirenext < vk.aquirelast) { - VkAssert(vkWaitForFences(vk.device, 1, &vk.acquirefences[vk.aquirenext%ACQUIRELIMIT], VK_FALSE, UINT64_MAX)); + VkWarnAssert(vkWaitForFences(vk.device, 1, &vk.acquirefences[vk.aquirenext%ACQUIRELIMIT], VK_FALSE, UINT64_MAX)); vk.aquirenext++; } for (i = 0; i < ACQUIRELIMIT; i++) @@ -209,7 +211,6 @@ static void VK_DestroySwapChain(void) vkDestroyFence(vk.device, vk.acquirefences[i], vkallocationcb); vk.acquirefences[i] = VK_NULL_HANDLE; } -#endif while(vk.unusedframes) { @@ -220,10 +221,6 @@ static void VK_DestroySwapChain(void) vkResetCommandBuffer(frame->cbuf, VK_COMMAND_BUFFER_RESET_RELEASE_RESOURCES_BIT); vkFreeCommandBuffers(vk.device, vk.cmdpool, 1, &frame->cbuf); -#ifndef THREADACQUIRE - vkDestroySemaphore(vk.device, frame->vsyncsemaphore, vkallocationcb); -#endif - vkDestroySemaphore(vk.device, frame->presentsemaphore, vkallocationcb); vkDestroyFence(vk.device, frame->finishedfence, vkallocationcb); Z_Free(frame); } @@ -255,6 +252,8 @@ static qboolean VK_CreateSwapChain(void) VkImageView attachments[2]; VkFramebufferCreateInfo fb_info = {VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO}; + vk.dopresent(NULL); //make sure they're all pushed through. + VkAssert(vkGetPhysicalDeviceSurfaceFormatsKHR(vk.gpu, vk.surface, &fmtcount, NULL)); surffmts = malloc(sizeof(VkSurfaceFormatKHR)*fmtcount); VkAssert(vkGetPhysicalDeviceSurfaceFormatsKHR(vk.gpu, vk.surface, &fmtcount, surffmts)); @@ -375,7 +374,6 @@ static qboolean VK_CreateSwapChain(void) images = malloc(sizeof(VkImage)*vk.backbuf_count); VkAssert(vkGetSwapchainImagesKHR(vk.device, vk.swapchain, &vk.backbuf_count, images)); -#ifdef THREADACQUIRE vk.aquirelast = vk.aquirenext = 0; for (i = 0; i < ACQUIRELIMIT; i++) { @@ -388,7 +386,6 @@ static qboolean VK_CreateSwapChain(void) VkAssert(vkAcquireNextImageKHR(vk.device, vk.swapchain, UINT64_MAX, VK_NULL_HANDLE, vk.acquirefences[vk.aquirelast%ACQUIRELIMIT], &vk.acquirebufferidx[vk.aquirelast%ACQUIRELIMIT])); vk.aquirelast++; } -#endif VK_CreateRenderPass(); if (reloadshaders) @@ -429,6 +426,8 @@ static qboolean VK_CreateSwapChain(void) vk.backbufs[i].colour.image = images[i]; VkAssert(vkCreateImageView(vk.device, &ivci, vkallocationcb, &vk.backbufs[i].colour.view)); + vk.backbufs[i].firstuse = true; + { VkImageCreateInfo depthinfo = {VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO}; depthinfo.flags = 0; @@ -481,6 +480,11 @@ static qboolean VK_CreateSwapChain(void) attachments[0] = vk.backbufs[i].colour.view; VkAssert(vkCreateFramebuffer(vk.device, &fb_info, vkallocationcb, &vk.backbufs[i].framebuffer)); + + { + VkSemaphoreCreateInfo seminfo = {VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO}; + VkAssert(vkCreateSemaphore(vk.device, &seminfo, vkallocationcb, &vk.backbufs[i].presentsemaphore)); + } } free(images); @@ -1086,6 +1090,7 @@ void VK_R_DeInit (void) { R_GAliasFlushSkinCache(true); Surf_DeInit(); + VK_Shutdown_PostProc(); VK_DestroySwapChain(); VKBE_Shutdown(); Shader_Shutdown(); @@ -1203,7 +1208,17 @@ void VK_Set2D(void) BE_SelectEntity(&r_worldentity); } -void VK_Init_PostProc(void) +static void VK_Shutdown_PostProc(void) +{ + unsigned int i; + for (i = 0; i < countof(postproc); i++) + VKBE_RT_Gen(&postproc[i], 0, 0, true); + + vk.scenepp_waterwarp = NULL; + vk.scenepp_antialias = NULL; + VK_R_BloomShutdown(); +} +static void VK_Init_PostProc(void) { texid_t scenepp_texture_warp, scenepp_texture_edge; //this block liberated from the opengl code @@ -1641,15 +1656,23 @@ void VK_R_RenderView (void) } custompostproc = NULL; - if (!(r_refdef.flags & RDF_NOWORLDMODEL) && (*r_postprocshader.string)) + if (r_refdef.flags & RDF_NOWORLDMODEL) + renderscale = 1; //with no worldmodel, this is probably meant to be transparent so make sure that there's no post-proc stuff messing up transparencies. + else { - custompostproc = R_RegisterCustom(r_postprocshader.string, SUF_NONE, NULL, NULL); - if (custompostproc) - r_refdef.flags |= RDF_CUSTOMPOSTPROC; - } + if (*r_postprocshader.string) + { + custompostproc = R_RegisterCustom(r_postprocshader.string, SUF_NONE, NULL, NULL); + if (custompostproc) + r_refdef.flags |= RDF_CUSTOMPOSTPROC; + } - if (!(r_refdef.flags & RDF_NOWORLDMODEL) && r_fxaa.ival) //overlays will have problems. - r_refdef.flags |= RDF_ANTIALIAS; + if (r_fxaa.ival) //overlays will have problems. + r_refdef.flags |= RDF_ANTIALIAS; + + if (R_CanBloom()) + r_refdef.flags |= RDF_BLOOM; + } // // figure out the viewport @@ -1691,9 +1714,6 @@ void VK_R_RenderView (void) //FIXME: VF_RT_* //FIXME: if we're meant to be using msaa, render the scene to an msaa target and then resolve. - if (R_CanBloom()) - r_refdef.flags |= RDF_BLOOM; - postproc_buf = 0; if (r_refdef.flags & (RDF_ALLPOSTPROC|RDF_RENDERSCALE)) { @@ -2085,9 +2105,6 @@ static void VK_PaintScreen(void) qboolean VK_SCR_GrabBackBuffer(void) { RSpeedLocals(); -#ifndef THREADACQUIRE - VkResult err; -#endif if (vk.frame) //erk, we already have one... return true; @@ -2104,7 +2121,6 @@ qboolean VK_SCR_GrabBackBuffer(void) vk.unusedframes = newframe; } -#ifdef THREADACQUIRE while (vk.aquirenext == vk.aquirelast) { //we're still waiting for the render thread to increment acquirelast. Sys_Sleep(0); //o.O @@ -2114,7 +2130,13 @@ qboolean VK_SCR_GrabBackBuffer(void) if (1)//vk.vsync) { //friendly wait - VkAssert(vkWaitForFences(vk.device, 1, &vk.acquirefences[vk.aquirenext%ACQUIRELIMIT], VK_FALSE, UINT64_MAX)); + VkResult err = vkWaitForFences(vk.device, 1, &vk.acquirefences[vk.aquirenext%ACQUIRELIMIT], VK_FALSE, UINT64_MAX); + if (err) + { + if (err == VK_ERROR_DEVICE_LOST) + Sys_Error("Vulkan device lost"); + return false; + } } else { //busy wait, to try to get the highest fps possible @@ -2124,37 +2146,6 @@ qboolean VK_SCR_GrabBackBuffer(void) vk.bufferidx = vk.acquirebufferidx[vk.aquirenext%ACQUIRELIMIT]; VkAssert(vkResetFences(vk.device, 1, &vk.acquirefences[vk.aquirenext%ACQUIRELIMIT])); vk.aquirenext++; -#else - Sys_LockMutex(vk.swapchain_mutex); - err = vkAcquireNextImageKHR(vk.device, vk.swapchain, UINT64_MAX, vk.unusedframes->vsyncsemaphore, vk.acquirefence, &vk.bufferidx); - Sys_UnlockMutex(vk.swapchain_mutex); - switch(err) - { - case VK_ERROR_OUT_OF_DATE_KHR: - vk.neednewswapchain = true; - return false; - case VK_SUBOPTIMAL_KHR: - vk.neednewswapchain = true; - break; //this is still a success - case VK_SUCCESS: - break; //yay - case VK_ERROR_SURFACE_LOST_KHR: - //window was destroyed. - //shouldn't really happen... - return false; - case VK_NOT_READY: //VK_NOT_READY is returned if timeout is zero and no image was available. (timeout is not 0) - RSpeedEnd(RSPEED_SETUP); - Con_DPrintf("vkAcquireNextImageKHR: unexpected VK_NOT_READY\n"); - return false; //timed out - case VK_TIMEOUT: //VK_TIMEOUT is returned if timeout is greater than zero and less than UINT64_MAX, and no image became available within the time allowed. - RSpeedEnd(RSPEED_SETUP); - Con_DPrintf("vkAcquireNextImageKHR: unexpected VK_TIMEOUT\n"); - return false; //timed out - default: - Sys_Error("vkAcquireNextImageKHR == %i", err); - break; - } -#endif //grab the first unused Sys_LockConditional(vk.submitcondition); @@ -2199,7 +2190,7 @@ qboolean VK_SCR_GrabBackBuffer(void) imgbarrier.pNext = NULL; imgbarrier.srcAccessMask = VK_ACCESS_MEMORY_READ_BIT; imgbarrier.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; - imgbarrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;// VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; //'Alternately, oldLayout can be VK_IMAGE_LAYOUT_UNDEFINED, if the image’s contents need not be preserved.' + imgbarrier.oldLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; //'Alternately, oldLayout can be VK_IMAGE_LAYOUT_UNDEFINED, if the image’s contents need not be preserved.' imgbarrier.newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; imgbarrier.image = vk.frame->backbuf->colour.image; imgbarrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; @@ -2207,8 +2198,15 @@ qboolean VK_SCR_GrabBackBuffer(void) imgbarrier.subresourceRange.levelCount = 1; imgbarrier.subresourceRange.baseArrayLayer = 0; imgbarrier.subresourceRange.layerCount = 1; - imgbarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - imgbarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + imgbarrier.srcQueueFamilyIndex = vk.queuefam[1]; + imgbarrier.dstQueueFamilyIndex = vk.queuefam[0]; + if (vk.frame->backbuf->firstuse) + { + imgbarrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED; + imgbarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + imgbarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + vk.frame->backbuf->firstuse = false; + } vkCmdPipelineBarrier(vk.frame->cbuf, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 0, 0, NULL, 0, NULL, 1, &imgbarrier); } { @@ -2390,8 +2388,8 @@ qboolean VK_SCR_UpdateScreen (void) imgbarrier.subresourceRange.levelCount = 1; imgbarrier.subresourceRange.baseArrayLayer = 0; imgbarrier.subresourceRange.layerCount = 1; - imgbarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - imgbarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + imgbarrier.srcQueueFamilyIndex = vk.queuefam[0]; + imgbarrier.dstQueueFamilyIndex = vk.queuefam[1]; vkCmdPipelineBarrier(vk.frame->cbuf, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, 0, 0, NULL, 0, NULL, 1, &imgbarrier); } @@ -2402,16 +2400,6 @@ qboolean VK_SCR_UpdateScreen (void) bufs[0] = vk.frame->cbuf; -#ifndef THREADACQUIRE - { - RSpeedRemark(); - //make sure we actually got a buffer. required for vsync - VkAssert(vkWaitForFences(vk.device, 1, &vk.acquirefence, VK_FALSE, UINT64_MAX)); - VkAssert(vkResetFences(vk.device, 1, &vk.acquirefence)); - RSpeedEnd(RSPEED_SETUP); - } -#endif - { struct vk_presented *fw = Z_Malloc(sizeof(*fw)); fw->fw.Passed = VK_Presented; @@ -2421,13 +2409,7 @@ qboolean VK_SCR_UpdateScreen (void) vk.frame->frameendjobs = vk.frameendjobs; vk.frameendjobs = NULL; - VK_Submit_Work(bufs[0], -#ifndef THREADACQUIRE - vk.frame->vsyncsemaphore -#else - VK_NULL_HANDLE -#endif - , VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, vk.frame->presentsemaphore, vk.frame->finishedfence, vk.frame, &fw->fw); + VK_Submit_Work(bufs[0], VK_NULL_HANDLE, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, vk.frame->backbuf->presentsemaphore, vk.frame->finishedfence, vk.frame, &fw->fw); } //now would be a good time to do any compute work or lightmap updates... @@ -2538,6 +2520,46 @@ static VkRenderPassCreateInfo rp_info = {VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_I } } +void VK_DoPresent(struct vkframe *theframe) +{ + VkResult err; + uint32_t framenum; + VkPresentInfoKHR presinfo = {VK_STRUCTURE_TYPE_PRESENT_INFO_KHR}; + if (!theframe) + return; //used to ensure that the queue is flushed at shutdown + framenum = theframe->backbuf - vk.backbufs; + presinfo.waitSemaphoreCount = 1; + presinfo.pWaitSemaphores = &theframe->backbuf->presentsemaphore; + presinfo.swapchainCount = 1; + presinfo.pSwapchains = &vk.swapchain; + presinfo.pImageIndices = &framenum; + + { + RSpeedMark(); + err = vkQueuePresentKHR(vk.queue_present, &presinfo); + RSpeedEnd(RSPEED_PRESENT); + } + { + RSpeedMark(); + if (err) + { + Con_Printf("ERROR: vkQueuePresentKHR: %x\n", err); + vk.neednewswapchain = true; + } + else + { + err = vkAcquireNextImageKHR(vk.device, vk.swapchain, 0, VK_NULL_HANDLE, vk.acquirefences[vk.aquirelast%ACQUIRELIMIT], &vk.acquirebufferidx[vk.aquirelast%ACQUIRELIMIT]); + if (err) + { + Con_Printf("ERROR: vkAcquireNextImageKHR: %x\n", err); + vk.neednewswapchain = true; + } + vk.aquirelast++; + } + RSpeedEnd(RSPEED_ACQUIRE); + } +} + static void VK_Submit_DoWork(void) { VkCommandBuffer cbuf[64]; @@ -2588,50 +2610,15 @@ static void VK_Submit_DoWork(void) err = vkQueueSubmit(vk.queue_render, subcount, subinfo, waitfence); if (err) { - Con_Printf("ERROR: vkQueueSubmit: %x\n", err); + Con_Printf("ERROR: vkQueueSubmit: %i\n", err); errored = vk.neednewswapchain = true; } RSpeedEnd(RSPEED_SUBMIT); } - if (present) + if (present && !errored) { -// struct vkframe **link; - uint32_t framenum = present->backbuf - vk.backbufs; - VkPresentInfoKHR presinfo = {VK_STRUCTURE_TYPE_PRESENT_INFO_KHR}; - presinfo.waitSemaphoreCount = 1; - presinfo.pWaitSemaphores = &present->presentsemaphore; - presinfo.swapchainCount = 1; - presinfo.pSwapchains = &vk.swapchain; - presinfo.pImageIndices = &framenum; - - if (!errored) - { - RSpeedMark(); - Sys_LockMutex(vk.swapchain_mutex); - err = vkQueuePresentKHR(vk.queue_present, &presinfo); - Sys_UnlockMutex(vk.swapchain_mutex); - RSpeedEnd(RSPEED_PRESENT); - RSpeedRemark(); - if (err) - { - Con_Printf("ERROR: vkQueuePresentKHR: %x\n", err); - errored = vk.neednewswapchain = true; - } -#ifdef THREADACQUIRE - else - { - err = vkAcquireNextImageKHR(vk.device, vk.swapchain, 0, VK_NULL_HANDLE, vk.acquirefences[vk.aquirelast%ACQUIRELIMIT], &vk.acquirebufferidx[vk.aquirelast%ACQUIRELIMIT]); - if (err) - { - Con_Printf("ERROR: vkAcquireNextImageKHR: %x\n", err); - errored = vk.neednewswapchain = true; - } - vk.aquirelast++; - } -#endif - RSpeedEnd(RSPEED_ACQUIRE); - } + vk.dopresent(present); } Sys_LockConditional(vk.submitcondition); @@ -2660,9 +2647,6 @@ int VK_Submit_Thread(void *arg) Sys_ConditionWait(vk.submitcondition); VK_Submit_DoWork(); - - //Sys_ConditionSignal(vk.acquirecondition); - } Sys_UnlockConditional(vk.submitcondition); return true; @@ -2745,8 +2729,9 @@ void VK_CheckTextureFormats(void) } //initialise the vulkan instance, context, device, etc. -qboolean VK_Init(rendererstate_t *info, const char *sysextname, qboolean (*createSurface)(void)) +qboolean VK_Init(rendererstate_t *info, const char *sysextname, qboolean (*createSurface)(void), void (*dopresent)(struct vkframe *theframe)) { + VkQueueFamilyProperties *queueprops; VkResult err; VkApplicationInfo app; VkInstanceCreateInfo inst_info; @@ -2761,6 +2746,7 @@ qboolean VK_Init(rendererstate_t *info, const char *sysextname, qboolean (*creat vk.neednewswapchain = true; vk.triplebuffer = info->triplebuffer; vk.vsync = info->wait; + vk.dopresent = dopresent?dopresent:VK_DoPresent; memset(&sh_config, 0, sizeof(sh_config)); @@ -2974,34 +2960,64 @@ qboolean VK_Init(rendererstate_t *info, const char *sysextname, qboolean (*creat //figure out which of the device's queue's we're going to use { uint32_t queue_count, i; - VkQueueFamilyProperties *queueprops; vkGetPhysicalDeviceQueueFamilyProperties(vk.gpu, &queue_count, NULL); queueprops = malloc(sizeof(VkQueueFamilyProperties)*queue_count); //Oh how I wish I was able to use C99. vkGetPhysicalDeviceQueueFamilyProperties(vk.gpu, &queue_count, queueprops); - vk.queueidx[0] = ~0u; - vk.queueidx[1] = ~0u; + vk.queuefam[0] = ~0u; + vk.queuefam[1] = ~0u; + vk.queuenum[0] = 0; + vk.queuenum[1] = 0; + + /* + //try to find a 'dedicated' present queue for (i = 0; i < queue_count; i++) { - VkBool32 supportsPresent; + VkBool32 supportsPresent = FALSE; VkAssert(vkGetPhysicalDeviceSurfaceSupportKHR(vk.gpu, i, vk.surface, &supportsPresent)); - if ((queueprops[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) && supportsPresent) + if (supportsPresent && !(queueprops[i].queueFlags & VK_QUEUE_GRAPHICS_BIT)) { - vk.queueidx[0] = i; - vk.queueidx[1] = i; + vk.queuefam[1] = i; break; } - else if (vk.queueidx[0] == ~0u && (queueprops[i].queueFlags & VK_QUEUE_GRAPHICS_BIT)) - vk.queueidx[0] = i; - else if (vk.queueidx[1] == ~0u && supportsPresent) - vk.queueidx[1] = i; } - free(queueprops); - - if (vk.queueidx[0] == ~0u || vk.queueidx[1] == ~0u) + if (vk.queuefam[1] != ~0u) + { //try to find a good graphics queue + for (i = 0; i < queue_count; i++) + { + if (queueprops[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) + { + vk.queuefam[0] = i; + break; + } + } + } + else*/ { + for (i = 0; i < queue_count; i++) + { + VkBool32 supportsPresent; + VkAssert(vkGetPhysicalDeviceSurfaceSupportKHR(vk.gpu, i, vk.surface, &supportsPresent)); + + if ((queueprops[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) && supportsPresent) + { + vk.queuefam[0] = i; + vk.queuefam[1] = i; + break; + } + else if (vk.queuefam[0] == ~0u && (queueprops[i].queueFlags & VK_QUEUE_GRAPHICS_BIT)) + vk.queuefam[0] = i; + else if (vk.queuefam[1] == ~0u && supportsPresent) + vk.queuefam[1] = i; + } + } + + + if (vk.queuefam[0] == ~0u || vk.queuefam[1] == ~0u) + { + free(queueprops); Con_Printf("unable to find suitable queues\n"); return false; } @@ -3023,7 +3039,7 @@ qboolean VK_Init(rendererstate_t *info, const char *sysextname, qboolean (*creat { const char *devextensions[8]; size_t numdevextensions = 0; - float queue_priorities[1] = {1.0}; + float queue_priorities[2] = {0.8, 1.0}; VkDeviceQueueCreateInfo queueinf[2] = {{VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO},{VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO}}; VkDeviceCreateInfo devinf = {VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO}; @@ -3033,15 +3049,39 @@ qboolean VK_Init(rendererstate_t *info, const char *sysextname, qboolean (*creat queueinf[0].pNext = NULL; - queueinf[0].queueFamilyIndex = vk.queueidx[0]; - queueinf[0].queueCount = countof(queue_priorities); + queueinf[0].queueFamilyIndex = vk.queuefam[0]; + queueinf[0].queueCount = 1; queueinf[0].pQueuePriorities = queue_priorities; queueinf[1].pNext = NULL; - queueinf[1].queueFamilyIndex = vk.queueidx[1]; - queueinf[1].queueCount = countof(queue_priorities); - queueinf[1].pQueuePriorities = queue_priorities; + queueinf[1].queueFamilyIndex = vk.queuefam[1]; + queueinf[1].queueCount = 1; + queueinf[1].pQueuePriorities = &queue_priorities[1]; + + if (vk.queuefam[0] == vk.queuefam[1]) + { + devinf.queueCreateInfoCount = 1; + + if (queueprops[queueinf[0].queueFamilyIndex].queueCount >= 2 && vk_dualqueue.ival) + { + queueinf[0].queueCount = 2; + vk.queuenum[1] = 1; + Con_DPrintf("Using duel queue\n"); + } + else + { + queueinf[0].queueCount = 1; + vk.dopresent = VK_DoPresent; //can't split submit+present onto different queues, so do these on a single thread. + Con_DPrintf("Using single queue\n"); + } + } + else + { + devinf.queueCreateInfoCount = 2; + Con_DPrintf("Using separate queue families\n"); + } + + free(queueprops); - devinf.queueCreateInfoCount = (vk.queueidx[0]==vk.queueidx[0])?1:2; devinf.pQueueCreateInfos = queueinf; devinf.enabledLayerCount = vklayercount; devinf.ppEnabledLayerNames = vklayerlist; @@ -3073,15 +3113,15 @@ qboolean VK_Init(rendererstate_t *info, const char *sysextname, qboolean (*creat #undef VKFunc #endif - vkGetDeviceQueue(vk.device, vk.queueidx[0], 0, &vk.queue_render); - vkGetDeviceQueue(vk.device, vk.queueidx[1], 0, &vk.queue_present); + vkGetDeviceQueue(vk.device, vk.queuefam[0], vk.queuenum[0], &vk.queue_render); + vkGetDeviceQueue(vk.device, vk.queuefam[1], vk.queuenum[1], &vk.queue_present); vkGetPhysicalDeviceMemoryProperties(vk.gpu, &vk.memory_properties); { VkCommandPoolCreateInfo cpci = {VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO}; - cpci.queueFamilyIndex = vk.queueidx[0]; + cpci.queueFamilyIndex = vk.queuefam[0]; cpci.flags = VK_COMMAND_POOL_CREATE_TRANSIENT_BIT|VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; VkAssert(vkCreateCommandPool(vk.device, &cpci, vkallocationcb, &vk.cmdpool)); } @@ -3133,25 +3173,7 @@ qboolean VK_Init(rendererstate_t *info, const char *sysextname, qboolean (*creat else //16bit depth is guarenteed in vulkan vk.depthformat = VK_FORMAT_D16_UNORM; -#ifndef THREADACQUIRE - { - VkFenceCreateInfo fci = {VK_STRUCTURE_TYPE_FENCE_CREATE_INFO}; - VkAssert(vkCreateFence(vk.device,&fci,vkallocationcb,&vk.acquirefence)); - } -#endif - -/* - void (*pDeleteProg) (program_t *prog, unsigned int permu); - qboolean (*pLoadBlob) (program_t *prog, const char *name, unsigned int permu, vfsfile_t *blobfile); - qboolean (*pCreateProgram) (program_t *prog, const char *name, unsigned int permu, int ver, const char **precompilerconstants, const char *vert, const char *tcs, const char *tes, const char *geom, const char *frag, qboolean noerrors, vfsfile_t *blobfile); - qboolean (*pValidateProgram)(program_t *prog, const char *name, unsigned int permu, qboolean noerrors, vfsfile_t *blobfile); - void (*pProgAutoFields) (program_t *prog, const char *name, cvar_t **cvars, char **cvarnames, int *cvartypes); -*/ - - - vk.swapchain_mutex = Sys_CreateMutex(); vk.submitcondition = Sys_CreateConditional(); - vk.acquirecondition = Sys_CreateConditional(); { VkPipelineCacheCreateInfo pci = {VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO}; @@ -3187,10 +3209,6 @@ void VK_Shutdown(void) if (vk.cmdpool) vkDestroyCommandPool(vk.device, vk.cmdpool, vkallocationcb); VK_DestroyRenderPass(); -#ifndef THREADACQUIRE - if (vk.acquirefence) - vkDestroyFence(vk.device, vk.acquirefence, vkallocationcb); -#endif if (vk.pipelinecache) { @@ -3212,16 +3230,14 @@ void VK_Shutdown(void) vkDestroyDebugReportCallbackEXT(vk.instance, vk_debugcallback, vkallocationcb); vk_debugcallback = VK_NULL_HANDLE; } + if (vk.surface) vkDestroySurfaceKHR(vk.instance, vk.surface, vkallocationcb); if (vk.instance) vkDestroyInstance(vk.instance, vkallocationcb); - if (vk.swapchain_mutex) - Sys_DestroyMutex(vk.swapchain_mutex); if (vk.submitcondition) Sys_DestroyConditional(vk.submitcondition); - if (vk.acquirecondition) - Sys_DestroyConditional(vk.acquirecondition); + memset(&vk, 0, sizeof(vk)); qrenderer = QR_NONE; diff --git a/engine/vk/vk_win32.c b/engine/vk/vk_win32.c index c17f2f9b..0c687b6c 100644 --- a/engine/vk/vk_win32.c +++ b/engine/vk/vk_win32.c @@ -401,12 +401,15 @@ static qboolean VID_SetFullDIBMode (rendererstate_t *info) gdevmode.dmFields |= DM_BITSPERPEL; if (info->rate) gdevmode.dmFields |= DM_DISPLAYFREQUENCY; - gdevmode.dmBitsPerPel = info->bpp; - if (info->bpp && (gdevmode.dmBitsPerPel < 15)) - { + if (info->bpp && (info->bpp < 15)) + { //low values get you a warning. otherwise only 16 and 32bit are allowed. Con_Printf("Forcing at least 15bpp\n"); gdevmode.dmBitsPerPel = 16; } + else if (info->bpp == 16) + gdevmode.dmBitsPerPel = 16; + else + gdevmode.dmBitsPerPel = 32; gdevmode.dmDisplayFrequency = info->rate; gdevmode.dmPelsWidth = info->width; gdevmode.dmPelsHeight = info->height; @@ -632,6 +635,18 @@ static qboolean VK_CreateSurface(void) return true; } +#ifdef WTHREAD +static void VK_Win32_Present(struct vkframe *theframe) +{ +// if (theframe) +// PostMessage(mainwindow, WM_USER+7, 0, (LPARAM)theframe); +// else + SendMessage(mainwindow, WM_USER+7, 0, (LPARAM)theframe); +} +#else +#define VK_Present NULL +#endif + static qboolean VID_AttachVulkan (rendererstate_t *info) { //make sure we can get a valid renderer. #ifdef VK_NO_PROTOTYPES @@ -648,7 +663,7 @@ static qboolean VID_AttachVulkan (rendererstate_t *info) vkGetInstanceProcAddr = (PFN_vkGetInstanceProcAddr) GetProcAddress(hInstVulkan, "vkGetInstanceProcAddr"); #endif - return VK_Init(info, VK_KHR_WIN32_SURFACE_EXTENSION_NAME, VK_CreateSurface); + return VK_Init(info, VK_KHR_WIN32_SURFACE_EXTENSION_NAME, VK_CreateSurface, VK_Win32_Present); } @@ -841,10 +856,6 @@ static void VKVID_Recenter_f(void) //int nx = 0; //int ny = 0; -#ifdef _MSC_VER -#define strtoull _strtoui64 -#endif - if (Cmd_Argc() > 1) sys_parentleft = atoi(Cmd_Argv(1)); if (Cmd_Argc() > 2) @@ -1438,6 +1449,9 @@ static LONG WINAPI VKMainWndProc ( STT_Event(); #endif break; + case WM_USER+7: + VK_DoPresent((struct vkframe*)lParam); + break; case WM_GETMINMAXINFO: { diff --git a/engine/vk/vkrenderer.h b/engine/vk/vkrenderer.h index 30fcccab..2ef91264 100644 --- a/engine/vk/vkrenderer.h +++ b/engine/vk/vkrenderer.h @@ -15,15 +15,14 @@ #endif #define VK_NO_PROTOTYPES -#include +#include "../vulkan/vulkan.h" #if defined(_MSC_VER) && !defined(UINT64_MAX) #define UINT64_MAX _UI64_MAX +#ifndef _UI64_MAX +#define _UI64_MAX 0xffffffffffffffffui64 +#endif #endif - -#define THREADACQUIRE //should be better behaved, with no extra locks needed. - - #ifndef VKInstWin32Funcs #define VKInstWin32Funcs @@ -168,8 +167,10 @@ #define vkallocationcb NULL #ifdef _DEBUG #define VkAssert(f) do {VkResult err = f; if (err) Sys_Error("%s == %i", #f, err); } while(0) +#define VkWarnAssert(f) do {VkResult err = f; if (err) Con_Printf("%s == %i\n", #f, err); } while(0) #else #define VkAssert(f) f +#define VkWarnAssert(f) f #endif typedef struct vk_image_s @@ -207,6 +208,8 @@ struct vk_rendertarg qboolean depthcleared; //starting a new gameview needs cleared depth relative to other views, but the first probably won't. VkRenderPassBeginInfo restartinfo; + VkSemaphore presentsemaphore; + qboolean firstuse; }; struct vk_rendertarg_cube { @@ -225,21 +228,18 @@ extern struct vulkaninfo_s VkDevice device; VkPhysicalDevice gpu; VkSurfaceKHR surface; - uint32_t queueidx[2]; //queue families, render+present + uint32_t queuefam[2]; //queue families, render+present + uint32_t queuenum[2]; //queue families, render+present VkQueue queue_render; VkQueue queue_present; VkPhysicalDeviceMemoryProperties memory_properties; VkCommandPool cmdpool; -#ifdef THREADACQUIRE #define ACQUIRELIMIT 8 VkFence acquirefences[ACQUIRELIMIT]; uint32_t acquirebufferidx[ACQUIRELIMIT]; unsigned int aquirenext; volatile unsigned int aquirelast; //set inside the submission thread -#else - VkFence acquirefence; -#endif VkPipelineCache pipelinecache; @@ -281,10 +281,6 @@ extern struct vulkaninfo_s struct vk_rendertarg *rendertarg; struct vkframe { struct vkframe *next; -#ifndef THREADACQUIRE - VkSemaphore vsyncsemaphore; -#endif - VkSemaphore presentsemaphore; VkCommandBuffer cbuf; struct dynbuffer *dynbufs[DB_MAX]; struct descpool *descpools; @@ -299,7 +295,6 @@ extern struct vulkaninfo_s VkRenderPass shadow_renderpass; //clears depth etc. VkRenderPass renderpass[3]; //initial, resume VkSwapchainKHR swapchain; - void *swapchain_mutex; //acquire+present need some syncronisation. uint32_t bufferidx; VkFormat depthformat; @@ -321,7 +316,7 @@ extern struct vulkaninfo_s } *work; void *submitthread; void *submitcondition; - void *acquirecondition; + void (*dopresent)(struct vkframe *theframe); texid_t sourcecolour; texid_t sourcedepth; @@ -344,8 +339,9 @@ uint32_t vk_find_memory_try(uint32_t typeBits, VkFlags requirements_mask); uint32_t vk_find_memory_require(uint32_t typeBits, VkFlags requirements_mask); qboolean VK_LoadTextureMips (texid_t tex, struct pendingtextureinfo *mips); +void VK_DoPresent(struct vkframe *theframe); -qboolean VK_Init(rendererstate_t *info, const char *sysextname, qboolean (*createSurface)(void)); +qboolean VK_Init(rendererstate_t *info, const char *sysextname, qboolean (*createSurface)(void), void (*dopresent)(struct vkframe *theframe)); void VK_Shutdown(void); void VK_R_BloomBlend (texid_t source, int x, int y, int w, int h); diff --git a/engine/web/ftejslib.h b/engine/web/ftejslib.h index 049ce294..9f08245a 100644 --- a/engine/web/ftejslib.h +++ b/engine/web/ftejslib.h @@ -45,12 +45,12 @@ int emscriptenfte_setupcanvas( int width, int height, void(*Resized)(int newwidth, int newheight), - void(*Mouse)(int devid,int abs,float x,float y,float z,float size), - void(*Button)(int devid, int down, int mbutton), - int(*Keyboard)(int devid, int down, int keycode, int unicode), + void(*Mouse)(unsigned int devid,int abs,float x,float y,float z,float size), + void(*Button)(unsigned int devid, int down, int mbutton), + int(*Keyboard)(unsigned int devid, int down, int keycode, int unicode), void(*LoadFile)(char *url, char *mime, int filehandle), - void(*buttonevent)(int joydev, int button, int ispressed), - void(*axisevent)(int joydev, int axis, float value), + void(*buttonevent)(unsigned int joydev, int button, int ispressed), + void(*axisevent)(unsigned int joydev, int axis, float value), int (*ShouldSwitchToFullscreen)(void) ); diff --git a/engine/web/gl_vidweb.c b/engine/web/gl_vidweb.c index 2f7c3cf7..63d026bb 100644 --- a/engine/web/gl_vidweb.c +++ b/engine/web/gl_vidweb.c @@ -16,7 +16,7 @@ static void *GLVID_getsdlglfunction(char *functionname) return NULL; } -static void IN_JoystickButtonEvent(int joydevid, int button, int ispressed) +static void IN_JoystickButtonEvent(unsigned int joydevid, int button, int ispressed) { if (button >= 32+4) return; @@ -103,7 +103,7 @@ static unsigned int domkeytoshift(unsigned int code) // Con_DPrintf("You just pressed dom key %u, which is quake key %u\n", code, tab[code]); return tab[code]; } -static int DOM_KeyEvent(int devid, int down, int scan, int uni) +static int DOM_KeyEvent(unsigned int devid, int down, int scan, int uni) { extern int shift_down; // Con_Printf("Key %s %i %i:%c\n", down?"down":"up", scan, uni, uni?(char)uni:' '); @@ -129,7 +129,7 @@ static int DOM_KeyEvent(int devid, int down, int scan, int uni) return true; // return false; } -static void DOM_ButtonEvent(int devid, int down, int button) +static void DOM_ButtonEvent(unsigned int devid, int down, int button) { if (down == 2) { diff --git a/plugins/ezhud/hud_common.c b/plugins/ezhud/hud_common.c index 4ab24a02..f3edad87 100644 --- a/plugins/ezhud/hud_common.c +++ b/plugins/ezhud/hud_common.c @@ -2960,13 +2960,13 @@ void SCR_HUD_Group9(hud_t *hud) // for frags and players typedef struct sort_teams_info_s { - char *name; - int frags; - int min_ping; - int avg_ping; - int max_ping; - int nplayers; - int top, bottom; // leader colours + char *name; + int frags; + int min_ping; + int avg_ping; + int max_ping; + int nplayers; + int top, bottom; // leader colours int rlcount; // Number of RL's present in the team. (Cokeman 2006-05-27) } sort_teams_info_t; diff --git a/plugins/irc/ircclient.c b/plugins/irc/ircclient.c index 1eb30452..f035936a 100644 --- a/plugins/irc/ircclient.c +++ b/plugins/irc/ircclient.c @@ -271,6 +271,28 @@ void IRC_SetFooter(ircclient_t *irc, const char *subname, const char *format, .. pCon_SetConsoleString(lwr, "footer", string); } } +qboolean IRC_WindowShown(ircclient_t *irc, const char *subname) +{ + char lwr[128]; + int i; + if (irc) + { + Q_strlcpy(lwr, irc->id, sizeof(lwr)); + for (i = strlen(lwr); *subname && i < sizeof(lwr)-2; i++, subname++) + { + if (*subname >= 'A' && *subname <= 'Z') + lwr[i] = *subname - 'A' + 'a'; + else + lwr[i] = *subname; + } + + lwr[i] = '\0'; + + if (BUILTINISVALID(Con_SetConsoleFloat) && pCon_GetConsoleFloat(lwr, "iswindow") < true) + return false; + } + return true; +} void IRC_Printf(ircclient_t *irc, const char *subname, const char *format, ...) { va_list argptr; @@ -1052,7 +1074,7 @@ void numbered_command(int comm, char *msg, ircclient_t *irc) // move vars up 1 m IRC_Printf(irc, DEFAULTCONSOLE, "%s\n", motdmessage); if (*irc->autochannels) - IRC_JoinChannels(irc, irc->autochannels); // note to self... "" needs to be the channel key.. so autochannels needs a recoded + IRC_JoinChannels(irc, irc->autochannels); return; } @@ -1732,7 +1754,6 @@ int IRC_ClientFrame(ircclient_t *irc) char prefix[64]; int ret; char *nextmsg, *msg; - char *raw; char *temp; char token[1024]; char var[9][1000]; @@ -1783,8 +1804,6 @@ int IRC_ClientFrame(ircclient_t *irc) IRC_CvarUpdate(); // is this the right place for it? - raw = strtok(var[2], " "); - // if (irc_debug.value == 1) { IRC_Printf(irc, DEFAULTCONSOLE,COLOURRED "!!!!! ^11: %s ^22: %s ^33: %s ^44: %s ^55: %s ^66: %s ^77: %s ^88: %s\n",var[1],var[2],var[3],var[4],var[5],var[6],var[7],var[8]); } if (irc_debug.value == 1) { IRC_Printf(irc, DEFAULTCONSOLE,COLOURRED "%s\n",var[1]); } @@ -1881,32 +1900,29 @@ int IRC_ClientFrame(ircclient_t *irc) } else { + etghack = strtok(var[1],"\n"); - etghack = strtok(var[1],"\n"); + if (!irc->connecting || IRC_WindowShown(irc, DEFAULTCONSOLE)) + IRC_Printf(irc, DEFAULTCONSOLE, COLOURGREEN "SERVER NOTICE: <%s> %s\n", prefix, etghack); - IRC_Printf(irc, DEFAULTCONSOLE, COLOURGREEN "SERVER NOTICE: <%s> %s\n", prefix, etghack); +// strcpy(servername,prefix); -// strcpy(servername,prefix); - - while (1) - { - etghack = strtok(NULL, "\n"); - - if (etghack == NULL) + while (1) { - break; - break; + etghack = strtok(NULL, "\n"); + + if (etghack == NULL) + break; + + magic_etghack(etghack); + + if (atoi(subvar[2]) != 0) + numbered_command(atoi(subvar[2]), etghack, irc); + else + IRC_Printf(irc, DEFAULTCONSOLE, COLOURGREEN "SERVER NOTICE: <%s> %s\n", prefix, subvar[4]); + } - - magic_etghack(etghack); - - if (atoi(subvar[2]) != 0) - numbered_command(atoi(subvar[2]), etghack, irc); - else - IRC_Printf(irc, DEFAULTCONSOLE, COLOURGREEN "SERVER NOTICE: <%s> %s\n", prefix, subvar[4]); - } - } } else if (!strncmp(var[2], "PRIVMSG ", 7)) //no autoresponses to notice please, and any autoresponses should be in the form of a notice @@ -2036,7 +2052,8 @@ int IRC_ClientFrame(ircclient_t *irc) } else { - IRC_Printf(irc, channel,COLOURGREEN "%s sets mode %s\n",username,mode); + if (IRC_WindowShown(irc, channel)) + IRC_Printf(irc, channel, COLOURGREEN "%s sets mode %s\n",username,mode); } } @@ -2209,13 +2226,13 @@ int IRC_ClientFrame(ircclient_t *irc) } // would be great to convert the above to work better - else if (atoi(raw) != 0) + else if (atoi(var[2]) != 0) { // char *rawparameter = strtok(var[4], " "); // char *rawmessage = var[5]; // char *wholerawmessage = var[4]; - numbered_command(atoi(raw), msg, irc); + numbered_command(atoi(var[2]), msg, irc); IRC_CvarUpdate(); @@ -2569,7 +2586,7 @@ void IRC_Command(ircclient_t *ircclient, char *dest) if(*msg <= ' ' && *msg) msg++; IRC_AddClientMessage(ircclient, va("PRIVMSG %s :\001ACTION %s\001", dest, msg)); - IRC_Printf(ircclient, ircclient->defaultdest, "***%s %s\n", ircclient->nick, msg); + IRC_Printf(ircclient, ircclient->defaultdest, "***^3%s^7 %s\n", ircclient->nick, msg); } } } @@ -2593,7 +2610,7 @@ void IRC_Command(ircclient_t *ircclient, char *dest) if (!*msg) return; //this is apparently an error. certainly wasteful. IRC_AddClientMessage(ircclient, va("PRIVMSG %s :%s", dest, msg)); - IRC_Printf(ircclient, dest, "%s: %s\n", ircclient->nick, msg); + IRC_Printf(ircclient, dest, "^3%s^7: %s\n", ircclient->nick, msg); } } else diff --git a/plugins/jabber/jabbercl.vcproj b/plugins/jabber/jabbercl.vcproj index 016c65b0..04d9447e 100644 --- a/plugins/jabber/jabbercl.vcproj +++ b/plugins/jabber/jabbercl.vcproj @@ -125,7 +125,7 @@ /> diff --git a/plugins/plugin.h b/plugins/plugin.h index b8255929..428bb7c3 100644 --- a/plugins/plugin.h +++ b/plugins/plugin.h @@ -85,7 +85,7 @@ void BadBuiltin(void); typedef long long qintptr_t; typedef unsigned long long quintptr_t; #else - #ifndef _MSC_VER + #if !defined(_MSC_VER) || _MSC_VER < 1300 #define __w64 #endif typedef long __w64 qintptr_t; diff --git a/quakec/menusys/menu/options_hud.qc b/quakec/menusys/menu/options_hud.qc index 5419b6ab..6e3381ca 100644 --- a/quakec/menusys/menu/options_hud.qc +++ b/quakec/menusys/menu/options_hud.qc @@ -53,9 +53,7 @@ nonstatic void(mitem_desktop desktop) M_Options_Hud = } } search_end(fs); - - if (!i) - fr.add(spawn(mitem_text, item_text:"NO HUDS FOUND", item_scale:16, item_flags:IF_CENTERALIGN), RS_X_MIN_PARENT_MIN|RS_Y_MIN_PARENT_MIN | RS_X_MAX_PARENT_MAX|RS_Y_MAX_OWN_MIN, [0, 0], [0, 16]); + //random art for style #if 1//def CSQC