diff --git a/CMakeLists.txt b/CMakeLists.txt index e59546ef..df85cfc3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -550,7 +550,6 @@ SET(FTE_COMMON_FILES engine/common/pr_bgcmd.c engine/common/q1bsp.c engine/common/q2pmove.c - engine/common/q3common.c engine/common/qvm.c engine/common/sha1.c engine/common/sha2.c @@ -572,7 +571,6 @@ SET(FTE_COMMON_FILES engine/client/client.h engine/client/cl_ignore.h engine/client/cl_master.h - engine/client/clq3defs.h engine/client/input.h engine/client/keys.h engine/client/menu.h @@ -629,11 +627,9 @@ SET(FTE_COMMON_FILES engine/qclib/progtype.h engine/qclib/qcc.h engine/qclib/qcd.h - engine/server/botlib.h engine/server/progdefs.h engine/server/progs.h engine/server/q2game.h - engine/server/q3g_public.h engine/server/server.h #engine/server/svhl_gcapi.h engine/server/sv_sql.h @@ -688,13 +684,11 @@ SET(FTE_SERVER_FILES # engine/server/svhl_world.c engine/server/svq2_ents.c engine/server/svq2_game.c - engine/server/svq3_game.c ) #these files are only in the client SET(FTE_CLIENT_FILES engine/client/cl_cam.c - engine/client/cl_cg.c engine/client/cl_demo.c engine/client/cl_ents.c engine/client/cl_ignore.c @@ -704,11 +698,9 @@ SET(FTE_CLIENT_FILES engine/client/cl_pred.c engine/client/cl_screen.c engine/client/cl_tent.c - engine/client/cl_ui.c # engine/client/clhl_game.c engine/client/clq2_cin.c engine/client/clq2_ents.c - engine/client/clq3_parse.c engine/client/console.c engine/client/fragstats.c engine/client/image.c @@ -767,42 +759,73 @@ SET(FTE_CLIENT_FILES ${FTE_VK_FILES} ) -SET(FTE_LIB_Q3BOT true CACHE BOOL "Compile Q3 Bot library.") -IF(FTE_LIB_Q3BOT) - ADD_LIBRARY(fteq3bot MODULE - engine/botlib/be_aas_bspq3.c - engine/botlib/be_aas_entity.c - engine/botlib/be_aas_move.c - engine/botlib/be_aas_routealt.c - engine/botlib/be_ai_char.c - engine/botlib/be_ai_goal.c - engine/botlib/be_ai_weight.c - engine/botlib/l_crc.c - engine/botlib/l_memory.c - engine/botlib/l_struct.c - engine/botlib/be_aas_cluster.c - engine/botlib/be_aas_file.c - engine/botlib/be_aas_optimize.c - engine/botlib/be_aas_route.c - engine/botlib/be_ai_chat.c - engine/botlib/be_ai_move.c - engine/botlib/be_ea.c - engine/botlib/l_libvar.c - engine/botlib/l_precomp.c - engine/botlib/be_aas_debug.c - engine/botlib/be_aas_main.c - engine/botlib/be_aas_reach.c - engine/botlib/be_aas_sample.c - engine/botlib/be_ai_gen.c - engine/botlib/be_ai_weap.c - engine/botlib/be_interface.c - engine/botlib/l_log.c - engine/botlib/l_script.c - engine/botlib/standalone.c - ) - SET_TARGET_PROPERTIES(fteq3bot PROPERTIES COMPILE_DEFINITIONS "${FTE_LIB_DEFINES};${FTE_DEFINES};${FTE_REVISON};BOTLIB;EXTERNALBOTLIB") - TARGET_LINK_LIBRARIES(fteq3bot ${FTE_LIBS} ) - SET_TARGET_PROPERTIES(fteq3bot PROPERTIES LINK_FLAGS "-Wl,--no-undefined") +SET(FTE_BOTLIB_FILES + engine/botlib/be_aas_bspq3.c + engine/botlib/be_aas_entity.c + engine/botlib/be_aas_move.c + engine/botlib/be_aas_routealt.c + engine/botlib/be_ai_char.c + engine/botlib/be_ai_goal.c + engine/botlib/be_ai_weight.c + engine/botlib/l_crc.c + engine/botlib/l_memory.c + engine/botlib/l_struct.c + engine/botlib/be_aas_cluster.c + engine/botlib/be_aas_file.c + engine/botlib/be_aas_optimize.c + engine/botlib/be_aas_route.c + engine/botlib/be_ai_chat.c + engine/botlib/be_ai_move.c + engine/botlib/be_ea.c + engine/botlib/l_libvar.c + engine/botlib/l_precomp.c + engine/botlib/be_aas_debug.c + engine/botlib/be_aas_main.c + engine/botlib/be_aas_reach.c + engine/botlib/be_aas_sample.c + engine/botlib/be_ai_gen.c + engine/botlib/be_ai_weap.c + engine/botlib/be_interface.c + engine/botlib/l_log.c + engine/botlib/l_script.c + engine/botlib/standalone.c +) +SET(FTE_Q3_FILES + ${FTE_BOTLIB_FILES} + engine/client/cl_cg.c + engine/client/cl_ui.c + engine/client/clq3_parse.c + engine/server/svq3_game.c + engine/common/q3common.c + engine/common/q3common.h + + engine/client/clq3defs.h + engine/server/q3g_public.h +) + +SET(FTE_PLUG_QUAKE3 true CACHE BOOL "Compile Quake3 plugin.") +IF(FTE_PLUG_QUAKE3) + IF (0) + SET(FTE_DEFINES ${FTE_DEFINES};${Q3_DEFINES}) + SET(FTE_LIBS ${FTE_LIBS} quake3) + + #define the modules and make sure they're linked (one generic, one for server-only builds. + ADD_LIBRARY(quake3 STATIC ${FTE_Q3_FILES}) + SET_TARGET_PROPERTIES(quake3 PROPERTIES COMPILE_DEFINITIONS "${FTE_LIB_DEFINES};${FTE_REVISON};BOTLIB;BOTLIB_STATIC;FTEPLUGIN;STATIC_Q3") + TARGET_LINK_LIBRARIES(quake3 m) + + #ADD_LIBRARY(q3sv STATIC EXCLUDE_FROM_ALL ${FTE_Q3_FILES}) + #SET_TARGET_PROPERTIES(q3sv PROPERTIES COMPILE_DEFINITIONS "${FTE_LIB_DEFINES};${FTE_REVISON};BOTLIB;BOTLIB_STATIC;SERVERONLY") + #SET_TARGET_PROPERTIES(q3sv PROPERTIES LINK_FLAGS "-Wl,--no-undefined") + #TARGET_LINK_LIBRARIES(q3sv m) + #SET(FTESV_LIBS ${FTESV_LIBS} q3sv) + ELSE() + #define the modules and make sure they're linked (one generic, one for server-only builds. + ADD_LIBRARY(plug_quake3 MODULE ${FTE_Q3_FILES} plugins/plugin.c) + SET_TARGET_PROPERTIES(plug_quake3 PROPERTIES COMPILE_DEFINITIONS "${FTE_LIB_DEFINES};${FTE_REVISON};BOTLIB;BOTLIB_STATIC;FTEPLUGIN") + TARGET_LINK_LIBRARIES(plug_quake3 m) + EMBED_PLUGIN_META(quake3 "Quake3 Compat" "Provides compatability with Quake3's gamecode.") + ENDIF() ENDIF() FILE(STRINGS "${FTE_BUILD_CONFIG}" BULLET_INTERNAL REGEX "^#define[\t ]+USE_INTERNAL_BULLET") @@ -1537,4 +1560,4 @@ IF(FTE_MENU_SYS) quakec/menusys/menu/options_video.qc quakec/menusys/menu/quit.qc ) -ENDIF() \ No newline at end of file +ENDIF() diff --git a/engine/Makefile b/engine/Makefile index 720e17c6..6a12f3d3 100644 --- a/engine/Makefile +++ b/engine/Makefile @@ -646,7 +646,7 @@ endif SDL_INCLUDES= #-I$(LIBS_DIR)/sdl/include -I/usr/include/SDL -I$(LIBS_DIR)/sdl/include/SDL BASE_INCLUDES=-I$(CLIENT_DIR) -I$(SERVER_DIR) -I$(COMMON_DIR) -I$(GL_DIR) -I$(D3D_DIR) -I$(PROGS_DIR) -I. -BASE_CFLAGS=$(WARNINGFLAGS) $(GNUC_FUNCS) $(BASE_INCLUDES) -I$(LIBS_DIR)/dxsdk9/include -I$(LIBS_DIR)/dxsdk7/include $(SDL_INCLUDES) $(BOTLIB_CFLAGS) $(SVNREVISION) +BASE_CFLAGS=$(WARNINGFLAGS) $(GNUC_FUNCS) $(BASE_INCLUDES) -I$(LIBS_DIR)/dxsdk9/include -I$(LIBS_DIR)/dxsdk7/include $(SDL_INCLUDES) $(SVNREVISION) CLIENT_ONLY_CFLAGS=-DCLIENTONLY SERVER_ONLY_CFLAGS=-DSERVERONLY JOINT_CFLAGS= @@ -737,10 +737,7 @@ CLIENT_OBJS = \ cl_cam.o \ cl_screen.o \ pr_clcmd.o \ - cl_ui.o \ cl_ignore.o \ - cl_cg.o \ - clq3_parse.o \ pr_csqc.o \ console.o \ image.o \ @@ -874,7 +871,6 @@ SERVER_OBJS = \ savegame.o \ svq2_ents.o \ svq2_game.o \ - svq3_game.o \ webgen.o \ ftpserver.o \ httpserver.o @@ -937,7 +933,6 @@ COMMON_OBJS = \ r_d3.o \ gl_q2bsp.o \ glmod_doom.o \ - q3common.o \ world.o \ sv_phys.o \ sv_move.o \ @@ -952,6 +947,11 @@ COMMON_OBJS = \ ifeq (1,$(USE_BOTLIB)) BOTLIB_CFLAGS=-I$(BOTLIB_DIR) -DBOTLIB -DBOTLIB_STATIC BOTLIB_OBJS = \ + clq3_parse.o \ + cl_ui.o \ + cl_cg.o \ + svq3_game.o \ + q3common.o \ be_aas_bspq3.o \ be_aas_cluster.o \ be_aas_debug.o \ @@ -1062,7 +1062,7 @@ endif SDLCONFIG?=sdl-config FTE_FULLTARGET?=sdl$(FTE_TARGET)$(BITS) -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 +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=../$(EXE_NAME)-gl$(FTE_FULLTARGET) GLCL_EXE_NAME=../$(EXE_NAME)cl-gl$(FTE_FULLTARGET) @@ -1083,14 +1083,14 @@ GLB_DIR=gl_$(FTE_FULLTARGET) GLCL_DIR=glcl_$(FTE_FULLTARGET) SV_DIR?=sv_$(FTE_FULLTARGET) -VKCL_OBJS=$(VKQUAKE_OBJS) $(D3DGL_OBJS) gl_bloom.o $(BOTLIB_OBJS) gl_vidsdl.o snd_sdl.o cd_sdl.o sys_sdl.o in_sdl.o +VKCL_OBJS=$(VKQUAKE_OBJS) $(D3DGL_OBJS) gl_bloom.o gl_vidsdl.o snd_sdl.o cd_sdl.o sys_sdl.o in_sdl.o VK_CFLAGS=-DFTE_SDL $(VKCFLAGS) -DMULTITHREAD `$(SDLCONFIG) --cflags` VKB_DIR=vk_$(FTE_FULLTARGET) VKCL_DIR=vk_$(FTE_FULLTARGET) VK_EXE_NAME=../$(EXE_NAME)-vk$(FTE_FULLTARGET) VKCL_EXE_NAME=../$(EXE_NAME)-vkcl$(FTE_FULLTARGET) -SV_OBJS=$(COMMON_OBJS) $(SERVER_OBJS) $(PROGS_OBJS) $(SERVERONLY_OBJS) $(BOTLIB_OBJS) +SV_OBJS=$(COMMON_OBJS) $(SERVER_OBJS) $(PROGS_OBJS) $(SERVERONLY_OBJS) SV_EXE_NAME=../$(EXE_NAME)-sv$(FTE_FULLTARGET) SV_CFLAGS=-DFTE_SDL -DMULTITHREAD `$(SDLCONFIG) --cflags` $(SERVER_ONLY_CFLAGS) @@ -1101,7 +1101,7 @@ MB_DIR=m_$(FTE_FULLTARGET) MCL_DIR=mcl_$(FTE_FULLTARGET) M_EXE_NAME=../$(EXE_NAME)-$(FTE_FULLTARGET) MCL_EXE_NAME=../$(EXE_NAME)-cl$(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 +MCL_OBJS=$(D3DGL_OBJS) $(GLQUAKE_OBJS) $(SOFTWARE_OBJS) gl_vidsdl.o snd_sdl.o cd_sdl.o sys_sdl.o in_sdl.o M_CFLAGS=-DFTE_SDL $(VKCFLAGS) $(GLCFLAGS) -DMULTITHREAD `$(SDLCONFIG) --cflags` QCC_DIR=qcc$(BITS) @@ -1170,7 +1170,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) $(BOTLIB_OBJS) sys_ppapi.o cd_null.o gl_vidppapi.o fs_ppapi.o snd_ppapi.o + GLCL_OBJS=$(GL_OBJS) $(D3DGL_OBJS) $(GLQUAKE_OBJS) sys_ppapi.o cd_null.o gl_vidppapi.o fs_ppapi.o snd_ppapi.o GL_LDFLAGS=$(GLLDFLAGS) M_LDFLAGS=$(GLLDFLAGS) @@ -1204,7 +1204,7 @@ ifeq (win_SDL,$(findstring win,$(FTE_TARGET))$(findstring _SDL,$(FTE_TARGET))) ARCH_CFLAGS=`$(SDLCONFIG) --cflags` #the defaults for sdl come first - 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 snd_directx.o $(LTO_END) resources.o $(LTO_START) + GLCL_OBJS=$(GL_OBJS) $(D3DGL_OBJS) $(GLQUAKE_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=../$(EXE_NAME)-sdl-gl$(BITS)$(EXEPOSTFIX) GLCL_EXE_NAME=../$(EXE_NAME)-sdl-glcl$(BITS)$(EXEPOSTFIX) ifdef windir @@ -1226,7 +1226,7 @@ ifeq (win_SDL,$(findstring win,$(FTE_TARGET))$(findstring _SDL,$(FTE_TARGET))) GLB_DIR=gl_mgw_sdl$(BITS) 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_OBJS=$(COMMON_OBJS) $(SERVER_OBJS) $(PROGS_OBJS) $(WINDOWSSERVERONLY_OBJS) $(LTO_END) resources.o $(LTO_START) SV_EXE_NAME=../$(EXE_NAME)-sdl-sv$(BITS)$(EXEPOSTFIX) SV_CFLAGS=$(SERVER_ONLY_CFLAGS) -DFTE_SDL @@ -1236,13 +1236,13 @@ ifeq (win_SDL,$(findstring win,$(FTE_TARGET))$(findstring _SDL,$(FTE_TARGET))) MB_DIR=m_mgw_sdl$(BITS) M_EXE_NAME=../$(EXE_NAME)-sdl$(BITS)$(EXEPOSTFIX) #with d3d... - #MCL_OBJS=$(D3DGL_OBJS) $(GLQUAKE_OBJS) $(SOFTWARE_OBJS) $(D3DQUAKE_OBJS) $(BOTLIB_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) + #MCL_OBJS=$(D3DGL_OBJS) $(GLQUAKE_OBJS) $(SOFTWARE_OBJS) $(D3DQUAKE_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) $(VKCFLAGS) $(GLCFLAGS) -DFTE_SDL $(CLIENTLIBFLAGS) $(DX7SDK) #without d3d... - 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 snd_directx.o $(LTO_END) resources.o $(LTO_START) + MCL_OBJS=$(D3DGL_OBJS) $(GLQUAKE_OBJS) $(SOFTWARE_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=$(VKCFLAGS) $(GLCFLAGS) -DFTE_SDL $(CLIENTLIBFLAGS) $(DX7SDK) - D3DCL_OBJS=$(D3DQUAKE_OBJS) $(BOTLIB_OBJS) snd_sdl.o cd_sdl.o sys_sdl.o in_sdl.o snd_directx.o $(D3DGL_OBJS) $(LTO_END) resources.o $(LTO_START) + D3DCL_OBJS=$(D3DQUAKE_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=../$(EXE_NAME)-sdl-d3d$(BITS)$(EXEPOSTFIX) D3DCL_EXE_NAME=../$(EXE_NAME)-sdl-d3dcl$(BITS)$(EXEPOSTFIX) D3D_LDFLAGS=$(IMAGELDFLAGS) -lws2_32 -lmingw32 $(SDL_LDFLAGS) -mwindows -ldxguid -lwinmm -lole32 @@ -1251,7 +1251,7 @@ ifeq (win_SDL,$(findstring win,$(FTE_TARGET))$(findstring _SDL,$(FTE_TARGET))) D3DCL_DIR=sdl_d3dcl_mgw$(BITS) - VKCL_OBJS=$(VKQUAKE_OBJS) $(BOTLIB_OBJS) gl_bloom.o gl_vidsdl.o snd_sdl.o cd_sdl.o sys_sdl.o in_sdl.o snd_directx.o $(D3DGL_OBJS) $(LTO_END) resources.o $(LTO_START) + VKCL_OBJS=$(VKQUAKE_OBJS) gl_bloom.o gl_vidsdl.o 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=../$(EXE_NAME)-sdl-vk$(BITS)$(EXEPOSTFIX) VKCL_EXE_NAME=../$(EXE_NAME)-sdl-vkcl$(BITS)$(EXEPOSTFIX) VK_CFLAGS=$(VKCFLAGS) -DFTE_SDL -DNO_XFLIP $(CLIENTLIBFLAGS) $(DX7SDK) @@ -1358,7 +1358,7 @@ ifeq ($(findstring msvc,$(FTE_TARGET)),msvc) SV_CFLAGS=$(SERVER_ONLY_CFLAGS) $(W32_CFLAGS) -DMULTITHREAD -DMSVCLIBPATH=libs/ SV_EXE_NAME=../$(EXE_NAME)-sv$(BITS)$(EXEPOSTFIX) SV_DIR=sv_vc$(BITS) - SV_OBJS=$(COMMON_OBJS) $(SERVER_OBJS) $(BOTLIB_OBJS) $(PROGS_OBJS) $(WINDOWSSERVERONLY_OBJS) fs_win32.o resources.o + SV_OBJS=$(COMMON_OBJS) $(SERVER_OBJS) $(PROGS_OBJS) $(WINDOWSSERVERONLY_OBJS) fs_win32.o resources.o SV_LDFLAGS=ole32.lib /subsystem:console GL_EXE_NAME=../$(EXE_NAME)-gl$(BITS)$(EXEPOSTFIX) @@ -1367,13 +1367,13 @@ ifeq ($(findstring msvc,$(FTE_TARGET)),msvc) GLCL_DIR=glcl_vc$(BITS) GL_LDFLAGS=$(GLLDFLAGS) $(JPEGLIB) libs/libpng$(BITS).lib uuid.lib gdi32.lib ole32.lib /subsystem:windows GL_CFLAGS=$(GLCFLAGS) $(W32_CFLAGS) -DMULTITHREAD -DMSVCLIBPATH=libs/ - GLCL_OBJS=$(D3DGL_OBJS) $(GLQUAKE_OBJS) $(BOTLIB_OBJS) gl_vidnt.o $(WINDOWS_OBJS) + GLCL_OBJS=$(D3DGL_OBJS) $(GLQUAKE_OBJS) gl_vidnt.o $(WINDOWS_OBJS) GL_OBJS= MINGL_DIR=mingl_vc$(BITS) MINGL_EXE_NAME=../$(EXE_NAME)-mingl$(BITS)$(EXEPOSTFIX) - VKCL_OBJS=$(VKQUAKE_OBJS) $(D3DGL_OBJS) $(BOTLIB_OBJS) gl_bloom.o gl_vidnt.o $(WINDOWS_OBJS) + VKCL_OBJS=$(VKQUAKE_OBJS) $(D3DGL_OBJS) gl_bloom.o gl_vidnt.o $(WINDOWS_OBJS) VK_EXE_NAME=../$(EXE_NAME)-vk$(BITS)$(EXEPOSTFIX) VKCL_EXE_NAME=../$(EXE_NAME)-vkcl$(BITS)$(EXEPOSTFIX) VK_CFLAGS=$(VKCFLAGS) $(CLIENTLIBFLAGS) $(DX7SDK) -DMULTITHREAD -DMSVCLIBPATH=libs/ @@ -1381,7 +1381,7 @@ ifeq ($(findstring msvc,$(FTE_TARGET)),msvc) VKB_DIR=vk_vc$(BITS) VKCL_DIR=vkcl_vc$(BITS) - D3DCL_OBJS=$(D3DQUAKE_OBJS) $(D3DGL_OBJS) $(BOTLIB_OBJS) $(WINDOWS_OBJS) + D3DCL_OBJS=$(D3DQUAKE_OBJS) $(D3DGL_OBJS) $(WINDOWS_OBJS) D3D_EXE_NAME=../$(EXE_NAME)-d3d$(BITS)$(EXEPOSTFIX) D3DCL_EXE_NAME=../$(EXE_NAME)-d3dcl$(BITS)$(EXEPOSTFIX) D3D_LDFLAGS=$(JPEGLIB) libs/libpng$(BITS).lib uuid.lib gdi32.lib ole32.lib /subsystem:windows @@ -1390,7 +1390,7 @@ ifeq ($(findstring msvc,$(FTE_TARGET)),msvc) D3DCL_DIR=d3dcl_vc$(BITS) #merged client stuff - MCL_OBJS=$(D3DGL_OBJS) $(GLQUAKE_OBJS) $(SOFTWARE_OBJS) $(D3DQUAKE_OBJS) $(BOTLIB_OBJS) gl_vidnt.o gl_videgl.o $(WINDOWS_OBJS) + MCL_OBJS=$(D3DGL_OBJS) $(GLQUAKE_OBJS) $(SOFTWARE_OBJS) $(D3DQUAKE_OBJS) gl_vidnt.o gl_videgl.o $(WINDOWS_OBJS) M_EXE_NAME=../$(EXE_NAME)$(BITS)$(EXEPOSTFIX) MCL_EXE_NAME=../$(EXE_NAME)cl$(BITS)$(EXEPOSTFIX) M_CFLAGS=$(GLCFLAGS) $(W32_CFLAGS) $(D3DCFLAGS) $(DX7SDK) $(VKCFLAGS) -DMULTITHREAD $(CLIENTLIBFLAGS) @@ -1436,11 +1436,11 @@ ifeq (win,$(findstring win,$(FTE_TARGET))$(findstring _SDL,$(FTE_TARGET))) SV_EXE_NAME=../$(EXE_NAME)sv$(BITS)$(EXEPOSTFIX) SV_LDFLAGS=-lws2_32 -lwinmm -lole32 SV_DIR=sv_mingw$(BITS) - SV_OBJS=$(COMMON_OBJS) $(SERVER_OBJS) $(PROGS_OBJS) $(WINDOWSSERVERONLY_OBJS) $(BOTLIB_OBJS) fs_win32.o $(LTO_END) resources.o $(LTO_START) + SV_OBJS=$(COMMON_OBJS) $(SERVER_OBJS) $(PROGS_OBJS) $(WINDOWSSERVERONLY_OBJS) fs_win32.o $(LTO_END) resources.o $(LTO_START) SV_CFLAGS=$(SERVER_ONLY_CFLAGS) $(W32_CFLAGS) - GLCL_OBJS=$(GL_OBJS) $(D3DGL_OBJS) $(GLQUAKE_OBJS) $(BOTLIB_OBJS) gl_vidnt.o $(WINDOWS_OBJS) + GLCL_OBJS=$(GL_OBJS) $(D3DGL_OBJS) $(GLQUAKE_OBJS) gl_vidnt.o $(WINDOWS_OBJS) GL_EXE_NAME=../fteglqw$(BITS)$(EXEPOSTFIX) GLCL_EXE_NAME=../fteglqwcl$(BITS)$(EXEPOSTFIX) GL_LDFLAGS=$(GLLDFLAGS) $(IMAGELDFLAGS) -ldxguid -lws2_32 -lwinmm -lgdi32 -lole32 -Wl,--subsystem,windows @@ -1454,7 +1454,7 @@ ifeq (win,$(findstring win,$(FTE_TARGET))$(findstring _SDL,$(FTE_TARGET))) NPFTE_CFLAGS=$(NPFTECFLAGS) $(W32_CFLAGS) -DMULTITHREAD NPFTEB_DIR=npfte_mgw$(BITS) - MCL_OBJS=$(D3DGL_OBJS) $(GLQUAKE_OBJS) $(SOFTWARE_OBJS) $(D3DQUAKE_OBJS) $(BOTLIB_OBJS) gl_vidnt.o gl_videgl.o $(WINDOWS_OBJS) + MCL_OBJS=$(D3DGL_OBJS) $(GLQUAKE_OBJS) $(SOFTWARE_OBJS) $(D3DQUAKE_OBJS) gl_vidnt.o gl_videgl.o $(WINDOWS_OBJS) M_EXE_NAME=../$(EXE_NAME)$(BITS)$(EXEPOSTFIX) MCL_EXE_NAME=../$(EXE_NAME)cl$(BITS)$(EXEPOSTFIX) M_LDFLAGS=$(GLLDFLAGS) $(IMAGELDFLAGS) -ldxguid -lws2_32 -lwinmm -lgdi32 -lole32 -Wl,--subsystem,windows @@ -1462,7 +1462,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) $(BOTLIB_OBJS) $(WINDOWS_OBJS) + D3DCL_OBJS=$(D3DQUAKE_OBJS) $(D3DGL_OBJS) $(WINDOWS_OBJS) D3D_EXE_NAME=../fted3dqw$(BITS)$(EXEPOSTFIX) D3DCL_EXE_NAME=../fted3dclqw$(BITS)$(EXEPOSTFIX) D3D_LDFLAGS=$(IMAGELDFLAGS) -ldxguid -lws2_32 -lwinmm -lgdi32 -lole32 -Wl,--subsystem,windows @@ -1470,7 +1470,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) $(BOTLIB_OBJS) $(WINDOWS_OBJS) gl_vidnt.o + VKCL_OBJS=$(GLQUAKE_OBJS) $(D3DGL_OBJS) $(WINDOWS_OBJS) gl_vidnt.o VK_EXE_NAME=../ftevkqw$(BITS)$(EXEPOSTFIX) VKCL_EXE_NAME=../ftevkclqw$(BITS)$(EXEPOSTFIX) VK_LDFLAGS=$(IMAGELDFLAGS) -ldxguid -lws2_32 -lwinmm -lgdi32 -lole32 -Wl,--subsystem,windows @@ -1508,7 +1508,7 @@ ifeq ($(FTE_TARGET),bsd) SV_LDFLAGS=-lpthread SV_CFLAGS=$(SERVER_ONLY_CFLAGS) -DMULTITHREAD - 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 + GLCL_OBJS=$(GL_OBJS) $(D3DGL_OBJS) $(GLQUAKE_OBJS) gl_vidlinuxglx.o snd_linux.o cd_null.o sys_linux.o sys_linux_threads.o GL_EXE_NAME=../$(EXE_NAME)-gl GLCL_EXE_NAME=../$(EXE_NAME)-glcl GL_LDFLAGS= -L/usr/local/lib $(GLLDFLAGS) $(XLDFLAGS) -lpthread @@ -1516,7 +1516,7 @@ ifeq ($(FTE_TARGET),bsd) GLB_DIR=gl_bsd GLCL_DIR=glcl_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 + MCL_OBJS=$(D3DGL_OBJS) $(GLQUAKE_OBJS) $(SOFTWARE_OBJS) gl_vidlinuxglx.o snd_linux.o cd_null.o sys_linux.o sys_linux_threads.o M_EXE_NAME=../$(EXE_NAME) MCL_EXE_NAME=../$(EXE_NAME)-cl M_LDFLAGS= -L/usr/local/lib -L/usr/X11R6/lib $(GLLDFLAGS) $(XLDFLAGS) -lpthread @@ -1577,7 +1577,7 @@ ifneq (,$(findstring linux,$(FTE_TARGET))) NPFTE_CFLAGS=$(NPFTECFLAGS) $(W32_CFLAGS) -DMULTITHREAD -fPIC -DDYNAMIC_LIBPNG -DDYNAMIC_LIBJPEG NPFTEB_DIR=npfte_linux$(BITS) - GLCL_OBJS=$(GL_OBJS) $(D3DGL_OBJS) $(GLQUAKE_OBJS) $(BOTLIB_OBJS) gl_vidlinuxglx.o gl_vidwayland.o gl_videgl.o snd_pulse.o snd_alsa.o snd_linux.o snd_sdl.o cd_linux.o sys_linux.o sys_linux_threads.o + GLCL_OBJS=$(GL_OBJS) $(D3DGL_OBJS) $(GLQUAKE_OBJS) gl_vidlinuxglx.o gl_vidwayland.o gl_videgl.o snd_pulse.o snd_alsa.o snd_linux.o snd_sdl.o cd_linux.o sys_linux.o sys_linux_threads.o GL_EXE_NAME=../$(EXE_NAME)-gl$(BITS) GLCL_EXE_NAME=../$(EXE_NAME)-glcl$(BITS) GL_LDFLAGS=$(GLLDFLAGS) $(XLDFLAGS) @@ -1585,7 +1585,7 @@ ifneq (,$(findstring linux,$(FTE_TARGET))) GLB_DIR=gl_linux$(BITS) GLCL_DIR=glcl_linux$(BITS) - VKCL_OBJS=$(GL_OBJS) $(D3DGL_OBJS) $(GLQUAKE_OBJS) $(BOTLIB_OBJS) gl_vidlinuxglx.o gl_vidwayland.o gl_videgl.o snd_pulse.o snd_alsa.o snd_linux.o snd_sdl.o cd_linux.o sys_linux.o sys_linux_threads.o + VKCL_OBJS=$(GL_OBJS) $(D3DGL_OBJS) $(GLQUAKE_OBJS) gl_vidlinuxglx.o gl_vidwayland.o gl_videgl.o snd_pulse.o snd_alsa.o snd_linux.o snd_sdl.o cd_linux.o sys_linux.o sys_linux_threads.o VK_EXE_NAME=../$(EXE_NAME)-vk$(BITS) VKCL_EXE_NAME=../$(EXE_NAME)-vkcl$(BITS) VK_LDFLAGS=$(GLLDFLAGS) $(XLDFLAGS) @@ -1593,7 +1593,7 @@ ifneq (,$(findstring linux,$(FTE_TARGET))) VKB_DIR=vk_linux$(BITS) VKCL_DIR=vkcl_linux$(BITS) - MCL_OBJS=$(D3DGL_OBJS) $(GLQUAKE_OBJS) $(SOFTWARE_OBJS) $(BOTLIB_OBJS) gl_vidlinuxglx.o gl_vidwayland.o gl_videgl.o snd_linux.o snd_sdl.o snd_pulse.o snd_alsa.o cd_linux.o sys_linux.o sys_linux_threads.o + MCL_OBJS=$(D3DGL_OBJS) $(GLQUAKE_OBJS) $(SOFTWARE_OBJS) gl_vidlinuxglx.o gl_vidwayland.o gl_videgl.o snd_linux.o snd_sdl.o snd_pulse.o snd_alsa.o cd_linux.o sys_linux.o sys_linux_threads.o M_EXE_NAME=../$(EXE_NAME)$(BITS) MCL_EXE_NAME=../$(EXE_NAME)-cl$(BITS) M_LDFLAGS=$(GL_LDFLAGS) @@ -1648,7 +1648,7 @@ ifneq ($(shell echo $(FTE_TARGET)|grep macosx),) endif GL_LDFLAGS=-framework AGL -framework OpenGL -framework Cocoa -framework AudioUnit - 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 + 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 GL_EXE_NAME=../$(EXE_NAME)-macosx-gl$(EXTENSION)$(BITS) GLCL_EXE_NAME=../$(EXE_NAME)cl-macosx-gl$(EXTENSION)$(BITS) @@ -1657,7 +1657,7 @@ ifneq ($(shell echo $(FTE_TARGET)|grep macosx),) MINGL_EXE_NAME=../$(EXE_NAME)-macosx-mingl$(EXTENSION)$(BITS) MINGL_DIR=mingl_macosx$(EXTENSION)$(BITS) - SV_OBJS=$(COMMON_OBJS) $(SERVER_OBJS) $(PROGS_OBJS) $(BOTLIB_OBJS) $(SERVERONLY_OBJS) + SV_OBJS=$(COMMON_OBJS) $(SERVER_OBJS) $(PROGS_OBJS) $(SERVERONLY_OBJS) SV_EXE_NAME=../$(EXE_NAME)-macosx-sv$(EXTENSION)$(BITS) SV_CFLAGS=$(SERVER_ONLY_CFLAGS) SV_LDFLAGS=-lz @@ -1674,7 +1674,7 @@ ifeq ($(FTE_TARGET),morphos) SV_DIR=sv_morphos SV_LDFLAGS=-ldl -lz - 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 + GLCL_OBJS=$(GL_OBJS) $(D3DGL_OBJS) $(GLQUAKE_OBJS) gl_vidmorphos.o in_morphos.o snd_morphos.o cd_null.o sys_morphos.o GL_EXE_NAME=../$(EXE_NAME)-morphos-gl GLCL_EXE_NAME=../$(EXE_NAME)-morphos-glcl GL_LDFLAGS=$(GLLDFLAGS) -ldl $(IMAGELDFLAGS) -lz @@ -1682,7 +1682,7 @@ ifeq ($(FTE_TARGET),morphos) 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 + MCL_OBJS=$(D3DGL_OBJS) $(GLQUAKE_OBJS) $(SOFTWARE_OBJS) gl_vidmorphos.o vid_morphos.o in_morphos.o snd_morphos.o cd_null.o sys_morphos.o M_EXE_NAME=../$(EXE_NAME)-morphos MCL_EXE_NAME=../$(EXE_NAME)-morphos-cl M_LDFLAGS=$(GLLDFLAGS) @@ -1693,7 +1693,7 @@ ifeq ($(FTE_TARGET),morphos) MINGL_EXE_NAME=../$(EXE_NAME)-morphos-mingl MINGL_DIR=mingl_morphos - SV_OBJS=$(COMMON_OBJS) $(SERVER_OBJS) $(PROGS_OBJS) $(SERVERONLY_OBJS) $(BOTLIB_OBJS) + SV_OBJS=$(COMMON_OBJS) $(SERVER_OBJS) $(PROGS_OBJS) $(SERVERONLY_OBJS) SV_EXE_NAME=../$(EXE_NAME)-morphos-sv$(BITS) SV_CFLAGS=$(SERVER_ONLY_CFLAGS) endif @@ -1719,7 +1719,7 @@ ifeq ($(FTE_TARGET),dos) SV_EXE_NAME=../$(EXE_NAME)sv$(BITS)$(EXEPOSTFIX) VK_EXE_NAME=../$(EXE_NAME)-vk$(BITS)$(EXEPOSTFIX) - VKCL_OBJS=$(GL_OBJS) $(D3DGL_OBJS) $(GLQUAKE_OBJS) $(BOTLIB_OBJS) cd_null.o sys_dos.o snd_sblaster.o + VKCL_OBJS=$(GL_OBJS) $(D3DGL_OBJS) $(GLQUAKE_OBJS) cd_null.o sys_dos.o snd_sblaster.o endif ifeq ($(FTE_TARGET),cyg) @@ -1728,7 +1728,7 @@ ifeq ($(FTE_TARGET),cyg) SV_CFLAGS=$(SERVER_ONLY_CFLAGS) EXEPOSTFIX=.exe - 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 + GLCL_OBJS=$(GL_OBJS) $(D3DGL_OBJS) $(GLQUAKE_OBJS) gl_vidlinuxglx.o snd_linux.o cd_null.o sys_linux.o sys_linux_threads.o GL_EXE_NAME=../$(EXE_NAME)-cyg-gl$(EXEPOSTFIX) GLCL_EXE_NAME=../$(EXE_NAME)-cyg-glcl$(EXEPOSTFIX) GL_LDFLAGS=$(GLLDFLAGS) $(XLDFLAGS) -lz -lltdl @@ -1736,7 +1736,7 @@ ifeq ($(FTE_TARGET),cyg) GLB_DIR=gl_cygwin GLCL_DIR=glcl_cygwin - 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 + MCL_OBJS=$(D3DGL_OBJS) $(GLQUAKE_OBJS) $(SOFTWARE_OBJS) gl_vidlinuxglx.o snd_linux.o cd_null.o sys_linux.o sys_linux_threads.o M_EXE_NAME=../$(EXE_NAME)-cyg$(EXEPOSTFIX) MCL_EXE_NAME=../$(EXE_NAME)-cyg-cl$(EXEPOSTFIX) M_LDFLAGS=$(GLLDFLAGS) $(XLDFLAGS) -lz -lltdl @@ -1761,18 +1761,18 @@ ifeq ($(FTE_TARGET),droid) SV_CFLAGS=$(SERVER_ONLY_CFLAGS) $(W32_CFLAGS) SV_LDFLAGS= SV_DIR=sv_droid-$(DROID_ARCH) - SV_OBJS=$(COMMON_OBJS) $(SERVER_OBJS) $(PROGS_OBJS) $(BOTLIB_OBJS) $(SYS_DROID_O) + SV_OBJS=$(COMMON_OBJS) $(SERVER_OBJS) $(PROGS_OBJS) $(SYS_DROID_O) SV_EXE_NAME=libftedroid.so GL_CFLAGS=$(GLCFLAGS) GL_LDFLAGS=$(GLLDFLAGS) -landroid - GLCL_OBJS=$(GL_OBJS) $(D3DGL_OBJS) $(GLQUAKE_OBJS) $(BOTLIB_OBJS) $(GL_DROID_O) cd_null.o snd_droid.o + GLCL_OBJS=$(GL_OBJS) $(D3DGL_OBJS) $(GLQUAKE_OBJS) $(GL_DROID_O) cd_null.o snd_droid.o GLB_DIR=gl_droid-$(DROID_ARCH) GL_EXE_NAME=libftedroid.so M_CFLAGS=$(VKCFLAGS) $(GLCFLAGS) -DMULTITHREAD M_LDFLAGS=$(GLLDFLAGS) -landroid -lEGL -lOpenSLES - MCL_OBJS=$(GL_OBJS) $(D3DGL_OBJS) $(GLQUAKE_OBJS) $(BOTLIB_OBJS) $(GL_DROID_O) cd_null.o snd_opensl.o + MCL_OBJS=$(GL_OBJS) $(D3DGL_OBJS) $(GLQUAKE_OBJS) $(GL_DROID_O) cd_null.o snd_opensl.o #snd_droid.o MB_DIR=m_droid-$(DROID_ARCH) M_EXE_NAME=libftedroid.so @@ -1835,7 +1835,6 @@ ifeq ($(FTE_TARGET),web) CLIENTLDDEPS= SERVERLDDEPS= - #BOTLIB_CFLAGS= #generate deps properly #DEPCC= #DEPCXX= diff --git a/engine/botlib/standalone.c b/engine/botlib/standalone.c index 68854cfd..aa689e56 100644 --- a/engine/botlib/standalone.c +++ b/engine/botlib/standalone.c @@ -163,6 +163,11 @@ int Q_strncasecmp (const char *s1, const char *s2, int n) return -1; } +int Q_strcasecmp (const char *s1, const char *s2) +{ + return Q_strncasecmp (s1, s2, 0x7fffffff); +} + int QDECL Q_stricmp (const char *s1, const char *s2) { return Q_strncasecmp (s1, s2, 0x7fffffff); @@ -184,6 +189,7 @@ void QDECL Q_strncpyz(char *d, const char *s, int n) *d='\0'; } +/* char *QDECL va(char *format, ...) { #define VA_BUFFER_SIZE 1024 @@ -196,3 +202,4 @@ char *QDECL va(char *format, ...) return string; } +*/ \ No newline at end of file diff --git a/engine/client/cl_cg.c b/engine/client/cl_cg.c index f0025c23..002e44ca 100644 --- a/engine/client/cl_cg.c +++ b/engine/client/cl_cg.c @@ -1,6 +1,6 @@ -#include "quakedef.h" +#include "q3common.h" //#include "cg_public.h" -#ifdef VM_CG +#if defined(VM_CG) && defined(HAVE_CLIENT) #include "shader.h" @@ -11,23 +11,15 @@ typedef float m3by3_t[3][3]; #endif #include "clq3defs.h" +#include "com_mesh.h" //cl_ui.c void CG_Command_f(void); #define CGAME_IMPORT_API_VERSION 4 -#define CGTAGNUM 5423 - -extern model_t *mod_known; -extern int mod_numknown; -#define VM_FROMMHANDLE(a) ((a&&((unsigned int)a)<=mod_numknown)?mod_known+a-1:NULL) -#define VM_TOMHANDLE(a) (a?a-mod_known+1:0) - -#define VM_FROMSHANDLE(a) ((a&&(unsigned int)a<=r_numshaders)?r_shaders[a-1]:NULL) -#define VM_TOSHANDLE(a) (a?a->id+1:0) - static model_t *box_model; +cvar_t *cl_shownet_ptr, *cl_c2sdupe_ptr, *cl_nodelta_ptr; typedef enum { CG_PRINT, @@ -136,10 +128,11 @@ typedef enum { CG_TESTPRINTFLOAT, CG_ACOS, - CG_FTE_FINDPARTICLEEFFECT = 200, + + /*CG_FTE_FINDPARTICLEEFFECT = 200, CG_FTE_SPAWNPARTICLEEFFECT, CG_FTE_SPAWNPARTICLETRAIL, - CG_FTE_FREEPARTICLESTATE + CG_FTE_FREEPARTICLESTATE*/ } cgameImport_t; /* @@ -240,16 +233,19 @@ unsigned int Contents_From_Q3(unsigned int Q3) return ret; } -#define MAX_GAMESTATE_CHARS 16000 -#define MAX_CONFIGSTRINGS 1024 typedef struct { - int stringOffsets[MAX_CONFIGSTRINGS]; - char stringData[MAX_GAMESTATE_CHARS]; + int stringOffsets[MAX_Q3_CONFIGSTRINGS]; + char stringData[MAX_Q3_GAMESTATE_CHARS]; int dataCount; } gameState_t; -gameState_t cggamestate; +static gameState_t cggamestate; -void CG_InsertIntoGameState(int num, char *str) +void CG_ClearGameState(void) +{ + memset(&cggamestate, 0, sizeof(cggamestate)); +} + +void CG_InsertIntoGameState(int num, const char *str) { if (num < 5) { @@ -259,24 +255,24 @@ void CG_InsertIntoGameState(int num, char *str) if (num == CFGSTR_SYSINFO) { //check some things. - cl.servercount = atoi(Info_ValueForKey(str, "sv_serverid")); + ccs.servercount = atoi(worldfuncs->GetInfoKey(str, "sv_serverid")); } - if (cggamestate.dataCount + strlen(str)+1 > MAX_GAMESTATE_CHARS) + if (cggamestate.dataCount + strlen(str)+1 > countof(cggamestate.stringData)) { - char oldstringData[MAX_GAMESTATE_CHARS]; + char oldstringData[countof(cggamestate.stringData)]; int i; char *oldstr; //copy the old strings to a temporary buffer - memcpy(oldstringData, cggamestate.stringData, MAX_GAMESTATE_CHARS); + memcpy(oldstringData, cggamestate.stringData, countof(cggamestate.stringData)); cggamestate.dataCount = 0; - for (i = 0; i < MAX_CONFIGSTRINGS; i++) + for (i = 0; i < countof(cggamestate.stringOffsets); i++) { oldstr = oldstringData+cggamestate.stringOffsets[i]; if (*oldstr) { - if (cggamestate.dataCount + strlen(oldstr)+1 > MAX_GAMESTATE_CHARS) - Host_EndGame("Too much configstring text\n"); + if (cggamestate.dataCount + strlen(oldstr)+1 > countof(cggamestate.stringData)) + plugfuncs->EndGame("Too much configstring text\n"); cggamestate.dataCount+=1; strcpy(cggamestate.stringData+cggamestate.dataCount, oldstr); @@ -300,9 +296,9 @@ void CG_InsertIntoGameState(int num, char *str) cggamestate.dataCount += strlen(str); } -char *CG_GetConfigString(int num) +const char *CG_GetConfigString(int num) { - if ((unsigned)num >= MAX_CONFIGSTRINGS) + if ((unsigned)num >= countof(cggamestate.stringOffsets)) return ""; return cggamestate.stringData + cggamestate.stringOffsets[num]; } @@ -316,7 +312,7 @@ int CG_GetGameState(gameState_t *gs) static int CGQ3_GetCurrentCmdNumber(void) { //Q3 sequences are 1-based, so 1<=idx<=latestsequence are valid //FTE's sequences are 0-based, so 0<=idxGetMoveCount()-1; } static qboolean CGQ3_GetUserCmd(int cmdNumber, q3usercmd_t *ucmd) { @@ -326,14 +322,14 @@ static qboolean CGQ3_GetUserCmd(int cmdNumber, q3usercmd_t *ucmd) usercmd_t *cmd; //q3 does not do partials. - if (cmdNumber >= cl.movesequence) - Host_EndGame("CLQ3_GetUserCmd: %i >= %i", cmdNumber, cl.movesequence); + if (cmdNumber < 0) + return false; //grr, stoopid q3. + if (cmdNumber >= inputfuncs->GetMoveCount()) + plugfuncs->EndGame("CLQ3_GetUserCmd: %i >= %i", cmdNumber, inputfuncs->GetMoveCount()); - if (cl.movesequence - (cmdNumber+1) > Q3CMD_BACKUP) + cmd = inputfuncs->GetMoveEntry(cmdNumber); + if (!cmd) return false; - - //note: frames and commands are desynced in q3. - cmd = &cl.outframes[(cmdNumber) & Q3CMD_MASK].cmd[0]; ucmd->angles[0] = cmd->angles[0]; ucmd->angles[1] = cmd->angles[1]; ucmd->angles[2] = cmd->angles[2]; @@ -344,16 +340,19 @@ static qboolean CGQ3_GetUserCmd(int cmdNumber, q3usercmd_t *ucmd) ucmd->buttons = cmd->buttons; ucmd->weapon = cmd->weapon; + return true; } -static vm_t *cgvm; +vm_t *cgvm; +static const char *mapentspointer; extern int keycatcher; qboolean CG_GetServerCommand(int cmdnum) { static char bigconfigstring[65536]; + char *arg0; //quote from cgame code: // get the gamestate from the client system, which will have the @@ -362,31 +361,32 @@ qboolean CG_GetServerCommand(int cmdnum) char *str = ccs.serverCommands[cmdnum & Q3TEXTCMD_MASK]; Con_DPrintf("Dispaching %s\n", str); - Cmd_TokenizeString(str, false, false); + cmdfuncs->TokenizeString(str); + arg0 = cmdfuncs->Argv(0, NULL, 0); - if (!strcmp(Cmd_Argv(0), "bcs0")) + if (!strcmp(arg0, "bcs0")) { //start - Q_snprintfz(bigconfigstring, sizeof(bigconfigstring), "cs %s \"%s", Cmd_Argv(1), Cmd_Argv(2)); + Q_snprintfz(bigconfigstring, sizeof(bigconfigstring), "cs %s \"%s", cmdfuncs->Argv(1, NULL, 0), cmdfuncs->Argv(2, NULL, 0)); return false; } - if (!strcmp(Cmd_Argv(0), "bcs1")) + if (!strcmp(arg0, "bcs1")) { //continuation - Q_strncatz(bigconfigstring, Cmd_Argv(2), sizeof(bigconfigstring)); + Q_strncatz(bigconfigstring, cmdfuncs->Argv(2, NULL, 0), sizeof(bigconfigstring)); return false; } - if (!strcmp(Cmd_Argv(0), "bcs2")) + if (!strcmp(arg0, "bcs2")) { //end - Q_strncatz(bigconfigstring, Cmd_Argv(2), sizeof(bigconfigstring)); + Q_strncatz(bigconfigstring, cmdfuncs->Argv(2, NULL, 0), sizeof(bigconfigstring)); Q_strncatz(bigconfigstring, "\"", sizeof(bigconfigstring)); - Cmd_TokenizeString(bigconfigstring, false, false); + cmdfuncs->TokenizeString(bigconfigstring); } - if (!strcmp(Cmd_Argv(0), "cs")) - CG_InsertIntoGameState(atoi(Cmd_Argv(1)), Cmd_Argv(2)); - else if (!strcmp(Cmd_Argv(0), "map_restart")) + if (!strcmp(arg0, "cs")) + CG_InsertIntoGameState(atoi(cmdfuncs->Argv(1, NULL, 0)), cmdfuncs->Argv(2, NULL, 0)); + else if (!strcmp(arg0, "map_restart")) Con_ClearNotify(); - else if (!strcmp(Cmd_Argv(0), "disconnect")) - Host_EndGame("Server disconnected - %s", (Cmd_Argc()>1)?Cmd_Argv(1):"No reason given"); + else if (!strcmp(arg0, "disconnect")) + plugfuncs->EndGame("Server disconnected - %s", (cmdfuncs->Argc()>1)?cmdfuncs->Argv(1, NULL, 0):"No reason given"); return true; } @@ -478,7 +478,7 @@ int CG_MarkFragments( int numPoints, const vec3_t *points, const vec3_t projecti ctx.frags = fragmentBuffer; ctx.numfrags = 0; ctx.maxfrags = maxFragments; - Mod_ClipDecal(cl.worldmodel, center, axis[0], axis[1], axis[2], radius, 0,0, CG_MarkFragments_Callback, &ctx); + scenefuncs->ClipDecal(ccs.worldmodel, center, axis[0], axis[1], axis[2], radius, 0,0, CG_MarkFragments_Callback, &ctx); return ctx.numfrags; } @@ -521,7 +521,7 @@ static void CG_StopLoopingSounds(unsigned int entnum) loopers[i] = loopers[numloopers-1]; numloopers--; } -static void CG_StartLoopingSounds(unsigned int entnum, float *origin, float *velocity, const char *soundname, qboolean persistent) +static void CG_StartLoopingSounds(unsigned int entnum, float *origin, float *velocity, int range, const char *soundname, float volume, qboolean persistent) { size_t i; for (i = 0; i < numloopers; i++) @@ -539,8 +539,10 @@ static void CG_StartLoopingSounds(unsigned int entnum, float *origin, float *vel loopers[i].entnum = entnum; VectorCopy(origin, loopers[i].origin); //VectorCopy(velocity, loopers[i].velocity); - loopers[i].sfx = S_PrecacheSound(soundname); + loopers[i].sfx = audiofuncs->PrecacheSound(soundname); loopers[i].ispersistent = persistent; +// loopers[i].range = range; +// loopers[i].volume = volume; } static void CG_MoveLoopingSound(unsigned int entnum, float *origin) { @@ -575,9 +577,11 @@ static void CG_ClearLoopingSounds(qboolean clearall) } } -int VM_LerpTag(void *out, model_t *model, int f1, int f2, float l2, char *tagname); -#define VALIDATEPOINTER(o,l) if ((int)o + l >= mask || VM_POINTER(o) < offset) Host_EndGame("Call to cgame trap %u passes invalid pointer\n", (unsigned int)fn); //out of bounds. + +int VM_LerpTag(float *out, model_t *model, int f1, int f2, float l2, char *tagname); + +#define VALIDATEPOINTER(o,l) if ((int)o + l >= mask || VM_POINTER(o) < offset) plugfuncs->EndGame("Call to cgame trap %u passes invalid pointer\n", (unsigned int)fn); //out of bounds. static qintptr_t CG_SystemCalls(void *offset, quintptr_t mask, qintptr_t fn, const qintptr_t *arg) { @@ -593,25 +597,28 @@ static qintptr_t CG_SystemCalls(void *offset, quintptr_t mask, qintptr_t fn, con //make sure that any called functions are also range checked. //like reading from files copies names into alternate buffers, allowing stack screwups. //OutputDebugString(va("cl_cg: %i\n", fn)); - switch(fn) + switch((cgameImport_t)fn) { case CG_PRINT: - Con_Printf("%s", (char*)VM_POINTER(arg[0])); + { + const char *text = VM_POINTER(arg[0]); + Con_Printf("%s", text); + } break; case CG_ERROR: - Host_EndGame("cgame: %s", (char*)VM_POINTER(arg[0])); + plugfuncs->EndGame("cgame: %s", (char*)VM_POINTER(arg[0])); break; case CG_ARGC: - VM_LONG(ret) = Cmd_Argc(); + VM_LONG(ret) = cmdfuncs->Argc(); break; case CG_ARGV: VALIDATEPOINTER(arg[1], arg[2]); - Q_strncpyz(VM_POINTER(arg[1]), Cmd_Argv(VM_LONG(arg[0])), VM_LONG(arg[2])); + cmdfuncs->Argv(VM_LONG(arg[0]), VM_POINTER(arg[1]), VM_LONG(arg[2])); break; case CG_ARGS: VALIDATEPOINTER(arg[0], arg[1]); - Q_strncpyz(VM_POINTER(arg[0]), Cmd_Args(), VM_LONG(arg[1])); + cmdfuncs->Args(VM_POINTER(arg[0]), VM_LONG(arg[1])); break; case CG_CVAR_REGISTER: if (arg[0]) @@ -622,19 +629,11 @@ static qintptr_t CG_SystemCalls(void *offset, quintptr_t mask, qintptr_t fn, con return VMQ3_Cvar_Update(VM_POINTER(arg[0])); case CG_CVAR_SET: - { - cvar_t *var; - var = Cvar_FindVar(VM_POINTER(arg[0])); - if (var) - Cvar_Set(var, VM_POINTER(arg[1])?VM_POINTER(arg[1]):""); //set it - else - Cvar_Get(VM_POINTER(arg[0]), VM_POINTER(arg[1]), 0, "Q3CG created"); //create one - } + cvarfuncs->SetString(VM_POINTER(arg[0]), VM_POINTER(arg[1])?VM_POINTER(arg[1]):""); break; case CG_CVAR_VARIABLESTRINGBUFFER: { - cvar_t *var; - var = Cvar_FindVar(VM_POINTER(arg[0])); + cvar_t *var = cvarfuncs->GetNVFDG(VM_POINTER(arg[0]), NULL, 0, NULL, "Q3CG created"); if (!VM_LONG(arg[2])) VM_LONG(ret) = 0; else if (!var) @@ -653,20 +652,18 @@ static qintptr_t CG_SystemCalls(void *offset, quintptr_t mask, qintptr_t fn, con case CG_SENDCONSOLECOMMAND: Con_DPrintf("CG_SENDCONSOLECOMMAND: %s", (char*)VM_POINTER(arg[0])); - Cbuf_AddText(VM_POINTER(arg[0]), RESTRICT_SERVER); + cmdfuncs->AddText(VM_POINTER(arg[0]), false); break; case CG_ADDCOMMAND: - Cmd_AddCommand(VM_POINTER(arg[0]), NULL); + cmdfuncs->AddCommand(VM_POINTER(arg[0]), NULL, NULL); break; case CG_SENDCLIENTCOMMAND: Con_DPrintf("CG_SENDCLIENTCOMMAND: %s", (char*)VM_POINTER(arg[0])); - CL_SendClientCommand(true, "%s", (char*)VM_POINTER(arg[0])); + CLQ3_SendClientCommand("%s", (char*)VM_POINTER(arg[0])); break; case CG_UPDATESCREEN: //force a buffer swap cos loading won't refresh it soon. - if (!Key_Dest_Has(kdm_console)) - scr_con_current = 0; - SCR_UpdateScreen(); + drawfuncs->RedrawScreen(); break; case CG_FS_FOPENFILE: //fopen @@ -682,6 +679,8 @@ static qintptr_t CG_SystemCalls(void *offset, quintptr_t mask, qintptr_t fn, con case CG_FS_WRITE: //fwrite Con_DPrintf("CG_FS_WRITE: not implemented\n"); break; + case CG_FS_SEEK: + return VM_FSeek(arg[0], arg[1], arg[2], 1); case CG_FS_FCLOSEFILE: //fclose VM_fclose(VM_LONG(arg[0]), 1); break; @@ -691,15 +690,15 @@ static qintptr_t CG_SystemCalls(void *offset, quintptr_t mask, qintptr_t fn, con unsigned int pc; unsigned int modhandle = VM_LONG(arg[1]); model_t *mod; - if (modhandle >= MAX_PRECACHE_MODELS) + if (modhandle >= countof(ccs.model_precache)) { -// if (modhandle == MAX_PRECACHE_MODELS+1) +// if (modhandle == countof(ccs.model_precache)+1) // mod = &capsule_model; // else mod = box_model; } else - mod = cl.model_precache[modhandle+1]; + mod = ccs.model_precache[modhandle]; if (mod && mod->loadstate == MLS_LOADED) pc = mod->funcs.NativeContents(mod, 0, 0, NULL, VM_POINTER(arg[0]), vec3_origin, vec3_origin); else @@ -716,15 +715,15 @@ static qintptr_t CG_SystemCalls(void *offset, quintptr_t mask, qintptr_t fn, con float *origin = VM_POINTER(arg[2]); float *angles = VM_POINTER(arg[3]); model_t *mod; - if (modhandle >= MAX_PRECACHE_MODELS) + if (modhandle >= countof(ccs.model_precache)) { -// if (modhandle == MAX_PRECACHE_MODELS+1) +// if (modhandle == countof(ccs.model_precache)+1) // mod = &capsule_model; // else mod = box_model; } else - mod = cl.model_precache[modhandle+1]; + mod = ccs.model_precache[modhandle]; if (mod && mod->loadstate == MLS_LOADED) { @@ -768,15 +767,15 @@ static qintptr_t CG_SystemCalls(void *offset, quintptr_t mask, qintptr_t fn, con float *origin = VM_POINTER(arg[7]); float *angles = VM_POINTER(arg[8]); model_t *mod; - if (modhandle >= MAX_PRECACHE_MODELS) + if (modhandle >= countof(ccs.model_precache)) { -// if (modhandle == MAX_PRECACHE_MODELS+1) +// if (modhandle == countof(ccs.model_precache)+1) // mod = &capsule_model; // else mod = box_model; } else - mod = cl.model_precache[modhandle+1]; + mod = ccs.model_precache[modhandle]; if (!mins) mins = vec3_origin; @@ -788,7 +787,7 @@ static qintptr_t CG_SystemCalls(void *offset, quintptr_t mask, qintptr_t fn, con angles = vec3_origin; if (mod && mod->loadstate == MLS_LOADED) #if !defined(CLIENTONLY) || defined(CSQC_DAT) - World_TransformedTrace(mod, 0, 0, start, end, mins, maxs, fn==CG_CM_TRANSFORMEDCAPSULETRACE, &tr, origin, angles, brushmask); + worldfuncs->TransformedTrace(mod, 0, 0, start, end, mins, maxs, fn==CG_CM_TRANSFORMEDCAPSULETRACE, &tr, origin, angles, brushmask); #else { #ifdef warningmsg @@ -828,27 +827,31 @@ static qintptr_t CG_SystemCalls(void *offset, quintptr_t mask, qintptr_t fn, con float *end = VM_POINTER(arg[2]); float *mins = VM_POINTER(arg[3]); float *maxs = VM_POINTER(arg[4]); - unsigned int modhandle = VM_LONG(arg[5]); - int brushmask = VM_LONG(arg[6]); + unsigned int modhandle = VM_LONG(arg[5]); + unsigned int brushmask = VM_LONG(arg[6]); model_t *mod; - if (modhandle >= MAX_PRECACHE_MODELS) + if (modhandle >= countof(ccs.model_precache)) { -// if (modhandle == MAX_PRECACHE_MODELS+1) +// if (modhandle == countof(ccs.model_precache)+1) // mod = &capsule_model; // else mod = box_model; } else - mod = cl.model_precache[modhandle+1]; + mod = ccs.model_precache[modhandle]; if (mod->loadstate != MLS_LOADED) { if (mod->loadstate == MLS_NOTLOADED) - Mod_LoadModel(mod, MLV_SILENT); + scenefuncs->LoadModel(mod->publicname, MLV_SILENTSYNC); if (mod->loadstate == MLS_LOADING) COM_WorkerPartialSync(mod, &mod->loadstate, MLS_LOADING); if (mod->loadstate != MLS_LOADED) - mod = box_model; //stop crashes, even if this is wrong. + { + memset(results, 0, sizeof(*results)); + results->fraction = 1; + break; + } } if (!mins) @@ -875,45 +878,40 @@ static qintptr_t CG_SystemCalls(void *offset, quintptr_t mask, qintptr_t fn, con { int i; char *mapname = VM_POINTER(arg[0]); - strcpy(cl.model_name[1], mapname); - cl.worldmodel = cl.model_precache[1] = Mod_ForName(Mod_FixName(mapname, mapname), MLV_SILENT); - if (cl.worldmodel->loadstate == MLS_LOADING) - COM_WorkerPartialSync(cl.worldmodel, &cl.worldmodel->loadstate, MLS_LOADING); - if (cl.worldmodel->loadstate != MLS_LOADED) - Host_EndGame("Couldn't load map %s", mapname); + ccs.worldmodel = ccs.model_precache[0] = worldfuncs->LoadModel(mapname, MLV_SILENTSYNC); + if (ccs.worldmodel->loadstate != MLS_LOADED) + plugfuncs->EndGame("Couldn't load map %s", mapname); - for (i=1 ; inumsubmodels ; i++) - { - strcpy(cl.model_name[1+i], va("*%i", i)); - cl.model_precache[i+1] = Mod_ForName (Mod_FixName(cl.model_name[i+1], mapname), MLV_SILENT); - } + + for (i=1 ; i<=ccs.worldmodel->numsubmodels && i < countof(ccs.model_precache); i++) + ccs.model_precache[i] = worldfuncs->LoadModel(worldfuncs->FixName(va("*%i", i), mapname), MLV_SILENTSYNC); } break; case CG_CM_INLINEMODEL: - if ((unsigned int)VM_LONG(arg[0]) > (cl.worldmodel?cl.worldmodel->numsubmodels:0)) - Host_EndGame("cgame asked for invalid model number\n"); + if ((unsigned int)VM_LONG(arg[0]) > (ccs.worldmodel?ccs.worldmodel->numsubmodels:0)) + plugfuncs->EndGame("cgame asked for invalid model number\n"); VM_LONG(ret) = VM_LONG(arg[0]); break; case CG_CM_NUMINLINEMODELS: - VM_LONG(ret) = cl.worldmodel?cl.worldmodel->numsubmodels:0; + VM_LONG(ret) = ccs.worldmodel?ccs.worldmodel->numsubmodels:0; break; case CG_CM_TEMPBOXMODEL: - box_model = CM_TempBoxModel(VM_POINTER(arg[0]), VM_POINTER(arg[1])); - VM_LONG(ret) = MAX_PRECACHE_MODELS; + box_model = worldfuncs->TempBoxModel(VM_POINTER(arg[0]), VM_POINTER(arg[1])); + VM_LONG(ret) = countof(ccs.model_precache); break; case CG_CM_TEMPCAPSULEMODEL: - box_model = CM_TempBoxModel(VM_POINTER(arg[0]), VM_POINTER(arg[1])); - VM_LONG(ret) = MAX_PRECACHE_MODELS+1; + box_model = worldfuncs->TempBoxModel(VM_POINTER(arg[0]), VM_POINTER(arg[1])); + VM_LONG(ret) = countof(ccs.model_precache)+1; break; case CG_R_MODELBOUNDS: VALIDATEPOINTER(arg[1], sizeof(vec3_t)); VALIDATEPOINTER(arg[2], sizeof(vec3_t)); { - model_t *mod = VM_FROMMHANDLE(arg[0]); + model_t *mod = scenefuncs->ModelFromId(arg[0]); if (mod) { if (mod->loadstate == MLS_LOADING) @@ -929,42 +927,41 @@ static qintptr_t CG_SystemCalls(void *offset, quintptr_t mask, qintptr_t fn, con { char *name = VM_POINTER(arg[0]); model_t *mod; - mod = Mod_ForName(Mod_FixName(name, cl.model_name[1]), MLV_SILENT); - if (mod->loadstate == MLS_LOADING) - { //needed to ensure it really is missing - if (!COM_FCheckExists(mod->name)) - COM_WorkerPartialSync(mod, &mod->loadstate, MLS_LOADING); - } + if (!name) + return 0; + mod = scenefuncs->LoadModel(worldfuncs->FixName(name, ccs.worldmodel->name), MLV_SILENTSYNC); if (mod->loadstate == MLS_FAILED || mod->type == mod_dummy) VM_LONG(ret) = 0; else - VM_LONG(ret) = VM_TOMHANDLE(mod); + VM_LONG(ret) = scenefuncs->ModelToId(mod); } break; case CG_R_REGISTERSKIN: - VM_LONG(ret) = Mod_RegisterSkinFile(VM_POINTER(arg[0])); + VM_LONG(ret) = scenefuncs->RegisterSkinFile(VM_POINTER(arg[0])); break; case CG_R_REGISTERSHADER: if (!*(char*)VM_POINTER(arg[0])) VM_LONG(ret) = 0; else - VM_LONG(ret) = VM_TOSHANDLE(R_RegisterPic(VM_POINTER(arg[0]), NULL)); + VM_LONG(ret) = drawfuncs->LoadImage(VM_POINTER(arg[0])); break; case CG_R_REGISTERSHADERNOMIP: if (!*(char*)VM_POINTER(arg[0])) VM_LONG(ret) = 0; else - VM_LONG(ret) = VM_TOSHANDLE(R_RegisterPic(VM_POINTER(arg[0]), NULL)); + VM_LONG(ret) = drawfuncs->LoadImage(VM_POINTER(arg[0])); break; case CG_R_CLEARSCENE: //clear scene (not rtlights, only dynamic ones) - CL_ClearEntityLists(); - rtlights_first = RTL_FIRST; + scenefuncs->ClearScene(); break; case CG_R_ADDPOLYTOSCENE: - VQ3_AddPoly(VM_FROMSHANDLE(arg[0]), VM_LONG(arg[1]), VM_POINTER(arg[2])); + VQ3_AddPolys(drawfuncs->ShaderFromId(arg[0]), VM_LONG(arg[1]), VM_POINTER(arg[2]), 1); + break; + case CG_R_ADDPOLYSTOSCENE: + VQ3_AddPolys(drawfuncs->ShaderFromId(arg[0]), VM_LONG(arg[1]), VM_POINTER(arg[2]), VM_LONG(arg[3])); break; case CG_R_ADDREFENTITYTOSCENE: //add ent to scene VQ3_AddEntity(VM_POINTER(arg[0])); @@ -972,12 +969,14 @@ static qintptr_t CG_SystemCalls(void *offset, quintptr_t mask, qintptr_t fn, con case CG_R_ADDADDITIVELIGHTTOSCENE: case CG_R_ADDLIGHTTOSCENE: //add light to scene. { - float *org = VM_POINTER(arg[0]); - CL_NewDlight(-1, org, VM_FLOAT(arg[1]), 0, VM_FLOAT(arg[2]), VM_FLOAT(arg[3]), VM_FLOAT(arg[4])); + dlight_t *dl = scenefuncs->AllocDlightOrg(-1, VM_POINTER(arg[0])); + dl->flags = LFLAG_NORMALMODE|LFLAG_REALTIMEMODE; + dl->radius = VM_FLOAT(arg[1]); + dl->die = ccs.time+0.1; + VectorSet(dl->color, VM_FLOAT(arg[2]), VM_FLOAT(arg[3]), VM_FLOAT(arg[4])); } break; case CG_R_RENDERSCENE: //render scene - R_PushDlights(); VQ3_RenderView(VM_POINTER(arg[0])); break; @@ -985,25 +984,25 @@ static qintptr_t CG_SystemCalls(void *offset, quintptr_t mask, qintptr_t fn, con { float *f = VM_POINTER(arg[0]); if (f) - R2D_ImageColours(f[0], f[1], f[2], f[3]); + drawfuncs->Colour4f(f[0], f[1], f[2], f[3]); else - R2D_ImageColours(1, 1, 1, 1); + drawfuncs->Colour4f(1, 1, 1, 1); } break; case CG_R_DRAWSTRETCHPIC: - R2D_Image(VM_FLOAT(arg[0]), VM_FLOAT(arg[1]), VM_FLOAT(arg[2]), VM_FLOAT(arg[3]), VM_FLOAT(arg[4]), VM_FLOAT(arg[5]), VM_FLOAT(arg[6]), VM_FLOAT(arg[7]), VM_FROMSHANDLE(VM_LONG(arg[8]))); + drawfuncs->Image(VM_FLOAT(arg[0]), VM_FLOAT(arg[1]), VM_FLOAT(arg[2]), VM_FLOAT(arg[3]), VM_FLOAT(arg[4]), VM_FLOAT(arg[5]), VM_FLOAT(arg[6]), VM_FLOAT(arg[7]), VM_LONG(arg[8])); break; case CG_R_LERPTAG: //Lerp tag... VALIDATEPOINTER(arg[0], sizeof(float)*12); - VM_LONG(ret) = VM_LerpTag(VM_POINTER(arg[0]), VM_FROMMHANDLE(arg[1]), VM_LONG(arg[2]), VM_LONG(arg[3]), VM_FLOAT(arg[4]), VM_POINTER(arg[5])); + VM_LONG(ret) = VM_LerpTag(VM_POINTER(arg[0]), scenefuncs->ModelFromId(arg[1]), VM_LONG(arg[2]), VM_LONG(arg[3]), VM_FLOAT(arg[4]), VM_POINTER(arg[5])); break; case CG_S_REGISTERSOUND: { sfx_t *sfx; - sfx = S_PrecacheSound(VM_POINTER(arg[0])); + sfx = audiofuncs->PrecacheSound(VM_POINTER(arg[0])); if (sfx) VM_LONG(ret) = VM_TOSTRCACHE(arg[0]); else @@ -1013,20 +1012,20 @@ static qintptr_t CG_SystemCalls(void *offset, quintptr_t mask, qintptr_t fn, con case CG_S_STARTLOCALSOUND: if (VM_LONG(arg[0]) != -1 && arg[0]) - S_LocalSound(VM_FROMSTRCACHE(arg[0])); + audiofuncs->LocalSound(VM_FROMSTRCACHE(arg[0]), CHAN_AUTO, 1.0); break; case CG_S_STARTSOUND:// ( vec3_t origin, int entityNum, int entchannel, sfxHandle_t sfx ) - S_StartSound(VM_LONG(arg[1])+1, VM_LONG(arg[2]), S_PrecacheSound(VM_FROMSTRCACHE(arg[3])), VM_POINTER(arg[0]), NULL, 1, 1, 0, 0, CF_CLI_NODUPES); + audiofuncs->StartSound(VM_LONG(arg[1])+1, VM_LONG(arg[2]), audiofuncs->PrecacheSound(VM_FROMSTRCACHE(arg[3])), VM_POINTER(arg[0]), NULL, 1, 1, 0, 0, CF_CLI_NODUPES); break; case CG_S_ADDLOOPINGSOUND: //entnum, origin, velocity, sfx - CG_StartLoopingSounds(VM_LONG(arg[0])+1, VM_POINTER(arg[1]), VM_POINTER(arg[2]), VM_FROMSTRCACHE(arg[3]), false); + CG_StartLoopingSounds(VM_LONG(arg[0])+1, VM_POINTER(arg[1]), VM_POINTER(arg[2]), -1, VM_FROMSTRCACHE(arg[3]), 1, false); break; case CG_S_ADDREALLOOPINGSOUND: //entnum, origin, velocity, sfx - CG_StartLoopingSounds(VM_LONG(arg[0])+1, VM_POINTER(arg[1]), VM_POINTER(arg[2]), VM_FROMSTRCACHE(arg[3]), true); + CG_StartLoopingSounds(VM_LONG(arg[0])+1, VM_POINTER(arg[1]), VM_POINTER(arg[2]), -1, VM_FROMSTRCACHE(arg[3]), 1, true); break; case CG_S_STOPLOOPINGSOUND: //entnum @@ -1042,33 +1041,19 @@ static qintptr_t CG_SystemCalls(void *offset, quintptr_t mask, qintptr_t fn, con break; case CG_S_STARTBACKGROUNDTRACK: - Media_NamedTrack(VM_POINTER(arg[0]), VM_POINTER(arg[1])); + audiofuncs->ChangeMusicTrack(VM_POINTER(arg[0]), VM_POINTER(arg[1])); return 0; case CG_S_STOPBACKGROUNDTRACK: - Media_NamedTrack(NULL, NULL); + audiofuncs->ChangeMusicTrack(NULL, NULL); return 0; case CG_S_RESPATIALIZE://void trap_S_Respatialize( int entityNum, const vec3_t origin, vec3_t axis[3], int inwater ); - { - int entnum = VM_LONG(arg[0])+1; - float *org = VM_POINTER(arg[1]); - vec3_t *axis = VM_POINTER(arg[2]); - int inwater = VM_LONG(arg[3]); - - cl.playerview[0].audio.defaulted = false; - cl.playerview[0].audio.entnum = entnum; - VectorCopy(org, cl.playerview[0].audio.origin); - VectorCopy(axis[0], cl.playerview[0].audio.forward); - VectorCopy(axis[1], cl.playerview[0].audio.right); - VectorCopy(axis[2], cl.playerview[0].audio.up); - cl.playerview[0].audio.reverbtype = inwater?1:0; - VectorClear(cl.playerview[0].audio.velocity); - } + audiofuncs->Spacialize(0, VM_LONG(arg[0])+1, VM_POINTER(arg[1]), VM_POINTER(arg[2]), VM_LONG(arg[3])?1:0, vec3_origin); break; case CG_KEY_ISDOWN: { - if (keydown[VM_LONG(arg[0])]) + if (inputfuncs->IsKeyDown(VM_LONG(arg[0]))) VM_LONG(ret) = 1; else VM_LONG(ret) = 0; @@ -1078,7 +1063,7 @@ static qintptr_t CG_SystemCalls(void *offset, quintptr_t mask, qintptr_t fn, con case CG_KEY_GETKEY: { int ret[1]; - M_FindKeysForCommand (0, 0, VM_POINTER(arg[0]), ret, NULL, countof(ret)); + inputfuncs->FindKeysForCommand(0, VM_POINTER(arg[0]), ret, NULL, countof(ret)); return ret[0]; } break; @@ -1091,16 +1076,31 @@ static qintptr_t CG_SystemCalls(void *offset, quintptr_t mask, qintptr_t fn, con break; case CG_GETGLCONFIG: - VALIDATEPOINTER(arg[0], 11332); + { + float vsize[2]; + q3glconfig_t *cfg; + VALIDATEPOINTER(arg[0], sizeof(q3glconfig_t)); + drawfuncs->GetVideoSize(vsize, NULL); + cfg = VM_POINTER(arg[0]); - { //FIXME: Clean this shit up //do any needed work - unsigned char *glconfig = VM_POINTER(arg[0]); - memset(glconfig, 0, 11304); - *(int *)(glconfig+11304) = vid.width; - *(int *)(glconfig+11308) = vid.height; - *(float *)(glconfig+11312) = (float)vid.width/vid.height; - memset((glconfig+11316), 0, 11332-11316); + memset(cfg, 0, sizeof(*cfg)); + + Q_strncpyz(cfg->renderer_string, "", sizeof(cfg->renderer_string)); + Q_strncpyz(cfg->vendor_string, "", sizeof(cfg->vendor_string)); + Q_strncpyz(cfg->version_string, "", sizeof(cfg->version_string)); + Q_strncpyz(cfg->extensions_string, "", sizeof(cfg->extensions_string)); + + cfg->colorBits = 32; + cfg->depthBits = 24; + cfg->stencilBits = 8;//sh_config.stencilbits; + cfg->textureCompression = true;//!!sh_config.hw_bc; + cfg->textureEnvAddAvailable = true;//sh_config.env_add; + + //these are the only three that really matter. + cfg->vidWidth = vsize[0]; + cfg->vidHeight = vsize[1]; + cfg->windowAspect = (float)vsize[0]/vsize[1]; } break; @@ -1146,7 +1146,7 @@ static qintptr_t CG_SystemCalls(void *offset, quintptr_t mask, qintptr_t fn, con break; case CG_MILLISECONDS: - VM_LONG(ret) = Sys_Milliseconds(); + VM_LONG(ret) = plugfuncs->GetMilliseconds(); break; case CG_REAL_TIME: VALIDATEPOINTER(arg[0], sizeof(q3time_t)); @@ -1227,7 +1227,7 @@ static qintptr_t CG_SystemCalls(void *offset, quintptr_t mask, qintptr_t fn, con break; case CG_R_REMAP_SHADER: - R_RemapShader(VM_POINTER(arg[0]), VM_POINTER(arg[1]), VM_FLOAT(arg[2])); + scenefuncs->RemapShader(VM_POINTER(arg[0]), VM_POINTER(arg[1]), VM_FLOAT(arg[2])); break; case CG_R_REGISTERFONT: @@ -1235,6 +1235,11 @@ static qintptr_t CG_SystemCalls(void *offset, quintptr_t mask, qintptr_t fn, con UI_RegisterFont(VM_POINTER(arg[0]), VM_LONG(arg[1]), VM_POINTER(arg[2])); break; + case CG_GET_ENTITY_TOKEN: + mapentspointer = cmdfuncs->ParseToken(mapentspointer, VM_POINTER(arg[0]), arg[1], NULL); + return !!mapentspointer; + + case CG_CIN_PLAYCINEMATIC: return UI_Cin_Play(VM_POINTER(arg[0]), VM_LONG(arg[1]), VM_LONG(arg[2]), VM_LONG(arg[3]), VM_LONG(arg[4]), VM_LONG(arg[5])); case CG_CIN_STOPCINEMATIC: @@ -1246,7 +1251,7 @@ static qintptr_t CG_SystemCalls(void *offset, quintptr_t mask, qintptr_t fn, con case CG_CIN_SETEXTENTS: return UI_Cin_SetExtents(VM_LONG(arg[0]), VM_LONG(arg[1]), VM_LONG(arg[2]), VM_LONG(arg[3]), VM_LONG(arg[4])); - case CG_FTE_FINDPARTICLEEFFECT: +/* case CG_FTE_FINDPARTICLEEFFECT: return pe->FindParticleType(VM_POINTER(arg[0])); case CG_FTE_SPAWNPARTICLEEFFECT: return pe->RunParticleEffectState(VM_POINTER(arg[0]), VM_POINTER(arg[1]), VM_FLOAT(arg[2]), VM_LONG(arg[3]), VM_POINTER(arg[4])); @@ -1255,7 +1260,14 @@ static qintptr_t CG_SystemCalls(void *offset, quintptr_t mask, qintptr_t fn, con case CG_FTE_FREEPARTICLESTATE: pe->DelinkTrailstate(VM_POINTER(arg[0])); break; - default: +*/ + case CG_CM_LOADMODEL: + case CG_REMOVECOMMAND: + case CG_TESTPRINTINT: + case CG_TESTPRINTFLOAT: + case CG_R_INPVS: + case CG_R_LIGHTFORPOINT: +// default: Con_Printf("Q3CG: Bad system trap: %i\n", (int)fn); } @@ -1308,18 +1320,14 @@ static qintptr_t EXPORT_FN CG_SystemCallsNative(qintptr_t arg, ...) return CG_SystemCalls(NULL, ~(quintptr_t)0, arg, args); } -int CG_Refresh(void) +int CG_Refresh(double time) { - int time; if (!cgvm) return false; - r_refdef.skyroom_enabled = false; - time = cl.time*1000; - VM_Call(cgvm, CG_DRAW_ACTIVE_FRAME, time, 0, false); - - R2D_ImageColours(1, 1, 1, 1); - + ccs.time = time; + vmfuncs->Call(cgvm, CG_DRAW_ACTIVE_FRAME, (int)(ccs.time*1000), 0, false); + drawfuncs->Colour4f(1, 1, 1, 1); return true; } @@ -1330,10 +1338,11 @@ void CG_Stop (void) Q3_SetKeyCatcher(Q3_GetKeyCatcher()&~2); if (cgvm) { - VM_Call(cgvm, CG_SHUTDOWN); - VM_Destroy(cgvm); + vmfuncs->Call(cgvm, CG_SHUTDOWN); + vmfuncs->Destroy(cgvm); VM_fcloseall(1); cgvm = NULL; + } } @@ -1341,7 +1350,7 @@ qboolean CG_VideoRestarted(void) { if (cgvm) { - VM_Call(cgvm, CG_INIT, ccs.serverMessageNum, ccs.lastServerCommandNum, cl.playerview[0].playernum); + vmfuncs->Call(cgvm, CG_INIT, ccs.serverMessageNum, ccs.lastServerCommandNum, ccs.playernum); return true; } return false; @@ -1350,39 +1359,35 @@ qboolean CG_VideoRestarted(void) void CG_Start (void) { SCR_SetLoadingStage(0); - if (cls.protocol != CP_QUAKE3) - { //q3 clients only. - CG_Stop(); - return; - } + CG_Stop(); - Z_FreeTags(CGTAGNUM); SCR_BeginLoadingPlaque(); - box_model = CM_TempBoxModel(vec3_origin, vec3_origin); + box_model = worldfuncs->TempBoxModel(vec3_origin, vec3_origin); //just in case. - cgvm = VM_Create("cgame", com_nogamedirnativecode.ival?NULL:CG_SystemCallsNative, "vm/cgame", CG_SystemCallsVM); + cgvm = vmfuncs->Create("cgame", cvarfuncs->GetFloat("com_gamedirnativecode")?CG_SystemCallsNative:NULL, "vm/cgame", CG_SystemCallsVM); if (cgvm) { //hu... cgame doesn't appear to have a query version call! SCR_EndLoadingPlaque(); - VM_Call(cgvm, CG_INIT, ccs.serverMessageNum, ccs.lastServerCommandNum, cl.playerview[0].playernum); + + vmfuncs->Call(cgvm, CG_INIT, ccs.serverMessageNum, ccs.lastServerCommandNum, ccs.playernum); } else { SCR_EndLoadingPlaque(); - Host_EndGame("Failed to initialise cgame module\n"); + plugfuncs->EndGame("Failed to initialise cgame module\n"); } } -qboolean CG_Command(void) +qboolean CG_ConsoleCommand(void) { if (!cgvm) return false; - Con_DPrintf("CG_Command: %s %s\n", Cmd_Argv(0), Cmd_Args()); - return VM_Call(cgvm, CG_CONSOLE_COMMAND); +// Con_DPrintf("CG_Command: %s %s\n", cmdfuncs->Argv(0), cmdfuncs->Args()); + return vmfuncs->Call(cgvm, CG_CONSOLE_COMMAND); } -void CG_Command_f(void) +/*void CG_Command_f(void) { if (cgvm) { @@ -1392,12 +1397,12 @@ void CG_Command_f(void) Cmd_ForwardToServer(); } } -} +}*/ -qboolean CG_KeyPress(int key, int unicode, int down) +qboolean CG_KeyPressed(int key, int unicode, int down) { - int catcher = Q3_GetKeyCatcher(); - if (!cgvm || !(catcher&8)) + + if (!cgvm || !(Q3_GetKeyCatcher()&8)) return false; /* if you change this here, it'll have to be changed in cl_cg.c too */ @@ -1451,18 +1456,13 @@ qboolean CG_KeyPress(int key, int unicode, int down) break; } - return VM_Call(cgvm, CG_KEY_EVENT, key, down); + return vmfuncs->Call(cgvm, CG_KEY_EVENT, key, down); } -void CG_Restart_f(void) +void CG_Restart(void) { CG_Stop(); CG_Start(); } -void CG_Init(void) -{ - Cmd_AddCommand("cg_restart", CG_Restart_f); -} - #endif diff --git a/engine/client/cl_demo.c b/engine/client/cl_demo.c index 6c67c943..b6c48add 100644 --- a/engine/client/cl_demo.c +++ b/engine/client/cl_demo.c @@ -262,7 +262,7 @@ int demo_preparsedemo(unsigned char *buffer, int bytes) { net_message.cursize = length; memcpy(net_message.data, buffer+ofs, length); - MSG_BeginReading(cls.netchan.netprim); + MSG_BeginReading(&net_message, cls.netchan.netprim); CLQW_ParseServerMessage(); } diff --git a/engine/client/cl_ents.c b/engine/client/cl_ents.c index d0cd0af0..108ca5a3 100644 --- a/engine/client/cl_ents.c +++ b/engine/client/cl_ents.c @@ -172,11 +172,11 @@ void CL_CloneDlight(dlight_t *dl, dlight_t *src) dl->customstyle = src->customstyle?Z_StrDup(src->customstyle):NULL; Z_Free(customstyle); } -static void CL_ClearDlight(dlight_t *dl, int key) +static void CL_ClearDlight(dlight_t *dl, int key, qboolean reused) { void *sm = dl->worldshadowmesh; unsigned int oq = dl->coronaocclusionquery; - unsigned int oqr = (dl->key == key)?dl->coronaocclusionresult:false; + unsigned int oqr = reused?dl->coronaocclusionresult:false; Z_Free(dl->customstyle); memset (dl, 0, sizeof(*dl)); dl->coronaocclusionquery = oq; @@ -224,7 +224,7 @@ dlight_t *CL_AllocSlight(void) } dl = &cl_dlights[i]; - CL_ClearDlight(dl, 0); + CL_ClearDlight(dl, 0, false); dl->flags = LFLAG_REALTIMEMODE; dl->corona = 0; return dl; @@ -249,7 +249,7 @@ dlight_t *CL_AllocDlight (int key) { if (dl->key == key) { - CL_ClearDlight(dl, key); + CL_ClearDlight(dl, key, true); return dl; } } @@ -270,10 +270,48 @@ dlight_t *CL_AllocDlight (int key) if (rtlights_first > dl - cl_dlights) rtlights_first = dl - cl_dlights; - CL_ClearDlight(dl, key); + CL_ClearDlight(dl, key, false); return dl; } +dlight_t *CL_AllocDlightOrg (int keyidx, vec3_t keyorg) +{ + int i; + dlight_t *dl; + +// first look for an exact key match + dl = cl_dlights+rtlights_first; + for (i=rtlights_first ; ikey == keyidx && VectorCompare(dl->origin, keyorg)) + { + CL_ClearDlight(dl, keyidx, true); + VectorCopy(keyorg, dl->origin); + return dl; + } + } + + //default to the first + dl = &cl_dlights[rtlights_first?rtlights_first-1:0]; + //try and find one that is free + for (i=RTL_FIRST; i > rtlights_first && i > 0; ) + { + i--; + if (!cl_dlights[i].radius) + { + dl = &cl_dlights[i]; + break; + } + } + if (rtlights_first > dl - cl_dlights) + rtlights_first = dl - cl_dlights; + + CL_ClearDlight(dl, keyidx, false); + VectorCopy(keyorg, dl->origin); + return dl; +} + + /* =============== CL_NewDlight diff --git a/engine/client/cl_input.c b/engine/client/cl_input.c index 4d12e50e..d02340a8 100644 --- a/engine/client/cl_input.c +++ b/engine/client/cl_input.c @@ -1609,7 +1609,7 @@ void VARGS CL_SendSeatClientCommand(qboolean reliable, unsigned int seat, char * #ifdef Q3CLIENT if (cls.protocol == CP_QUAKE3) { - CLQ3_SendClientCommand("%s", string); + q3->cl.SendClientCommand("%s", string); return; } #endif @@ -2135,7 +2135,7 @@ static void CL_SendUserinfoUpdate(void) if (info == &cls.userinfo[0]) { InfoBuf_ToString(info, userinfo, sizeof(userinfo), NULL, NULL, NULL, NULL, NULL); - CLQ3_SendClientCommand("userinfo \"%s\"", userinfo); + q3->cl.SendClientCommand("userinfo \"%s\"", userinfo); } return; } @@ -2527,7 +2527,11 @@ void CL_SendCmd (double frametime, qboolean mainloop) #ifdef Q3CLIENT case CP_QUAKE3: msecs -= (double)msecstouse; - CLQ3_SendCmd(&cl_pendingcmd[0]); + i = cl.movesequence&UPDATE_MASK; + memcpy(cl.outframes[i].cmd, cl_pendingcmd, sizeof(usercmd_t)*bound(1, cl.splitclients, MAX_SPLITS)); + cl.outframes[i].cmd_sequence = cl.movesequence++; + q3->cl.SendCmd(cls.sockets, cl.outframes[i].cmd, cl.movesequence, cl.time); + cls.netchan.outgoing_sequence = cl.movesequence; CL_ClearPendingCommands(); //don't bank too much, because that results in banking speedcheats diff --git a/engine/client/cl_main.c b/engine/client/cl_main.c index 902ec495..79969745 100644 --- a/engine/client/cl_main.c +++ b/engine/client/cl_main.c @@ -57,7 +57,7 @@ cvar_t cl_timeout = CVAR("cl_timeout", "60"); cvar_t cl_shownet = CVARD("cl_shownet","0", "Debugging var. 0 shows nothing. 1 shows incoming packet sizes. 2 shows individual messages. 3 shows entities too."); // can be 0, 1, or 2 -cvar_t cl_disconnectreason = CVARAFD("_cl_disconnectreason", "", "com_errorMessage", CVAR_NOSAVE, "This cvar contains the reason for the last disconnection, so that mod menus can know why things failed."); +cvar_t cl_disconnectreason = CVARAFD("_cl_disconnectreason", "", /*q3*/"com_errorMessage", CVAR_NOSAVE, "This cvar contains the reason for the last disconnection, so that mod menus can know why things failed."); cvar_t cl_pure = CVARD("cl_pure", "0", "0=standard quake rules.\n1=clients should prefer files within packages present on the server.\n2=clients should use *only* files within packages present on the server.\nDue to quake 1.01/1.06 differences, a setting of 2 is only reliable with total conversions.\nIf sv_pure is set, the client will prefer the highest value set."); cvar_t cl_sbar = CVARFC("cl_sbar", "0", CVAR_ARCHIVE, CL_Sbar_Callback); @@ -695,7 +695,9 @@ void CL_SendConnectPacket (netadr_t *to, int mtu, #ifdef Q3CLIENT if (connectinfo.protocol == CP_QUAKE3) { //q3 requires some very strange things. - CLQ3_SendConnectPacket(to, connectinfo.challenge, connectinfo.qport); + //cl.splitclients = 1; + if (q3) + q3->cl.SendConnectPacket(cls.sockets, to, connectinfo.challenge, connectinfo.qport, cls.userinfo); return; } #endif @@ -1118,7 +1120,7 @@ void CL_CheckForResend (void) net_message.packing = SZ_RAWBYTES; net_message.cursize = 0; - MSG_BeginReading(net_message.prim); + MSG_BeginReading(&net_message, net_message.prim); if (connectinfo.mode == CIM_QEONLY) { @@ -1247,10 +1249,7 @@ void CL_CheckForResend (void) if (!connectinfo.clogged) { #ifdef Q3CLIENT - //Q3 clients send their cdkey to the q3 authorize server. - //they send this packet with the challenge. - //and the server will refuse the client if it hasn't sent it. - CLQ3_SendAuthPacket(to); + q3->cl.SendAuthPacket(cls.sockets, to); #endif if (connectinfo.istransfer || connectinfo.numadr>1) @@ -1281,7 +1280,7 @@ void CL_CheckForResend (void) { contype |= 1; /*always try qw type connections*/ #ifdef VM_UI - if (!UI_IsRunning()) //don't try to connect to nq servers when running a q3ui. I was getting annoying error messages from q3 servers due to this. + if (!q3->ui.IsRunning()) //don't try to connect to nq servers when running a q3ui. I was getting annoying error messages from q3 servers due to this. #endif contype |= 2; /*try nq connections periodically (or if its the default nq port)*/ } @@ -1823,6 +1822,7 @@ static void CL_ReconfigureCommands(int newgame) #endif extern void CL_Say_f (void); extern void CL_SayTeam_f (void); + extern void CL_Color_f (void); static const struct { const char *name; @@ -1834,8 +1834,9 @@ static void CL_ReconfigureCommands(int newgame) #define Q2 (1u<cl.Disconnect(cls.sockets); #endif #ifdef CSQC_DAT CSQC_Shutdown(); @@ -2199,7 +2201,7 @@ void CL_Disconnect (const char *reason) CL_ClearState(false); - FS_PureMode(0, NULL, NULL, NULL, NULL, 0); + FS_PureMode(NULL, 0, NULL, NULL, NULL, NULL, 0); Alias_WipeStuffedAliases(); @@ -2440,7 +2442,7 @@ void CL_CheckServerPacks(void) if (pure != oldpure || cl.serverpakschanged) { CL_PakDownloads((pure && !cl_download_packages.ival)?1:cl_download_packages.ival); - FS_PureMode(pure, cl.serverpacknames, cl.serverpackhashes, NULL, NULL, cls.challenge); + FS_PureMode(NULL, pure, cl.serverpacknames, cl.serverpackhashes, NULL, NULL, cls.challenge); if (pure) { @@ -3226,7 +3228,7 @@ void CL_ConnectionlessPacket (void) int c; char adr[MAX_ADR_SIZE]; - MSG_BeginReading (msg_nullnetprim); + MSG_BeginReading (&net_message, msg_nullnetprim); MSG_ReadLong (); // skip the -1 Cmd_TokenizeString(net_message.data+4, false, false); @@ -3885,7 +3887,9 @@ client_connect: //fixme: make function #endif CL_ParseEstablished(); #ifdef Q3CLIENT - if (cls.protocol != CP_QUAKE3) + if (cls.protocol == CP_QUAKE3) + q3->cl.Established(); + else #endif CL_SendClientCommand(true, "new"); cls.state = ca_connected; @@ -4004,7 +4008,7 @@ void CLNQ_ConnectionlessPacket(void) if (net_message.cursize < 5) return; //not enough size to be meaningful (qe does not include a port number) - MSG_BeginReading (msg_nullnetprim); + MSG_BeginReading (&net_message, msg_nullnetprim); length = LongSwap(MSG_ReadLong ()); if (!(length & NETFLAG_CTL)) return; //not an nq control packet. @@ -4118,7 +4122,7 @@ void CL_ReadPacket(void) #ifdef NQPROT if (cls.demoplayback == DPB_NETQUAKE) { - MSG_BeginReading (cls.netchan.netprim); + MSG_BeginReading (&net_message, cls.netchan.netprim); cls.netchan.last_received = realtime; CLNQ_ParseServerMessage (); @@ -4130,7 +4134,7 @@ void CL_ReadPacket(void) #ifdef Q2CLIENT if (cls.demoplayback == DPB_QUAKE2) { - MSG_BeginReading (cls.netchan.netprim); + MSG_BeginReading (&net_message, cls.netchan.netprim); cls.netchan.last_received = realtime; CLQ2_ParseServerMessage (); return; @@ -4212,13 +4216,21 @@ void CL_ReadPacket(void) #endif case CP_QUAKE3: #ifdef Q3CLIENT - CLQ3_ParseServerMessage(); + { + cactive_t newstate = q3->cl.ParseServerMessage(&net_message); + if (newstate != cls.state) + { + cls.state = newstate; + if (cls.state == ca_active) + CL_MakeActive("Quake3Arena"); //became active, can flush old stuff now. + } + } #endif break; case CP_QUAKEWORLD: if (cls.demoplayback == DPB_MVD || cls.demoplayback == DPB_EZTV) { - MSG_BeginReading(cls.netchan.netprim); + MSG_BeginReading(&net_message, cls.netchan.netprim); cls.netchan.last_received = realtime; cls.netchan.outgoing_sequence = cls.netchan.incoming_sequence; } @@ -5343,6 +5355,7 @@ void CL_Init (void) Stats_Init(); #endif CL_ClearState(false); //make sure the cl.* fields are set properly if there's no ssqc or whatever. + R_BumpLightstyles(1); } @@ -5968,7 +5981,7 @@ done: if (!(f->flags & HRF_ACTION)) { Key_Dest_Remove(kdm_console); - Menu_Prompt(Host_RunFilePrompted, f, va("Exec %s?\n", COM_SkipPath(f->fname)), "Yes", NULL, "Cancel"); + Menu_Prompt(Host_RunFilePrompted, f, va("Exec %s?\n", COM_SkipPath(f->fname)), "Yes", NULL, "Cancel", true); return; } if (f->flags & HRF_OPENED) @@ -6079,17 +6092,17 @@ done: Key_Dest_Remove(kdm_console); if (haschanged) { - Menu_Prompt(Host_RunFilePrompted, f, va("File already exists.\nWhat would you like to do?\n%s\n", displayname), "Overwrite", "Run old", "Cancel"); + Menu_Prompt(Host_RunFilePrompted, f, va("File already exists.\nWhat would you like to do?\n%s\n", displayname), "Overwrite", "Run old", "Cancel", true); return; } else if (isnew) { - Menu_Prompt(Host_RunFilePrompted, f, va("File appears new.\nWould you like to install\n%s\n", displayname), "Install!", "", "Cancel"); + Menu_Prompt(Host_RunFilePrompted, f, va("File appears new.\nWould you like to install\n%s\n", displayname), "Install!", "", "Cancel", true); return; } else { - Menu_Prompt(NULL, NULL, va("File is already installed\n%s\n", displayname), NULL, NULL, "Cancel"); + Menu_Prompt(NULL, NULL, va("File is already installed\n%s\n", displayname), NULL, NULL, "Cancel", true); f->flags |= HRF_ABORT; } } @@ -6721,11 +6734,6 @@ void CL_StartCinematicOrMenu(void) Key_Dest_Remove(kdm_console); //make sure console doesn't stay up weirdly. } - //start up the ui now we have a renderer -#ifdef VM_UI - UI_Start(); -#endif - Cbuf_AddText("menu_restart\n", RESTRICT_LOCAL); Con_TPrintf ("^Ue080^Ue081^Ue081^Ue081^Ue081^Ue081^Ue081 %s %sInitialized ^Ue081^Ue081^Ue081^Ue081^Ue081^Ue081^Ue082\n", *fs_gamename.string?fs_gamename.string:"Nothing", com_installer?"Installer ":""); @@ -7043,7 +7051,7 @@ void Host_FinishLoading(void) char *scheme = Sys_URIScheme_NeedsRegistering(); if (scheme) { - Menu_Prompt(Host_URIPrompt, NULL, va("The URI scheme %s:// is not configured.\nRegister now?", scheme), "Register", NULL, "No"); + Menu_Prompt(Host_URIPrompt, NULL, va("The URI scheme %s:// is not configured.\nRegister now?", scheme), "Register", NULL, "No", true); Z_Free(scheme); } } @@ -7147,10 +7155,6 @@ void Host_Init (quakeparms_t *parms) Editor_Init(); #endif -#ifdef VM_UI - UI_Init(); -#endif - #ifdef CL_MASTER Master_SetupSockets(); #endif @@ -7168,6 +7172,10 @@ void Host_Init (quakeparms_t *parms) host_initialized = true; forcesaveprompt = false; +#ifdef PLUGINS + Plug_Initialise(false); +#endif + Sys_SendKeyEvents(); //the engine is fully running, except the file system may be nulled out waiting for a manifest to download. @@ -7207,10 +7215,6 @@ void Host_Shutdown(void) CSQC_Shutdown(); #endif -#ifdef VM_UI - UI_Stop(); -#endif - S_Shutdown(true); CDAudio_Shutdown (); IN_Shutdown (); @@ -7240,9 +7244,6 @@ void Host_Shutdown(void) Stats_Clear(); #endif Ruleset_Shutdown(); -#ifdef Q3CLIENT - VMQ3_FlushStringHandles(); -#endif COM_DestroyWorkerThread(); diff --git a/engine/client/cl_master.h b/engine/client/cl_master.h index 83c85188..6bf00ed9 100644 --- a/engine/client/cl_master.h +++ b/engine/client/cl_master.h @@ -239,8 +239,8 @@ void MasterInfo_WriteServers(void); char *Master_ServerToString (char *s, int len, serverinfo_t *a); //like NET_AdrToString, but handles more complex addresses. hostcachekey_t Master_KeyForName(const char *keyname); -float Master_ReadKeyFloat(serverinfo_t *server, hostcachekey_t keynum); -char *Master_ReadKeyString(serverinfo_t *server, hostcachekey_t keynum); +float Master_ReadKeyFloat(serverinfo_t *server, unsigned int keynum); +char *Master_ReadKeyString(serverinfo_t *server, unsigned int keynum); int Master_SortServers(void); void Master_SetSortField(hostcachekey_t field, qboolean descending); diff --git a/engine/client/cl_parse.c b/engine/client/cl_parse.c index 699247bb..0e0ef831 100644 --- a/engine/client/cl_parse.c +++ b/engine/client/cl_parse.c @@ -1492,8 +1492,7 @@ static int CL_LoadModels(int stage, qboolean dontactuallyload) SCR_SetLoadingFile("newmap"); // if (!cl.worldmodel || cl.worldmodel->type == mod_dummy) // Host_EndGame("No worldmodel was loaded\n"); - cl.model_precaches_added = false; - Surf_NewMap (); + Surf_NewMap (cl.worldmodel); pmove.physents[0].model = cl.worldmodel; @@ -2642,7 +2641,7 @@ void DL_Abort(qdownload_t *dl, enum qdlabort aborttype) break; #ifdef Q3CLIENT case DL_Q3: - CLQ3_SendClientCommand("stopdl"); + q3->cl.SendClientCommand("stopdl"); break; #endif case DL_QW: @@ -3329,13 +3328,7 @@ static void CLQW_ParseServerData (void) #ifndef CLIENTONLY if (!sv.state) #endif - { - COM_FlushTempoaryPacks(); COM_Gamedir(str, NULL); -#ifndef CLIENTONLY - InfoBuf_SetStarKey (&svs.info, "*gamedir", str); -#endif - } CL_ClearState (true); #ifdef QUAKEHUD @@ -3541,9 +3534,6 @@ static void CLQW_ParseServerData (void) S_Voip_MapChange(); #endif -#ifdef VM_CG - CG_Stop(); -#endif #ifdef CSQC_DAT CSQC_Shutdown(); //revive it when we get the serverinfo saying the checksum. #endif @@ -3935,13 +3925,7 @@ static void CLNQ_ParseServerData(void) //Doesn't change gamedir - use with caut #ifndef CLIENTONLY if (!sv.state) #endif - { - COM_FlushTempoaryPacks(); COM_Gamedir(str, NULL); -#ifndef CLIENTONLY - InfoBuf_SetStarKey (&svs.info, "*gamedir", str); -#endif - } } if (cl.allocated_client_slots > MAX_CLIENTS) { @@ -4189,9 +4173,6 @@ Con_DPrintf ("CL_SignonReply: %i\n", cls.signon); case 3: CL_SendClientCommand(true, "begin"); -#ifdef VM_CG - CG_Start(); -#endif break; case 4: @@ -4838,10 +4819,6 @@ static void CLQ2_Precache_f (void) cl.contentstage = 0; cl.sendprespawn = true; SCR_SetLoadingFile("loading data"); - -#ifdef VM_CG - CG_Start(); -#endif } #endif @@ -6924,8 +6901,6 @@ static void CL_ParsePrecache(void) // Con_Printf("svc_precache: Mod_ForName(\"%s\") failed\n", s); cl.model_precache[i] = model; Q_strncpyz (cl.model_name[i], s, sizeof(cl.model_name[i])); - - cl.model_precaches_added = true; } else Con_Printf("svc_precache: model index %i outside range %i...%i\n", i, 1, MAX_PRECACHE_MODELS); diff --git a/engine/client/cl_plugin.inc b/engine/client/cl_plugin.inc index b0e5816d..d9a63643 100644 --- a/engine/client/cl_plugin.inc +++ b/engine/client/cl_plugin.inc @@ -103,6 +103,33 @@ static unsigned int IN_GetKeyDest(void) return key_dest_mask; } +qboolean QDECL Plug_Input_IsKeyDown(int key) +{ + extern qboolean keydown[K_MAX]; + if (key >= 0 && key < K_MAX) + return !!keydown[key]; + return false; +} +void QDECL Plug_Input_ClearKeyStates(void) +{ + Key_ClearStates(); +} +unsigned int QDECL Plug_Input_GetMoveCount(void) +{ + return cl.movesequence; +} +usercmd_t *QDECL Plug_Input_GetMoveEntry(unsigned int move) +{ + if (move == cl.movesequence) + return NULL; //the partial + else if (move >= cl.movesequence) + return NULL; //too new + else if (cl.outframes[move&UPDATE_MASK].cmd_sequence != move) + return NULL; //too old or otherwise missing + else + return &cl.outframes[move&UPDATE_MASK].cmd[0]; +} + /* static void QDECL Plug_SCR_CenterPrint(int seat, const char *text) @@ -114,112 +141,37 @@ static void QDECL Plug_SCR_CenterPrint(int seat, const char *text) -typedef struct { - //Make SURE that the engine has resolved all cvar pointers into globals before this happens. - plugin_t *plugin; - char name[64]; - int type; //cache, wad, shader, raw - char *script; - mpic_t *pic; -} pluginimagearray_t; -size_t pluginimagearraylen; -pluginimagearray_t *pluginimagearray; - #include "shader.h" -static void Plug_Draw_UnloadImage(qhandle_t image) +static qboolean Plug_Draw_GetScreenSize(float *vsize, unsigned int *psize) { - size_t i = image-1; - if (i < 0 || i >= pluginimagearraylen) - return; - if (pluginimagearray[i].plugin == currentplug) - { - pluginimagearray[i].plugin = 0; - if (pluginimagearray[i].pic) - R_UnloadShader(pluginimagearray[i].pic); - pluginimagearray[i].pic = NULL; - pluginimagearray[i].name[0] = '\0'; - } -} -static void Plug_FreePlugImages(plugin_t *plug) -{ - size_t i; - for (i = 0; i < pluginimagearraylen; i++) - { - if (pluginimagearray[i].plugin == plug) - { - pluginimagearray[i].plugin = 0; - if (pluginimagearray[i].pic) - R_UnloadShader(pluginimagearray[i].pic); - pluginimagearray[i].pic = NULL; - pluginimagearray[i].name[0] = '\0'; - } - } -} - -//called before shaders get flushed, to avoid issues later. -void Plug_FreeAllImages(void) -{ - size_t i; - for (i = 0; i < pluginimagearraylen; i++) - { - if (pluginimagearray[i].pic) - { - R_UnloadShader(pluginimagearray[i].pic); - pluginimagearray[i].pic = NULL; - } - } + if (qrenderer<=0) + return false; + if (vsize) + vsize[0] = vid.width, vsize[1] = vid.height; + if (psize) + psize[0] = vid.pixelwidth, psize[1] = vid.pixelheight; + return true; } static qhandle_t Plug_Draw_LoadImage(const char *name, int type, const char *script) { - int i; - - mpic_t *pic; - - if (!*name) - return 0; - - for (i = 0; i < pluginimagearraylen; i++) - { - if (!pluginimagearray[i].plugin) - break; - if (pluginimagearray[i].plugin == currentplug) - { - if (!strcmp(name, pluginimagearray[i].name)) - break; - } - } - if (i == pluginimagearraylen) - { - pluginimagearraylen++; - pluginimagearray = BZ_Realloc(pluginimagearray, pluginimagearraylen*sizeof(pluginimagearray_t)); - pluginimagearray[i].pic = NULL; - } - - if (pluginimagearray[i].pic) - return i+1; //already loaded. - + shader_t *pic; if (qrenderer != QR_NONE) { if (type == 3) pic = NULL; else if (type == 2) pic = R_RegisterShader(name, SUF_NONE, script); - else if (type) - pic = R2D_SafePicFromWad(name); else pic = R2D_SafeCachePic(name); } else pic = NULL; - Q_strncpyz(pluginimagearray[i].name, name, sizeof(pluginimagearray[i].name)); - pluginimagearray[i].type = type; - pluginimagearray[i].pic = pic; - pluginimagearray[i].plugin = currentplug; - pluginimagearray[i].script = script?Z_StrDup(script):NULL; - return i + 1; + if (pic) + return pic->id+1; + return 0; } static qhandle_t QDECL Plug_Draw_LoadImageData(const char *name, const char *mimetype, void *codeddata, size_t datalength) @@ -232,8 +184,6 @@ static qhandle_t QDECL Plug_Draw_LoadImageData(const char *name, const char *mim if ((rgbdata = ReadRawImageFile(codeddata, datalength, &width, &height, &format, false, name))) { -// name = va("%s", name); - t = Image_FindTexture(name, NULL, IF_PREMULTIPLYALPHA|IF_NOMIPMAP|IF_UIPIC|IF_CLAMP); if (!TEXVALID(t)) t = Image_CreateTexture(name, NULL, IF_PREMULTIPLYALPHA|IF_NOMIPMAP|IF_UIPIC|IF_CLAMP); @@ -251,93 +201,51 @@ static qhandle_t QDECL Plug_Draw_LoadImageShader(const char *name, const char *s { return Plug_Draw_LoadImage(name, 2, script); } -static qhandle_t QDECL Plug_Draw_LoadImagePic(const char *name, qboolean type) +static qhandle_t QDECL Plug_Draw_LoadImagePic(const char *name) { - if (type != 0 && type != 1) - return 0; - return Plug_Draw_LoadImage(name, type, NULL); + return Plug_Draw_LoadImage(name, 0, NULL); } -void Plug_DrawReloadImages(void) +static shader_t *Plug_Draw_ShaderFromId(qhandle_t id) { - int i; - for (i = 0; i < pluginimagearraylen; i++) - { - if (!pluginimagearray[i].plugin) - { - pluginimagearray[i].pic = NULL; - continue; - } - - pluginimagearray[i].pic = R2D_SafePicFromWad(pluginimagearray[i].name); - //pluginimagearray[i].pic = R2D_SafeCachePic(pluginimagearray[i].name); - //pluginimagearray[i].pic = NULL; - } + if (--id >= r_numshaders) + return NULL; + return r_shaders[id]; } -//int R2D_ImageSize (qhandle_t image, float *w, float *h) static int QDECL Plug_Draw_ImageSize(qhandle_t image, float *w, float *h) { int iw, ih, ret; - mpic_t *pic; - int i; - - *w = 0; - *h = 0; - if (qrenderer == QR_NONE) - return 0; - i = image; - if (i <= 0 || i > pluginimagearraylen) - return -1; // you fool - i = i - 1; - if (pluginimagearray[i].plugin != currentplug) - return -1; - - if (pluginimagearray[i].pic) - pic = pluginimagearray[i].pic; - else if (pluginimagearray[i].type == 1) - return 0; //wasn't loaded. - else + if (image > 0 && image <= r_numshaders) { - pic = R2D_SafeCachePic(pluginimagearray[i].name); - if (!pic) - return -1; + ret = R_GetShaderSizes(r_shaders[image-1], &iw, &ih, true); + if (w) + *w = iw; + if (h) + *h = ih; + return ret; } - - ret = R_GetShaderSizes(pic, &iw, &ih, true); - *w = iw; - *h = ih; - return ret; + return -1; } static int QDECL Plug_Draw_Image(float x, float y, float w, float h, float s1, float t1, float s2, float t2, qhandle_t image) { - mpic_t *pic; - int i; - if (qrenderer == QR_NONE) - return 0; - - i = image; - if (i <= 0 || i > pluginimagearraylen) - return -1; // you fool - i = i - 1; - if (pluginimagearray[i].plugin != currentplug) - return -1; - - if (pluginimagearray[i].pic) - pic = pluginimagearray[i].pic; - else if (pluginimagearray[i].type == 1) - return 0; //wasn't loaded. - else + if (image > 0 && image <= r_numshaders) { - pic = R2D_SafeCachePic(pluginimagearray[i].name); - if (!pic) - return -1; + R2D_Image(x, y, w, h, s1, t1, s2, t2, r_shaders[image-1]); + return 1; } - - R2D_Image(x, y, w, h, s1, t1, s2, t2, pic); - return 1; + return 0; +} +static int QDECL Plug_Draw_Image2dQuad(const vec2_t *points, const vec2_t *texcoords, const vec4_t *colours, qhandle_t image) +{ + if (image > 0 && image <= r_numshaders) + { + R2D_Image2dQuad(points, texcoords, colours, r_shaders[image-1]); + return 1; + } + return 0; } //x1,y1,x2,y2 static void QDECL Plug_Draw_Line(float x1, float y1, float x2, float y2) @@ -454,13 +362,148 @@ static void QDECL Plug_Draw_Colour4f(float r, float g, float b, float a) R2D_ImageColours(r,g,b,a); } +static void QDECL Plug_Draw_RedrawScreen(void) +{ + SCR_UpdateScreen(); +} +static qhandle_t Plug_Scene_ModelToId(model_t *mod) +{ + if (!mod) + return 0; + return (mod-mod_known)+1; +} +static model_t *Plug_Scene_ModelFromId(qhandle_t id) +{ + extern int mod_numknown; + if ((unsigned)(--id) >= mod_numknown) + return NULL; + return mod_known+id; +} +static qhandle_t Plug_Scene_ShaderForSkin(qhandle_t modelid, int surfaceidx, int skinnum, float time) +{ + shader_t *s = Mod_ShaderForSkin(Plug_Scene_ModelFromId(modelid), surfaceidx, skinnum, time, NULL); + return s->id+1; +} +static void QDECL Plug_Scene_Clear(void) +{ + CL_ClearEntityLists(); + rtlights_first = RTL_FIRST; +} +static unsigned int Plug_Scene_AddPolydata(struct shader_s *s, unsigned int beflags, size_t numverts, size_t numidx, vecV_t **vertcoord, vec2_t **texcoord, vec4_t **colour, index_t **indexes) +{ + unsigned int ret; + scenetris_t *t; + /*reuse the previous trigroup if its the same shader*/ + if (cl_numstris && cl_stris[cl_numstris-1].shader == s && cl_stris[cl_numstris-1].flags == beflags) + t = &cl_stris[cl_numstris-1]; + else + { + if (cl_numstris == cl_maxstris) + { + cl_maxstris += 8; + cl_stris = BZ_Realloc(cl_stris, sizeof(*cl_stris)*cl_maxstris); + } + t = &cl_stris[cl_numstris++]; + t->shader = s; + t->flags = beflags; + t->numidx = 0; + t->numvert = 0; + t->firstidx = cl_numstrisidx; + t->firstvert = cl_numstrisvert; + } + ret = cl_numstrisvert - t->firstvert; + if (cl_maxstrisvert < cl_numstrisvert+numverts) + cl_stris_ExpandVerts(cl_numstrisvert+numverts + 64); + if (cl_maxstrisidx < cl_numstrisidx+numidx) + { + cl_maxstrisidx = cl_numstrisidx+numidx + 64; + cl_strisidx = BZ_Realloc(cl_strisidx, sizeof(*cl_strisidx)*cl_maxstrisidx); + } + *vertcoord = cl_strisvertv+cl_numstrisvert; + *texcoord = cl_strisvertt+cl_numstrisvert; + *colour = cl_strisvertc+cl_numstrisvert; + *indexes = cl_strisidx+cl_numstrisidx; + t->numvert += numverts; + t->numidx += numidx; + cl_numstrisvert += numverts; + cl_numstrisidx += numidx; + return ret; +} + +void R_DrawNameTags(void); +static void Plug_Scene_RenderScene(plugrefdef_t *in, size_t areabytes, const qbyte *areadata) +{ + size_t i; + extern cvar_t r_torch; + if (R2D_Flush) + R2D_Flush(); + + VectorCopy(in->viewaxisorg[0], r_refdef.viewaxis[0]); + VectorCopy(in->viewaxisorg[1], r_refdef.viewaxis[1]); + VectorCopy(in->viewaxisorg[2], r_refdef.viewaxis[2]); + VectorCopy(in->viewaxisorg[3], r_refdef.vieworg); + VectorAngles(r_refdef.viewaxis[0], r_refdef.viewaxis[2], r_refdef.viewangles, false); //do we actually still need this? + r_refdef.flags = in->flags; + r_refdef.fov_x = in->fov[0]; + r_refdef.fov_y = in->fov[1]; + r_refdef.fovv_x = in->fov_viewmodel[0]; + r_refdef.fovv_y = in->fov_viewmodel[1]; + r_refdef.vrect.x = in->rect.x; + r_refdef.vrect.y = in->rect.y; + r_refdef.vrect.width = in->rect.w; + r_refdef.vrect.height = in->rect.h; + r_refdef.time = in->time; + r_refdef.useperspective = true; + r_refdef.mindist = bound(0.1, gl_mindist.value, 4); + r_refdef.maxdist = gl_maxdist.value; + r_refdef.playerview = &cl.playerview[0]; + + if (in->flags & RDF_SKYROOMENABLED) + { + r_refdef.skyroom_enabled = true; + VectorCopy(in->skyroom_org, r_refdef.skyroom_pos); + } + else + r_refdef.skyroom_enabled = false; + + if (r_refdef.vrect.y < 0) + { //evil hack to work around player model ui bug. + //if the y coord is off screen, reduce the height to keep things centred, and reduce the fov to compensate. + r_refdef.vrect.height += r_refdef.vrect.y*2; + r_refdef.fov_y = in->fov[1] * r_refdef.vrect.height / in->rect.h; + r_refdef.fovv_y = in->fov_viewmodel[1] * r_refdef.vrect.height / in->rect.h; + r_refdef.vrect.y = 0; + } + + memset(&r_refdef.globalfog, 0, sizeof(r_refdef.globalfog)); + + if (r_torch.ival) + { + dlight_t *dl; + dl = CL_NewDlight(0, r_refdef.vieworg, 300, r_torch.ival, 0.5, 0.5, 0.2); + dl->flags |= LFLAG_SHADOWMAP|LFLAG_FLASHBLEND; + dl->fov = 60; + VectorCopy(r_refdef.viewaxis[0], dl->axis[0]); + VectorCopy(r_refdef.viewaxis[1], dl->axis[1]); + VectorCopy(r_refdef.viewaxis[2], dl->axis[2]); + } + + r_refdef.areabitsknown = areabytes>0; + for (i = 0; i < sizeof(r_refdef.areabits)/sizeof(int) && i < areabytes/sizeof(int); i++) + ((int*)r_refdef.areabits)[i] = ((int*)areadata)[i] ^ ~0; + R_PushDlights(); + R_RenderView(); + R_DrawNameTags(); + r_refdef.playerview = NULL; + r_refdef.time = 0; +} static void QDECL Plug_LocalSound(const char *soundname, int channel, float volume) { @@ -592,6 +635,18 @@ static void QDECL Plug_SetUserInfo(int seat, const char *key, const char *value) CL_SetInfo(seat, key, value); } +void QDECL Plug_CL_ClearState(void) +{ + CL_ClearState(true); +} +void QDECL Plug_CL_UpdateGameTime(double servertime) +{ + cl.oldgametime = cl.gametime; + cl.oldgametimemark = cl.gametimemark; + cl.gametime = servertime; + cl.gametimemark = realtime; +} + static qboolean QDECL Plug_GetLastInputFrame(int seat, usercmd_t *outcmd) { unsigned int curframe = (cl.movesequence-1u) & UPDATE_MASK; @@ -1056,11 +1111,27 @@ static void QDECL Plug_S_RawAudio(int sourceid, void *data, int speed, int sampl { S_RawAudio(sourceid, data, speed, samples, channels, width, volume); } +static void QDECL S_Spacialize(unsigned int seat, int entnum, vec3_t origin, vec3_t axis[3], int reverb, vec3_t velocity) +{ + if (seat >= countof(cl.playerview)) + return; + cl.playerview[seat].audio.defaulted = false; + cl.playerview[seat].audio.entnum = entnum; + VectorCopy(origin, cl.playerview[seat].audio.origin); + VectorCopy(axis[0], cl.playerview[seat].audio.forward); + VectorCopy(axis[1], cl.playerview[seat].audio.right); + VectorCopy(axis[2], cl.playerview[seat].audio.up); + cl.playerview[seat].audio.reverbtype = reverb; + VectorCopy(velocity, cl.playerview[seat].audio.velocity); +} +static sfx_t *QDECL Plug_S_PrecacheSound(const char *sndname) +{ + return S_PrecacheSound(sndname); +} static void Plug_Client_Close(plugin_t *plug) { menu_t *m = Menu_FindContext(currentplug); - Plug_FreePlugImages(plug); if (m) Menu_Unlink(m, true); @@ -1072,13 +1143,6 @@ static void Plug_Client_Close(plugin_t *plug) } } -static void Plug_Client_Shutdown(void) -{ - BZ_Free(pluginimagearray); - pluginimagearray = NULL; - pluginimagearraylen = 0; -} - diff --git a/engine/client/cl_screen.c b/engine/client/cl_screen.c index a381e17f..159ff1bd 100644 --- a/engine/client/cl_screen.c +++ b/engine/client/cl_screen.c @@ -2293,7 +2293,7 @@ void SCR_SetUpToDrawConsole (void) scr_con_target = 0; // not looking at an normal console } #ifdef VM_UI - else if (UI_OpenMenu()) + else if (q3 && q3->ui.OpenMenu()) scr_con_current = scr_con_target = 0; //force instantly hidden. #endif else @@ -2499,7 +2499,7 @@ void *SCR_ScreenShot_Capture(int fbwidth, int fbheight, int *stride, enum upload R2D_FillBlock(0, 0, vid.fbvwidth, vid.fbvheight); #ifdef VM_CG - if (!okay && CG_Refresh()) + if (!okay && q3->cg.Redraw(cl.time)) okay = true; #endif #ifdef CSQC_DAT diff --git a/engine/client/cl_ui.c b/engine/client/cl_ui.c index 5f9c1556..0133446e 100644 --- a/engine/client/cl_ui.c +++ b/engine/client/cl_ui.c @@ -1,4 +1,4 @@ -#include "quakedef.h" +#include "q3common.h" #ifdef VM_UI #include "clq3defs.h" #include "ui_public.h" @@ -7,6 +7,11 @@ static int keycatcher; +#include "botlib.h" +void SV_InitBotLib(void); +extern botlib_export_t *botlib; +qboolean CG_GetLimboString(int index, char *outbuf); + #define TT_STRING 1 // string #define TT_LITERAL 2 // literal #define TT_NUMBER 3 // number @@ -28,7 +33,7 @@ typedef struct { } script_t; static script_t *scripts; static int maxscripts; -static unsigned int ui_width, ui_height; //to track when it needs to be restarted (the api has no video mode changed event) +static float ui_size[2]; //to track when it needs to be restarted (the api has no video mode changed event) static menu_t uimenu; void Q3_SetKeyCatcher(int newcatcher) @@ -39,9 +44,9 @@ void Q3_SetKeyCatcher(int newcatcher) { uimenu.isopaque = false; //no surprises. if (newcatcher&2) - Menu_Push(&uimenu, false); + inputfuncs->Menu_Push(&uimenu, false); else - Menu_Unlink(&uimenu, false); + inputfuncs->Menu_Unlink(&uimenu, false); } } int Q3_GetKeyCatcher(void) @@ -81,6 +86,8 @@ int Script_Read(int handle, struct pc_token_s *token) char readstring[8192]; int i; script_t *sc = scripts+handle-1; + char thetoken[1024]; + com_tokentype_t tokentype; for(;;) { @@ -94,9 +101,9 @@ int Script_Read(int handle, struct pc_token_s *token) sc->lastreadptr = s; sc->lastreaddepth = sc->stackdepth; - s = (char *)COM_ParseToken(s, Q3SCRIPTPUNCTUATION); - Q_strncpyz(readstring, com_token, sizeof(readstring)); - if (com_tokentype == TTP_STRING) + s = (char *)cmdfuncs->ParsePunctuation(s, Q3SCRIPTPUNCTUATION, thetoken, sizeof(thetoken), &tokentype); + Q_strncpyz(readstring, thetoken, sizeof(readstring)); + if (tokentype == TTP_STRING) { while(s) { @@ -112,43 +119,43 @@ int Script_Read(int handle, struct pc_token_s *token) s++; if (*s == '\"') { - s = (char*)COM_ParseToken(s, Q3SCRIPTPUNCTUATION); - Q_strncatz(readstring, com_token, sizeof(readstring)); + s = (char*)cmdfuncs->ParsePunctuation(s, Q3SCRIPTPUNCTUATION, thetoken, sizeof(thetoken), &tokentype); + Q_strncatz(readstring, thetoken, sizeof(readstring)); } else break; } } sc->filestack[sc->stackdepth-1] = s; - if (com_tokentype == TTP_LINEENDING) + if (tokentype == TTP_LINEENDING) continue; //apparently we shouldn't stop on linebreaks if (!strcmp(readstring, "#include")) { - sc->filestack[sc->stackdepth-1] = (char *)COM_ParseToken(sc->filestack[sc->stackdepth-1], Q3SCRIPTPUNCTUATION); + sc->filestack[sc->stackdepth-1] = (char *)cmdfuncs->ParsePunctuation(sc->filestack[sc->stackdepth-1], Q3SCRIPTPUNCTUATION, thetoken, sizeof(thetoken), &tokentype); if (sc->stackdepth == SCRIPT_MAXDEPTH) //just don't enter it continue; if (sc->originalfilestack[sc->stackdepth]) - BZ_Free(sc->originalfilestack[sc->stackdepth]); - sc->filestack[sc->stackdepth] = sc->originalfilestack[sc->stackdepth] = FS_LoadMallocFile(com_token, NULL); - Q_strncpyz(sc->filename[sc->stackdepth], com_token, MAX_QPATH); + plugfuncs->Free(sc->originalfilestack[sc->stackdepth]); + sc->filestack[sc->stackdepth] = sc->originalfilestack[sc->stackdepth] = fsfuncs->LoadFile(thetoken, NULL); + Q_strncpyz(sc->filename[sc->stackdepth], thetoken, MAX_QPATH); sc->stackdepth++; continue; } if (!strcmp(readstring, "#define")) { sc->numdefines++; - sc->defines = BZ_Realloc(sc->defines, sc->numdefines*SCRIPT_DEFINELENGTH*2); - sc->filestack[sc->stackdepth-1] = (char *)COM_ParseToken(sc->filestack[sc->stackdepth-1], Q3SCRIPTPUNCTUATION); - Q_strncpyz(sc->defines+SCRIPT_DEFINELENGTH*2*(sc->numdefines-1), com_token, SCRIPT_DEFINELENGTH); - sc->filestack[sc->stackdepth-1] = (char *)COM_ParseToken(sc->filestack[sc->stackdepth-1], Q3SCRIPTPUNCTUATION); - Q_strncpyz(sc->defines+SCRIPT_DEFINELENGTH*2*(sc->numdefines-1)+SCRIPT_DEFINELENGTH, com_token, SCRIPT_DEFINELENGTH); + sc->defines = plugfuncs->Realloc(sc->defines, sc->numdefines*SCRIPT_DEFINELENGTH*2); + sc->filestack[sc->stackdepth-1] = (char *)cmdfuncs->ParsePunctuation(sc->filestack[sc->stackdepth-1], Q3SCRIPTPUNCTUATION, thetoken, sizeof(thetoken), &tokentype); + Q_strncpyz(sc->defines+SCRIPT_DEFINELENGTH*2*(sc->numdefines-1), thetoken, SCRIPT_DEFINELENGTH); + sc->filestack[sc->stackdepth-1] = (char *)cmdfuncs->ParsePunctuation(sc->filestack[sc->stackdepth-1], Q3SCRIPTPUNCTUATION, thetoken, sizeof(thetoken), &tokentype); + Q_strncpyz(sc->defines+SCRIPT_DEFINELENGTH*2*(sc->numdefines-1)+SCRIPT_DEFINELENGTH, thetoken, SCRIPT_DEFINELENGTH); continue; } - if (!*readstring && com_tokentype != TTP_STRING) + if (!*readstring && tokentype != TTP_STRING) { if (sc->stackdepth==0) { @@ -161,7 +168,7 @@ int Script_Read(int handle, struct pc_token_s *token) } break; } - if (com_tokentype == TTP_STRING) + if (tokentype == TTP_STRING) { i = sc->numdefines; } @@ -197,7 +204,7 @@ int Script_Read(int handle, struct pc_token_s *token) token->type = TT_NUMBER; token->subtype = 0; } - else if (com_tokentype == TTP_STRING) + else if (tokentype == TTP_STRING) { token->type = TT_STRING; token->subtype = strlen(token->string); @@ -218,7 +225,7 @@ int Script_Read(int handle, struct pc_token_s *token) } // Con_Printf("Found %s (%i, %i)\n", token->string, token->type, token->subtype); - return com_tokentype != TTP_EOF; + return tokentype != TTP_EOF; } int Script_LoadFile(char *filename) @@ -231,12 +238,12 @@ int Script_LoadFile(char *filename) if (i == maxscripts) { maxscripts++; - scripts = BZ_Realloc(scripts, sizeof(script_t)*maxscripts); + scripts = plugfuncs->Realloc(scripts, sizeof(script_t)*maxscripts); } sc = scripts+i; memset(sc, 0, sizeof(*sc)); - sc->filestack[0] = sc->originalfilestack[0] = FS_LoadMallocFile(filename, NULL); + sc->filestack[0] = sc->originalfilestack[0] = fsfuncs->LoadFile(filename, NULL); Q_strncpyz(sc->filename[sc->stackdepth], filename, MAX_QPATH); sc->stackdepth = 1; @@ -248,10 +255,10 @@ void Script_Free(int handle) int i; script_t *sc = scripts+handle-1; if (sc->defines) - BZ_Free(sc->defines); + plugfuncs->Free(sc->defines); for (i = 0; i < sc->stackdepth; i++) - BZ_Free(sc->originalfilestack[i]); + plugfuncs->Free(sc->originalfilestack[i]); sc->stackdepth = 0; } @@ -293,17 +300,12 @@ void Script_Get_File_And_Line(int handle, char *filename, int *line) -#ifdef GLQUAKE -#include "glquake.h"//hack -#else -typedef float m3by3_t[3][3]; -#endif static vm_t *uivm; #define MAX_PINGREQUESTS 32 -struct +static struct { unsigned int startms; netadr_t adr; @@ -313,15 +315,6 @@ struct #define UITAGNUM 2452 -extern model_t *mod_known; -extern int mod_numknown; -#define VM_FROMMHANDLE(a) (a>0&&a<=mod_numknown?mod_known+a-1:NULL) -#define VM_TOMHANDLE(a) (a?a-mod_known+1:0) - -#define VM_FROMSHANDLE(a) (a>0&&a<=r_numshaders?r_shaders[a-1]:NULL) -#define VM_TOSHANDLE(a) (a?a->id+1:0) - - struct q3refEntity_s { refEntityType_t reType; int renderfx; @@ -344,8 +337,8 @@ struct q3refEntity_s { // texturing int skinNum; // inline skin index - int customSkin; // NULL for default skin - int customShader; // use one image for the entire thing + skinid_t customSkin; // NULL for default skin + int customShader; // use one image for the entire thing // misc qbyte shaderRGBA[4]; // colors used by rgbgen entity shaders @@ -372,7 +365,7 @@ struct q3polyvert_s #define Q3RF_LIGHTING_ORIGIN 128 #define MAX_VMQ3_CACHED_STRINGS 2048 -char *stringcache[MAX_VMQ3_CACHED_STRINGS]; +static char *stringcache[MAX_VMQ3_CACHED_STRINGS]; void VMQ3_FlushStringHandles(void) { @@ -424,7 +417,7 @@ void VQ3_AddEntity(const q3refEntity_t *q3) { entity_t ent; memset(&ent, 0, sizeof(ent)); - ent.model = VM_FROMMHANDLE(q3->hModel); + ent.model = scenefuncs->ModelFromId(q3->hModel); ent.framestate.g[FS_REG].frame[0] = q3->frame; ent.framestate.g[FS_REG].frame[1] = q3->oldframe; memcpy(ent.axis, q3->axis, sizeof(q3->axis)); @@ -451,7 +444,7 @@ void VQ3_AddEntity(const q3refEntity_t *q3) // if (ent.shaderRGBAf[3] <= 0) // return; - ent.forcedshader = VM_FROMSHANDLE(q3->customShader); + ent.forcedshader = drawfuncs->ShaderFromId(q3->customShader); ent.shaderTime = q3->shaderTime; if (q3->renderfx & Q3RF_FIRST_PERSON) @@ -467,59 +460,45 @@ void VQ3_AddEntity(const q3refEntity_t *q3) ent.bottomcolour = BOTTOM_DEFAULT; ent.playerindex = -1; + + if ((q3->renderfx & Q3RF_LIGHTING_ORIGIN) && ent.model) + { + VectorCopy(q3->lightingOrigin, ent.origin); + scenefuncs->CalcModelLighting(&ent, ent.model); + } + VectorCopy(q3->origin, ent.origin); VectorCopy(q3->oldorigin, ent.oldorigin); - V_AddAxisEntity(&ent); + + scenefuncs->AddEntity(&ent); } -void VQ3_AddPoly(shader_t *s, int num, q3polyvert_t *verts) +void VQ3_AddPolys(shader_t *s, int numverts, q3polyvert_t *verts, size_t polycount) { unsigned int v; - scenetris_t *t; - /*reuse the previous trigroup if its the same shader*/ - if (cl_numstris && cl_stris[cl_numstris-1].shader == s && cl_stris[cl_numstris-1].flags == (BEF_NODLIGHT|BEF_NOSHADOWS)) - t = &cl_stris[cl_numstris-1]; - else + + for (; polycount-->0; verts += numverts) { - if (cl_numstris == cl_maxstris) + vecV_t *vertcoord; + vec2_t *texcoord; + vec4_t *colour; + index_t *indexes; + index_t indexbias = scenefuncs->AddPolydata(s, BEF_NODLIGHT|BEF_NOSHADOWS, numverts, (numverts-2)*3, &vertcoord, &texcoord, &colour, &indexes); + + //and splurge the data out. + for (v = 0; v < numverts; v++) { - cl_maxstris += 8; - cl_stris = BZ_Realloc(cl_stris, sizeof(*cl_stris)*cl_maxstris); + VectorCopy(verts[v].org, vertcoord[v]); + Vector2Copy(verts[v].tcoord, texcoord[v]); + Vector4Scale(verts[v].colours, (1/255.0f), colour[v]); + } + for (v = 2; v < numverts; v++) + { + *indexes++ = indexbias + 0; + *indexes++ = indexbias + (v-1); + *indexes++ = indexbias + v; } - t = &cl_stris[cl_numstris++]; - t->shader = s; - t->flags = BEF_NODLIGHT|BEF_NOSHADOWS; - t->numidx = 0; - t->numvert = 0; - t->firstidx = cl_numstrisidx; - t->firstvert = cl_numstrisvert; } - - if (cl_maxstrisvert < cl_numstrisvert+num) - cl_stris_ExpandVerts(cl_numstrisvert+num + 64); - if (cl_maxstrisidx < cl_numstrisidx+(num-2)*3) - { - cl_maxstrisidx = cl_numstrisidx+(num-2)*3 + 64; - cl_strisidx = BZ_Realloc(cl_strisidx, sizeof(*cl_strisidx)*cl_maxstrisidx); - } - - for (v = 0; v < num; v++) - { - VectorCopy(verts[v].org, cl_strisvertv[cl_numstrisvert+v]); - Vector2Copy(verts[v].tcoord, cl_strisvertt[cl_numstrisvert+v]); - Vector4Scale(verts[v].colours, (1/255.0f), cl_strisvertc[cl_numstrisvert+v]); - } - for (v = 2; v < num; v++) - { - cl_strisidx[cl_numstrisidx++] = cl_numstrisvert - t->firstvert; - cl_strisidx[cl_numstrisidx++] = cl_numstrisvert+(v-1) - t->firstvert; - cl_strisidx[cl_numstrisidx++] = cl_numstrisvert+v - t->firstvert; - } - - t->numvert += num; - t->numidx += (num-2)*3; - cl_numstrisvert += num; - //we already increased idx } int VM_LerpTag(void *out, model_t *model, int f1, int f2, float l2, char *tagname) @@ -541,8 +520,8 @@ int VM_LerpTag(void *out, model_t *model, int f1, int f2, float l2, char *tagnam fstate.g[FS_REG].lerpweight[0] = 1 - l2; fstate.g[FS_REG].lerpweight[1] = l2; - tagnum = Mod_TagNumForName(model, tagname); - found = Mod_GetTag(model, tagnum, &fstate, tr); + tagnum = scenefuncs->TagNumForName(model, tagname, 0); + found = scenefuncs->GetTag(model, tagnum, &fstate, tr); if (found && tagnum) { @@ -605,78 +584,42 @@ struct q3refdef_s { // text messages for deform text shaders char text[MAX_RENDER_STRINGS][MAX_RENDER_STRING_LENGTH]; }; -void R_DrawNameTags(void); + void VQ3_RenderView(const q3refdef_t *ref) { - int i; - extern cvar_t r_torch; + plugrefdef_t scene; - if (R2D_Flush) - R2D_Flush(); + scene.flags = 0; - VectorCopy(ref->vieworg, r_refdef.vieworg); - r_refdef.viewangles[0] = -(atan2(ref->viewaxis[0][2], sqrt(ref->viewaxis[0][1]*ref->viewaxis[0][1]+ref->viewaxis[0][0]*ref->viewaxis[0][0])) * 180 / M_PI); - r_refdef.viewangles[1] = (atan2(ref->viewaxis[0][1], ref->viewaxis[0][0]) * 180 / M_PI); - r_refdef.viewangles[2] = 0; - VectorCopy(ref->viewaxis[0], r_refdef.viewaxis[0]); - VectorCopy(ref->viewaxis[1], r_refdef.viewaxis[1]); - VectorCopy(ref->viewaxis[2], r_refdef.viewaxis[2]); - if (ref->rdflags & 1) - r_refdef.flags |= RDF_NOWORLDMODEL; - else - r_refdef.flags &= ~RDF_NOWORLDMODEL; - r_refdef.fovv_x = r_refdef.fov_x = ref->fov_x; - r_refdef.fovv_y = r_refdef.fov_y = ref->fov_y; - r_refdef.vrect.x = ref->x; - r_refdef.vrect.y = ref->y; - r_refdef.vrect.width = ref->width; - r_refdef.vrect.height = ref->height; - r_refdef.time = ref->time/1000.0f; - r_refdef.useperspective = true; - r_refdef.mindist = bound(0.1, gl_mindist.value, 4); - r_refdef.maxdist = gl_maxdist.value; - r_refdef.playerview = &cl.playerview[0]; - if (ref->y < 0) - { //evil hack to work around player model ui bug. - //if the y coord is off screen, reduce the height to keep things centred, and reduce the fov to compensate. - r_refdef.vrect.height += ref->y*2; - r_refdef.fovv_y = r_refdef.fov_y = ref->fov_y * r_refdef.vrect.height / ref->height; - r_refdef.vrect.y = 0; - } + scene.rect.x = ref->x; + scene.rect.y = ref->y; + scene.rect.w = ref->width; + scene.rect.h = ref->height; + scene.fov[0] = scene.fov_viewmodel[0] = ref->fov_x; + scene.fov[1] = scene.fov_viewmodel[1] = ref->fov_y; + VectorCopy(ref->viewaxis[0], scene.viewaxisorg[0]); + VectorCopy(ref->viewaxis[1], scene.viewaxisorg[1]); + VectorCopy(ref->viewaxis[2], scene.viewaxisorg[2]); + VectorCopy(ref->vieworg, scene.viewaxisorg[3]); + scene.time = ref->time/1000.0f; - memset(&r_refdef.globalfog, 0, sizeof(r_refdef.globalfog)); + if (ref->rdflags & 1/*RDF_NOWORLDMODEL*/) + scene.flags |= RDF_NOWORLDMODEL; - if (r_torch.ival) - { - dlight_t *dl; - dl = CL_NewDlight(0, ref->vieworg, 300, r_torch.ival, 0.5, 0.5, 0.2); - dl->flags |= LFLAG_SHADOWMAP|LFLAG_FLASHBLEND; - dl->fov = 60; - VectorCopy(ref->viewaxis[0], dl->axis[0]); - VectorCopy(ref->viewaxis[1], dl->axis[1]); - VectorCopy(ref->viewaxis[2], dl->axis[2]); - } - - r_refdef.areabitsknown = true; - for (i = 0; i < MAX_MAP_AREA_BYTES/sizeof(int); i++) - ((int*)r_refdef.areabits)[i] = ((int*)ref->areamask)[i] ^ ~0; - R_RenderView(); - R_DrawNameTags(); - r_refdef.playerview = NULL; -#ifdef GLQUAKE - if (qrenderer == QR_OPENGL) - { -// GL_Set2D (false); - } -#endif - - r_refdef.time = 0; + scenefuncs->RenderScene(&scene, sizeof(ref->areamask), ref->areamask); } - - - +static void *Little4Block(void *out, qbyte *in, size_t count) +{ + while (count-->0) + { + *(unsigned int*)out = (in[0]<<0)|(in[1]<<8)|(in[2]<<16)|(in[3]<<24); + out = (qbyte*)out + 4; + in+=4; + } + return in; +} void UI_RegisterFont(char *fontName, int pointSize, fontInfo_t *font) { union @@ -687,44 +630,29 @@ void UI_RegisterFont(char *fontName, int pointSize, fontInfo_t *font) } in; int i; char name[MAX_QPATH]; + void *filedata; size_t sz; - shader_t *shader; - #define readInt() LittleLong(*in.i++) - #define readFloat() LittleFloat(*in.f++) snprintf(name, sizeof(name), "fonts/fontImage_%i.dat",pointSize); - in.c = COM_LoadTempFile(name, 0, &sz); + in.c = filedata = fsfuncs->LoadFile(name, &sz); if (sz == sizeof(fontInfo_t)) { for(i=0; iglyphs[i].height = readInt(); - font->glyphs[i].top = readInt(); - font->glyphs[i].bottom = readInt(); - font->glyphs[i].pitch = readInt(); - font->glyphs[i].xSkip = readInt(); - font->glyphs[i].imageWidth = readInt(); - font->glyphs[i].imageHeight = readInt(); - font->glyphs[i].s = readFloat(); - font->glyphs[i].t = readFloat(); - font->glyphs[i].s2 = readFloat(); - font->glyphs[i].t2 = readFloat(); - font->glyphs[i].glyph = readInt(); + in.c = Little4Block(&font->glyphs[i].height, in.c, (int*)font->glyphs[i].shaderName-&font->glyphs[i].height); memcpy(font->glyphs[i].shaderName, in.i, 32); in.c += 32; } - font->glyphScale = readFloat(); + in.c = Little4Block(&font->glyphScale, in.c, 1); memcpy(font->name, in.i, sizeof(font->name)); // Com_Memcpy(font, faceData, sizeof(fontInfo_t)); Q_strncpyz(font->name, name, sizeof(font->name)); for (i = GLYPH_START; i < GLYPH_END; i++) - { - shader = R_RegisterPic(font->glyphs[i].shaderName, NULL); - font->glyphs[i].glyph = VM_TOSHANDLE(shader); - } + font->glyphs[i].glyph = drawfuncs->LoadImage(font->glyphs[i].shaderName); } + plugfuncs->Free(filedata); } static struct @@ -736,8 +664,8 @@ static struct int UI_Cin_Play(const char *name, int x, int y, int w, int h, unsigned int flags) { int idx; - shader_t *mediashader; - cin_t *cin; + qhandle_t mediashader; + //cin_t *cin; for (idx = 0; ; idx++) { if (idx == countof(uicinematics)) @@ -747,13 +675,13 @@ int UI_Cin_Play(const char *name, int x, int y, int w, int h, unsigned int flags break; //this slot is usable } - mediashader = R_RegisterCustom(NULL, name, SUF_NONE, Shader_DefaultCinematic, va("video/%s", name)); + /*mediashader = R_RegisterCustom(name, SUF_NONE, Shader_DefaultCinematic, va("video/%s", name)); if (!mediashader) return -1; //wtf? cin = R_ShaderGetCinematic(mediashader); if (cin) Media_SetState(cin, CINSTATE_PLAY); - else + else*/ return -1; //FAIL! uicinematics[idx].x = x; @@ -761,7 +689,7 @@ int UI_Cin_Play(const char *name, int x, int y, int w, int h, unsigned int flags uicinematics[idx].w = w; uicinematics[idx].h = h; uicinematics[idx].loop = !!(flags&1); - uicinematics[idx].shaderhandle = VM_TOSHANDLE(mediashader); + uicinematics[idx].shaderhandle = mediashader; return idx; } @@ -769,8 +697,7 @@ int UI_Cin_Stop(int idx) { if (idx >= 0 && idx < countof(uicinematics)) { - shader_t *shader = VM_FROMSHANDLE(uicinematics[idx].shaderhandle); - R_UnloadShader(shader); + drawfuncs->UnloadImage(uicinematics[idx].shaderhandle); uicinematics[idx].shaderhandle = 0; } return 0; @@ -791,7 +718,7 @@ int UI_Cin_Run(int idx) if (idx >= 0 && idx < countof(uicinematics)) { - shader_t *shader = VM_FROMSHANDLE(uicinematics[idx].shaderhandle); + shader_t *shader = drawfuncs->ShaderFromId(uicinematics[idx].shaderhandle); cin_t *cin = R_ShaderGetCinematic(shader); if (cin) { @@ -819,19 +746,22 @@ int UI_Cin_Draw(int idx) { if (idx >= 0 && idx < countof(uicinematics)) { - shader_t *shader = VM_FROMSHANDLE(uicinematics[idx].shaderhandle); + unsigned int size[2]; + qhandle_t shader = uicinematics[idx].shaderhandle; float x = uicinematics[idx].x; float y = uicinematics[idx].y; float w = uicinematics[idx].w; float h = uicinematics[idx].h; - //gah! q3 compat sucks! - x *= vid.pixelwidth/640.0; - w *= vid.pixelwidth/640.0; - y *= vid.pixelheight/480.0; - h *= vid.pixelheight/480.0; + drawfuncs->GetVideoSize(NULL, size); - R2D_Image(x, y, w, h, 0, 0, 1, 1, shader); + //gah! q3 compat sucks! + x *= size[0]/640.0; + w *= size[0]/640.0; + y *= size[1]/480.0; + h *= size[1]/480.0; + + drawfuncs->Image(x, y, w, h, 0, 0, 1, 1, shader); } return 0; } @@ -847,7 +777,7 @@ int UI_Cin_SetExtents(int idx, int x, int y, int w, int h) return 0; } -static cvar_t *Cvar_Q3FindVar (const char *var_name) +static const char *Cvar_FixQ3Name (const char *var_name) { struct { const char *q3; @@ -864,6 +794,7 @@ static cvar_t *Cvar_Q3FindVar (const char *var_name) {"r_colorbits", "vid_bpp"}, {"r_dynamiclight", "r_dynamic"}, {"r_finish", "gl_finish"}, + {"protocol", "com_protocolversion"}, // {"r_glDriver", NULL}, // {"r_depthbits", NULL}, // {"r_stencilbits", NULL}, @@ -881,18 +812,13 @@ static cvar_t *Cvar_Q3FindVar (const char *var_name) // {"r_availableModes",NULL}, // {"r_mode", NULL}, }; - cvar_t *v; size_t i; - v = Cvar_FindVar(var_name); - if (v) - return v; for (i = 0; i < countof(cvarremaps); i++) { if (!strcmp(cvarremaps[i].q3, var_name)) - return Cvar_FindVar(cvarremaps[i].fte); + return cvarremaps[i].fte; } -// Con_Printf("Q3 Cvar %s is not known\n", var_name); - return NULL; + return var_name; } static void UI_SimulateTextEntry(void *cb, const char *utf8) @@ -904,11 +830,11 @@ static void UI_SimulateTextEntry(void *cb, const char *utf8) { unicode = utf8_decode(&err, line, &line); if (uivm) - VM_Call(uivm, UI_KEY_EVENT, unicode|1024, true); + vmfuncs->Call(uivm, UI_KEY_EVENT, unicode|1024, true); } } -#define VALIDATEPOINTER(o,l) if ((quintptr_t)o + l >= mask || VM_POINTER(o) < offset) Host_EndGame("Call to ui trap %i passes invalid pointer\n", (int)fn); //out of bounds. +#define VALIDATEPOINTER(o,l) if ((quintptr_t)o + l >= mask || VM_POINTER(o) < offset) plugfuncs->EndGame("Call to ui trap %i passes invalid pointer\n", (int)fn); //out of bounds. static qintptr_t UI_SystemCalls(void *offset, quintptr_t mask, qintptr_t fn, const qintptr_t *arg) { @@ -927,32 +853,31 @@ static qintptr_t UI_SystemCalls(void *offset, quintptr_t mask, qintptr_t fn, con switch((uiImport_t)fn) { - case UI_CVAR_CREATE: - case UI_CVAR_INFOSTRINGBUFFER: - case UI_R_ADDPOLYTOSCENE: - case UI_R_REMAP_SHADER: - case UI_UPDATESCREEN: - case UI_CM_LOADMODEL: - case UI_FS_SEEK: - Con_Printf("Q3UI: Not implemented system trap: %i\n", (int)fn); - break; + case UI_CVAR_CREATE: Con_Printf("Q3UI: Not implemented system trap: %s\n", "UI_CVAR_CREATE"); return 0; + case UI_CVAR_INFOSTRINGBUFFER: Con_Printf("Q3UI: Not implemented system trap: %s\n", "UI_CVAR_INFOSTRINGBUFFER"); return 0; + case UI_R_ADDPOLYTOSCENE: Con_Printf("Q3UI: Not implemented system trap: %s\n", "UI_R_ADDPOLYTOSCENE"); return 0; + case UI_R_REMAP_SHADER: Con_Printf("Q3UI: Not implemented system trap: %s\n", "UI_R_REMAP_SHADER"); return 0; + case UI_UPDATESCREEN: Con_Printf("Q3UI: Not implemented system trap: %s\n", "UI_UPDATESCREEN"); return 0; + case UI_CM_LOADMODEL: Con_Printf("Q3UI: Not implemented system trap: %s\n", "UI_CM_LOADMODEL"); return 0; case UI_ERROR: Con_Printf("%s", (char*)VM_POINTER(arg[0])); + UI_Stop(); + plugfuncs->EndGame("UI error"); break; case UI_PRINT: Con_Printf("%s", (char*)VM_POINTER(arg[0])); break; case UI_MILLISECONDS: - VM_LONG(ret) = Sys_Milliseconds(); + VM_LONG(ret) = plugfuncs->GetMilliseconds(); break; case UI_ARGC: - VM_LONG(ret) = Cmd_Argc(); + VM_LONG(ret) = cmdfuncs->Argc(); break; case UI_ARGV: // VALIDATEPOINTER(arg[1], arg[2]); - Q_strncpyz(VM_POINTER(arg[1]), Cmd_Argv(VM_LONG(arg[0])), VM_LONG(arg[2])); + cmdfuncs->Argv(VM_LONG(arg[0]), VM_POINTER(arg[1]), VM_LONG(arg[2])); break; /* case UI_ARGS: VALIDATEPOINTER(arg[0], arg[1]); @@ -961,70 +886,23 @@ static qintptr_t UI_SystemCalls(void *offset, quintptr_t mask, qintptr_t fn, con */ case UI_CVAR_SET: - { - cvar_t *var; - char *vname = VM_POINTER(arg[0]); - char *vval = VM_POINTER(arg[1]); - if (!strcmp(vname, "fs_game")) - { - char quoted[256]; - Cbuf_AddText(va("gamedir %s\nui_restart\n", COM_QuotedString(vval, quoted, sizeof(quoted), false)), RESTRICT_SERVER); - } - else - { - var = Cvar_Q3FindVar(vname); - if (var) - Cvar_Set(var, vval); //set it - else - Cvar_Get(vname, vval, 0, "UI created"); //create one - } - } + cvarfuncs->SetString(Cvar_FixQ3Name(VM_POINTER(arg[0])), VM_POINTER(arg[1])); break; case UI_CVAR_VARIABLEVALUE: - { - cvar_t *var; - char *vname = VM_POINTER(arg[0]); - var = Cvar_Q3FindVar(vname); - if (var) - VM_FLOAT(ret) = var->value; - else - VM_FLOAT(ret) = 0; - } + VM_FLOAT(ret) = cvarfuncs->GetFloat(Cvar_FixQ3Name(VM_POINTER(arg[0]))); break; case UI_CVAR_VARIABLESTRINGBUFFER: - { - cvar_t *var; - char *vname = VM_POINTER(arg[0]); - var = Cvar_Q3FindVar(vname); - if (!VM_LONG(arg[2])) - VM_LONG(ret) = 0; - else if (!var) - { - *(char *)VM_POINTER(arg[1]) = '\0'; - VM_LONG(ret) = -1; - } - else - { - if (arg[1] + arg[2] >= mask || VM_POINTER(arg[1]) < offset) - VM_LONG(ret) = -2; //out of bounds. - else - Q_strncpyz(VM_POINTER(arg[1]), var->string, VM_LONG(arg[2])); - } - } + if (arg[1] + arg[2] >= mask || VM_POINTER(arg[1]) < offset) + VM_LONG(ret) = -2; //out of bounds. + cvarfuncs->GetString(Cvar_FixQ3Name(VM_POINTER(arg[0])), VM_POINTER(arg[1]), VM_LONG(arg[2])); break; case UI_CVAR_SETVALUE: - Cvar_SetValue(Cvar_Q3FindVar(VM_POINTER(arg[0])), VM_FLOAT(arg[1])); + cvarfuncs->SetFloat(Cvar_FixQ3Name(VM_POINTER(arg[0])), VM_FLOAT(arg[1])); break; case UI_CVAR_RESET: //cvar reset - { - cvar_t *var; - char *vname = VM_POINTER(arg[0]); - var = Cvar_Q3FindVar(vname); - if (var) - Cvar_Set(var, var->defaultstr); - } + cvarfuncs->SetString(Cvar_FixQ3Name(VM_POINTER(arg[0])), NULL); break; case UI_CMD_EXECUTETEXT: @@ -1033,23 +911,24 @@ static qintptr_t UI_SystemCalls(void *offset, quintptr_t mask, qintptr_t fn, con #ifdef CL_MASTER if (!strncmp(cmdtext, "ping ", 5)) { + char token[1024]; int i; for (i = 0; i < MAX_PINGREQUESTS; i++) if (ui_pings[i].adr.type == NA_INVALID && ui_pings[i].adr.prot == NP_INVALID) { const char *p = NULL; - COM_Parse(cmdtext + 5); - ui_pings[i].startms = Sys_Milliseconds(); - Q_strncpyz(ui_pings[i].adrstring, com_token, sizeof(ui_pings[i].adrstring)); - if (NET_StringToAdr2(ui_pings[i].adrstring, 0, &ui_pings[i].adr, 1, &p)) + cmdfuncs->ParseToken(cmdtext + 5, token, sizeof(token), NULL); + ui_pings[i].startms = plugfuncs->GetMilliseconds(); + Q_strncpyz(ui_pings[i].adrstring, token, sizeof(ui_pings[i].adrstring)); + if (masterfuncs->StringToAdr(ui_pings[i].adrstring, 0, &ui_pings[i].adr, 1, &p)) { #ifdef HAVE_PACKET - serverinfo_t *info = Master_InfoForServer(&ui_pings[i].adr, p); + serverinfo_t *info = masterfuncs->InfoForServer(&ui_pings[i].adr, p); if (info) { info->special |= SS_KEEPINFO; info->sends++; - Master_QueryServer(info); + masterfuncs->QueryServer(info); } #endif } @@ -1059,7 +938,7 @@ static qintptr_t UI_SystemCalls(void *offset, quintptr_t mask, qintptr_t fn, con } else #endif - Cbuf_AddText(cmdtext, RESTRICT_SERVER); + cmdfuncs->AddText(cmdtext, false); } break; @@ -1077,6 +956,8 @@ static qintptr_t UI_SystemCalls(void *offset, quintptr_t mask, qintptr_t fn, con break; case UI_FS_WRITE: //fwrite break; + case UI_FS_SEEK: + return VM_FSeek(arg[0], arg[1], arg[2], 0); case UI_FS_FCLOSEFILE: //fclose VM_fclose(VM_LONG(arg[0]), 0); break; @@ -1089,14 +970,11 @@ static qintptr_t UI_SystemCalls(void *offset, quintptr_t mask, qintptr_t fn, con case UI_R_REGISTERMODEL: //precache model { char *name = VM_POINTER(arg[0]); - model_t *mod; - mod = Mod_ForName(name, MLV_SILENT); - if (mod && mod->loadstate == MLS_LOADING) - COM_WorkerPartialSync(mod, &mod->loadstate, MLS_LOADING); + model_t *mod = scenefuncs->LoadModel(name, MLV_SILENTSYNC); if (!mod || mod->loadstate != MLS_LOADED || mod->type == mod_dummy) VM_LONG(ret) = 0; else - VM_LONG(ret) = VM_TOMHANDLE(mod); + VM_LONG(ret) = scenefuncs->ModelToId(mod); } break; case UI_R_MODELBOUNDS: @@ -1104,7 +982,7 @@ static qintptr_t UI_SystemCalls(void *offset, quintptr_t mask, qintptr_t fn, con VALIDATEPOINTER(arg[1], sizeof(vec3_t)); VALIDATEPOINTER(arg[2], sizeof(vec3_t)); { - model_t *mod = VM_FROMMHANDLE(arg[0]); + model_t *mod = scenefuncs->ModelFromId(arg[0]); if (mod) { VectorCopy(mod->mins, ((float*)VM_POINTER(arg[1]))); @@ -1120,7 +998,7 @@ static qintptr_t UI_SystemCalls(void *offset, quintptr_t mask, qintptr_t fn, con break; case UI_R_REGISTERSKIN: - VM_LONG(ret) = Mod_RegisterSkinFile(VM_POINTER(arg[0])); + VM_LONG(ret) = scenefuncs->RegisterSkinFile(VM_POINTER(arg[0])); break; case UI_R_REGISTERFONT: //register font @@ -1130,14 +1008,13 @@ static qintptr_t UI_SystemCalls(void *offset, quintptr_t mask, qintptr_t fn, con if (!*(char*)VM_POINTER(arg[0])) VM_LONG(ret) = 0; else - { - shader_t *shader = R_RegisterPic(VM_POINTER(arg[0]), NULL); - VM_LONG(ret) = VM_TOSHANDLE(shader); - } + VM_LONG(ret) = drawfuncs->LoadImage(VM_POINTER(arg[0])); + if (!drawfuncs->ImageSize(VM_LONG(ret), NULL, NULL)) + VM_LONG(ret) = 0; //not found... break; case UI_R_CLEARSCENE: //clear scene - CL_ClearEntityLists(); + scenefuncs->ClearScene(); break; case UI_R_ADDREFENTITYTOSCENE: //add ent to scene VQ3_AddEntity(VM_POINTER(arg[0])); @@ -1152,27 +1029,25 @@ static qintptr_t UI_SystemCalls(void *offset, quintptr_t mask, qintptr_t fn, con { float *fl =VM_POINTER(arg[0]); if (!fl) - R2D_ImageColours(1, 1, 1, 1); + drawfuncs->Colour4f(1, 1, 1, 1); else - R2D_ImageColours(fl[0], fl[1], fl[2], fl[3]); + drawfuncs->Colour4f(fl[0], fl[1], fl[2], fl[3]); } break; case UI_R_DRAWSTRETCHPIC: - R2D_Image(VM_FLOAT(arg[0]), VM_FLOAT(arg[1]), VM_FLOAT(arg[2]), VM_FLOAT(arg[3]), VM_FLOAT(arg[4]), VM_FLOAT(arg[5]), VM_FLOAT(arg[6]), VM_FLOAT(arg[7]), VM_FROMSHANDLE(VM_LONG(arg[8]))); + drawfuncs->Image(VM_FLOAT(arg[0]), VM_FLOAT(arg[1]), VM_FLOAT(arg[2]), VM_FLOAT(arg[3]), VM_FLOAT(arg[4]), VM_FLOAT(arg[5]), VM_FLOAT(arg[6]), VM_FLOAT(arg[7]), VM_LONG(arg[8])); break; case UI_CM_LERPTAG: //Lerp tag... - // tag, model, startFrame, endFrame, frac, tagName - if ((int)arg[0] + sizeof(float)*12 >= mask || VM_POINTER(arg[0]) < offset) - break; //out of bounds. - VM_LerpTag(VM_POINTER(arg[0]), VM_FROMMHANDLE(arg[1]), VM_LONG(arg[2]), VM_LONG(arg[3]), VM_FLOAT(arg[4]), VM_POINTER(arg[5])); + VALIDATEPOINTER(arg[0], sizeof(float)*12); + VM_LONG(ret) = VM_LerpTag(VM_POINTER(arg[0]), scenefuncs->ModelFromId(arg[1]), VM_LONG(arg[2]), VM_LONG(arg[3]), VM_FLOAT(arg[4]), VM_POINTER(arg[5])); break; case UI_S_REGISTERSOUND: { sfx_t *sfx; - sfx = S_PrecacheSound(va("%s", (char*)VM_POINTER(arg[0]))); + sfx = audiofuncs->PrecacheSound(va("%s", (char*)VM_POINTER(arg[0]))); if (sfx) VM_LONG(ret) = VM_TOSTRCACHE(arg[0]); //return handle is the parameter they just gave else @@ -1181,14 +1056,14 @@ static qintptr_t UI_SystemCalls(void *offset, quintptr_t mask, qintptr_t fn, con break; case UI_S_STARTLOCALSOUND: if (VM_LONG(arg[0]) != -1 && arg[0]) - S_LocalSound(VM_FROMSTRCACHE(arg[0])); //now we can fix up the sound name + audiofuncs->LocalSound(VM_FROMSTRCACHE(arg[0]), CHAN_AUTO, 1.0); //now we can fix up the sound name break; case UI_S_STARTBACKGROUNDTRACK: - Media_NamedTrack(VM_POINTER(arg[0]), VM_POINTER(arg[1])); + audiofuncs->ChangeMusicTrack(VM_POINTER(arg[0]), VM_POINTER(arg[1])); break; case UI_S_STOPBACKGROUNDTRACK: - Media_NamedTrack(NULL, NULL); + audiofuncs->ChangeMusicTrack(NULL, NULL); break; //q3 shares insert mode between its ui and console. whereas fte doesn't support it (FIXME: add to Key_EntryInsert). @@ -1211,38 +1086,35 @@ static qintptr_t UI_SystemCalls(void *offset, quintptr_t mask, qintptr_t fn, con break; case UI_KEY_KEYNUMTOSTRINGBUF: - if (VM_LONG(arg[0]) < 0 || VM_LONG(arg[0]) > 255 || (int)arg[1] + VM_LONG(arg[2]) >= mask || VM_POINTER(arg[1]) < offset || VM_LONG(arg[2]) < 1) + if (VM_LONG(arg[0]) < 0 || VM_LONG(arg[0]) >= K_MAX || (int)arg[1] + VM_LONG(arg[2]) >= mask || VM_POINTER(arg[1]) < offset || VM_LONG(arg[2]) < 1) break; //out of bounds. - Q_strncpyz(VM_POINTER(arg[1]), Key_KeynumToString(VM_LONG(arg[0]), 0), VM_LONG(arg[2])); + Q_strncpyz(VM_POINTER(arg[1]), inputfuncs->GetKeyName(VM_LONG(arg[0]), 0), VM_LONG(arg[2])); break; case UI_KEY_GETBINDINGBUF: - if (VM_LONG(arg[0]) < 0 || VM_LONG(arg[0]) > 255 || (int)arg[1] + VM_LONG(arg[2]) >= mask || VM_POINTER(arg[1]) < offset || VM_LONG(arg[2]) < 1) + if (VM_LONG(arg[0]) < 0 || VM_LONG(arg[0]) >= K_MAX || (int)arg[1] + VM_LONG(arg[2]) >= mask || VM_POINTER(arg[1]) < offset || VM_LONG(arg[2]) < 1) break; //out of bounds. - if (keybindings[VM_LONG(arg[0])][0]) - Q_strncpyz(VM_POINTER(arg[1]), keybindings[VM_LONG(arg[0])][0], VM_LONG(arg[2])); - else - *(char *)VM_POINTER(arg[1]) = '\0'; - break; - - case UI_KEY_SETBINDING: - Key_SetBinding(VM_LONG(arg[0]), ~0, VM_POINTER(arg[1]), RESTRICT_LOCAL); - break; - - case UI_KEY_ISDOWN: { - unsigned int k = VM_LONG(arg[0]); - if (k < K_MAX && keydown[k]) - VM_LONG(ret) = 1; + const char *binding = inputfuncs->GetKeyBind(0, VM_LONG(arg[0]), 0); + if (binding) + Q_strncpyz(VM_POINTER(arg[1]), binding, VM_LONG(arg[2])); else - VM_LONG(ret) = 0; + *(char *)VM_POINTER(arg[1]) = '\0'; } break; + case UI_KEY_SETBINDING: + inputfuncs->SetKeyBind(0, VM_LONG(arg[0]), 0, VM_POINTER(arg[1])); + break; + + case UI_KEY_ISDOWN: + VM_LONG(ret) = inputfuncs->IsKeyDown(VM_LONG(arg[0])); + break; + case UI_KEY_CLEARSTATES: - Key_ClearStates(); + inputfuncs->ClearKeyStates(); break; case UI_KEY_GETCATCHER: if (Key_Dest_Has(kdm_console)) @@ -1256,18 +1128,45 @@ static qintptr_t UI_SystemCalls(void *offset, quintptr_t mask, qintptr_t fn, con case UI_GETGLCONFIG: //get glconfig { + q3glconfig_t *cfg; + float vsize[2] = {0,0}; + if ((int)arg[0] + sizeof(q3glconfig_t) >= mask || VM_POINTER(arg[0]) < offset) + break; //out of bounds. + drawfuncs->GetVideoSize(vsize, NULL); + cfg = VM_POINTER(arg[0]); + + //do any needed work + memset(cfg, 0, sizeof(*cfg)); + + Q_strncpyz(cfg->renderer_string, "", sizeof(cfg->renderer_string)); + Q_strncpyz(cfg->vendor_string, "", sizeof(cfg->vendor_string)); + Q_strncpyz(cfg->version_string, "", sizeof(cfg->version_string)); + Q_strncpyz(cfg->extensions_string, "", sizeof(cfg->extensions_string)); + + cfg->colorBits = 32; + cfg->depthBits = 24; + cfg->stencilBits = 8;//sh_config.stencilbits; + cfg->textureCompression = true;//!!sh_config.texfmt[PTI_BC1_RGBA]; + cfg->textureEnvAddAvailable = true;//sh_config.env_add; + + //these are the only three that really matter. + cfg->vidWidth = vsize[0]; + cfg->vidHeight = vsize[1]; + cfg->windowAspect = vsize[0]/vsize[1];; +#if 0 char *cfg; if ((int)arg[0] + 11332/*sizeof(glconfig_t)*/ >= mask || VM_POINTER(arg[0]) < offset) break; //out of bounds. cfg = VM_POINTER(arg[0]); - //do any needed work - memset(cfg, 0, 11304); - *(int *)(cfg+11304) = vid.width; - *(int *)(cfg+11308) = vid.height; - *(float *)(cfg+11312) = (float)vid.width/vid.height; - memset(cfg+11316, 0, 11332-11316); + //do any needed work + memset(cfg, 0, 11304); + *(int *)(cfg+11304) = vsize[0]; + *(int *)(cfg+11308) = vid.height; + *(float *)(cfg+11312) = (float)vsize[0]/vid.height; + memset(cfg+11316, 0, 11332-11316); +#endif } break; @@ -1276,11 +1175,10 @@ static qintptr_t UI_SystemCalls(void *offset, quintptr_t mask, qintptr_t fn, con // Con_Printf("ui_getclientstate\n"); VALIDATEPOINTER(arg[0], sizeof(uiClientState_t)); { - extern cvar_t cl_disconnectreason; uiClientState_t *state = VM_POINTER(arg[0]); state->connectPacketCount = 0;//clc.connectPacketCount; - switch(cls.state) + switch(ccs.state) { case ca_disconnected: if (CL_TryingToConnect()) @@ -1301,10 +1199,10 @@ static qintptr_t UI_SystemCalls(void *offset, quintptr_t mask, qintptr_t fn, con state->connState = Q3CA_ACTIVE; break; } - Q_strncpyz( state->servername, cls.servername, sizeof( state->servername ) ); - Q_strncpyz( state->updateInfoString, "FTE!", sizeof( state->updateInfoString ) ); //warning/motd message from update server - Q_strncpyz( state->messageString, cl_disconnectreason.string, sizeof( state->messageString ) ); //error message from game server - state->clientNum = cl.playerview[0].playernum; + cvarfuncs->GetString("cl_servername", state->servername, sizeof(state->servername)); //error message from game server + Q_strncpyz(state->updateInfoString, "FTE!", sizeof(state->updateInfoString)); //warning/motd message from update server + cvarfuncs->GetString("com_errorMessage", state->messageString, sizeof(state->messageString)); //error message from game server + state->clientNum = ccs.playernum; } break; @@ -1340,7 +1238,7 @@ static qintptr_t UI_SystemCalls(void *offset, quintptr_t mask, qintptr_t fn, con if ((int)arg[3] + sizeof(int) >= mask || VM_POINTER(arg[3]) < offset) break; //out of bounds. - Master_CheckPollSockets(); + masterfuncs->CheckPollSockets(); if (VM_LONG(arg[0])>= 0 && VM_LONG(arg[0]) < MAX_PINGREQUESTS) { int i = VM_LONG(arg[0]); @@ -1349,7 +1247,7 @@ static qintptr_t UI_SystemCalls(void *offset, quintptr_t mask, qintptr_t fn, con int *ping = VM_POINTER(arg[3]); serverinfo_t *info; if (ui_pings[i].adr.type != NA_INVALID || ui_pings[i].adr.prot != NP_INVALID) - info = Master_InfoForServer(&ui_pings[i].adr, ui_pings[i].broker); + info = masterfuncs->InfoForServer(&ui_pings[i].adr, ui_pings[i].broker); else info = NULL; Q_strncpyz(buf, ui_pings[i].adrstring, bufsize); @@ -1360,7 +1258,7 @@ static qintptr_t UI_SystemCalls(void *offset, quintptr_t mask, qintptr_t fn, con *ping = (info->ping == PING_UNKNOWN)?1:info->ping; break; } - i = Sys_Milliseconds()-ui_pings[i].startms; + i = plugfuncs->GetMilliseconds()-ui_pings[i].startms; if (i < 999) i = 0; //don't time out yet. *ping = i; @@ -1373,14 +1271,14 @@ static qintptr_t UI_SystemCalls(void *offset, quintptr_t mask, qintptr_t fn, con if ((int)arg[3] + sizeof(int) >= mask || VM_POINTER(arg[3]) < offset) break; //out of bounds. - Master_CheckPollSockets(); + masterfuncs->CheckPollSockets(); if (VM_LONG(arg[0])>= 0 && VM_LONG(arg[0]) < MAX_PINGREQUESTS) { int i = VM_LONG(arg[0]); char *buf = VM_POINTER(arg[1]); size_t bufsize = VM_LONG(arg[2]); char *adr; - serverinfo_t *info = Master_InfoForServer(&ui_pings[i].adr, ui_pings[i].broker); + serverinfo_t *info = masterfuncs->InfoForServer(&ui_pings[i].adr, ui_pings[i].broker); if (info && /*(info->status & SRVSTATUS_ALIVE) &&*/ info->moreinfo) { @@ -1390,17 +1288,17 @@ static qintptr_t UI_SystemCalls(void *offset, quintptr_t mask, qintptr_t fn, con if (strlen(adr) < bufsize) { strcpy(buf, adr); - Info_SetValueForKey(buf, "mapname", info->map, bufsize); - Info_SetValueForKey(buf, "hostname", info->name, bufsize); - Info_SetValueForKey(buf, "g_humanplayers", va("%i", info->numhumans), bufsize); - Info_SetValueForKey(buf, "sv_maxclients", va("%i", info->maxplayers), bufsize); - Info_SetValueForKey(buf, "clients", va("%i", info->players), bufsize); + worldfuncs->SetInfoKey(buf, "mapname", info->map, bufsize); + worldfuncs->SetInfoKey(buf, "hostname", info->name, bufsize); + worldfuncs->SetInfoKey(buf, "g_humanplayers", va("%i", info->numhumans), bufsize); + worldfuncs->SetInfoKey(buf, "sv_maxclients", va("%i", info->maxplayers), bufsize); + worldfuncs->SetInfoKey(buf, "clients", va("%i", info->players), bufsize); if (info->adr.type == NA_IPV6 && info->adr.prot == NP_DGRAM) - Info_SetValueForKey(buf, "nettype", "2", bufsize); + worldfuncs->SetInfoKey(buf, "nettype", "2", bufsize); else if (info->adr.type == NA_IP && info->adr.prot == NP_DGRAM) - Info_SetValueForKey(buf, "nettype", "1", bufsize); + worldfuncs->SetInfoKey(buf, "nettype", "1", bufsize); else - Info_SetValueForKey(buf, "nettype", "", bufsize); + worldfuncs->SetInfoKey(buf, "nettype", "", bufsize); VM_LONG(ret) = true; } } @@ -1410,7 +1308,7 @@ static qintptr_t UI_SystemCalls(void *offset, quintptr_t mask, qintptr_t fn, con break; case UI_LAN_UPDATEVISIBLEPINGS: - return CL_QueryServers(); //return true while we're still going. + return masterfuncs->QueryServers(); //return true while we're still going. case UI_LAN_RESETPINGS: return 0; case UI_LAN_ADDSERVER: @@ -1427,13 +1325,13 @@ static qintptr_t UI_SystemCalls(void *offset, quintptr_t mask, qintptr_t fn, con //int source = VM_LONG(arg[0]); int key = bound(0, VM_LONG(arg[1]), countof(q3tofte)); int sortdir = VM_LONG(arg[2]); - serverinfo_t *s1 = Master_InfoForNum(VM_LONG(arg[3])); - serverinfo_t *s2 = Master_InfoForNum(VM_LONG(arg[4])); + serverinfo_t *s1 = masterfuncs->InfoForNum(VM_LONG(arg[3])); + serverinfo_t *s2 = masterfuncs->InfoForNum(VM_LONG(arg[4])); if (keyisstring[key]) - ret = strcasecmp(Master_ReadKeyString(s2, q3tofte[key]), Master_ReadKeyString(s1, q3tofte[key])); + ret = strcasecmp(masterfuncs->ReadKeyString(s2, q3tofte[key]), masterfuncs->ReadKeyString(s1, q3tofte[key])); else { - ret = Master_ReadKeyFloat(s2, q3tofte[key]) - Master_ReadKeyFloat(s1, q3tofte[key]); + ret = masterfuncs->ReadKeyFloat(s2, q3tofte[key]) - masterfuncs->ReadKeyFloat(s1, q3tofte[key]); if (ret < 0) ret = -1; else if (ret > 0) @@ -1446,8 +1344,8 @@ static qintptr_t UI_SystemCalls(void *offset, quintptr_t mask, qintptr_t fn, con case UI_LAN_GETSERVERCOUNT: //LAN Get server count //int (int source) - Master_CheckPollSockets(); - VM_LONG(ret) = Master_TotalCount(); + masterfuncs->CheckPollSockets(); + VM_LONG(ret) = masterfuncs->TotalCount(); break; case UI_LAN_GETSERVERADDRESSSTRING: //LAN get server address //void (int source, int svnum, char *buffer, int buflen) @@ -1457,11 +1355,11 @@ static qintptr_t UI_SystemCalls(void *offset, quintptr_t mask, qintptr_t fn, con char *buf = VM_POINTER(arg[2]); char *adr; char adrbuf[MAX_ADR_SIZE]; - serverinfo_t *info = Master_InfoForNum(VM_LONG(arg[1])); + serverinfo_t *info = masterfuncs->InfoForNum(VM_LONG(arg[1])); strcpy(buf, ""); if (info) { - adr = Master_ServerToString(adrbuf, sizeof(adrbuf), info); + adr = masterfuncs->ServerToString(adrbuf, sizeof(adrbuf), info); if (strlen(adr) < VM_LONG(arg[3])) { strcpy(buf, adr); @@ -1485,25 +1383,24 @@ static qintptr_t UI_SystemCalls(void *offset, quintptr_t mask, qintptr_t fn, con char *out = VM_POINTER(arg[2]); int maxsize = VM_LONG(arg[3]); char adr[MAX_ADR_SIZE]; - serverinfo_t *info = Master_InfoForNum(servernum); + serverinfo_t *info = masterfuncs->InfoForNum(servernum); *out = 0; if (info) { - Info_SetValueForStarKey(out, "hostname", info->name, maxsize); - Info_SetValueForStarKey(out, "mapname", info->map, maxsize); - Info_SetValueForStarKey(out, "clients", va("%i", info->players), maxsize); - Info_SetValueForStarKey(out, "sv_maxclients", va("%i", info->maxplayers), maxsize); - Info_SetValueForStarKey(out, "ping", va("%i", info->ping), maxsize); -// Info_SetValueForStarKey(out, "minping", info->map, maxsize); -// Info_SetValueForStarKey(out, "maxping", info->map, maxsize); -// Info_SetValueForStarKey(out, "game", info->map, maxsize); -// Info_SetValueForStarKey(out, "gametype", info->map, maxsize); -// Info_SetValueForStarKey(out, "nettype", info->map, maxsize); - Info_SetValueForStarKey(out, "addr", NET_AdrToString(adr, sizeof(adr), &info->adr), maxsize); -// Info_SetValueForStarKey(out, "punkbuster", info->map, maxsize); -// Info_SetValueForStarKey(out, "g_needpass", info->map, maxsize); -// Info_SetValueForStarKey(out, "g_humanplayers", info->map, maxsize); - + worldfuncs->SetInfoKey(out, "hostname", info->name, maxsize); + worldfuncs->SetInfoKey(out, "mapname", info->map, maxsize); + worldfuncs->SetInfoKey(out, "clients", va("%i", info->players), maxsize); + worldfuncs->SetInfoKey(out, "sv_maxclients", va("%i", info->maxplayers), maxsize); + worldfuncs->SetInfoKey(out, "ping", va("%i", info->ping), maxsize); +// worldfuncs->SetInfoKey(out, "minping", info->map, maxsize); +// worldfuncs->SetInfoKey(out, "maxping", info->map, maxsize); +// worldfuncs->SetInfoKey(out, "game", info->map, maxsize); +// worldfuncs->SetInfoKey(out, "gametype", info->map, maxsize); +// worldfuncs->SetInfoKey(out, "nettype", info->map, maxsize); + worldfuncs->SetInfoKey(out, "addr", masterfuncs->AdrToString(adr, sizeof(adr), &info->adr), maxsize); +// worldfuncs->SetInfoKey(out, "punkbuster", info->map, maxsize); +// worldfuncs->SetInfoKey(out, "g_needpass", info->map, maxsize); +// worldfuncs->SetInfoKey(out, "g_humanplayers", info->map, maxsize); } } break; @@ -1530,20 +1427,19 @@ static qintptr_t UI_SystemCalls(void *offset, quintptr_t mask, qintptr_t fn, con case UI_GET_CDKEY: //get cd key { + cvar_t *cvar = cvarfuncs->GetNVFDG("cl_cdkey", "", CVAR_ARCHIVE, "Quake3 auth", "Q3 Compat"); char *keydest = VM_POINTER(arg[0]); - if ((int)arg[0] + VM_LONG(arg[1]) >= mask || VM_POINTER(arg[0]) < offset) + if (!cvar || (int)arg[0] + VM_LONG(arg[1]) >= mask || VM_POINTER(arg[0]) < offset) break; //out of bounds. - strncpy(keydest, Cvar_VariableString("cl_cdkey"), VM_LONG(arg[1])); + Q_strncpyz(keydest, cvar->string, VM_LONG(arg[1])); } break; case UI_SET_CDKEY: //set cd key { char *keysrc = VM_POINTER(arg[0]); - cvar_t *cvar; if ((int)arg[0] + strlen(keysrc) >= mask || VM_POINTER(arg[0]) < offset) break; //out of bounds. - cvar = Cvar_Get("cl_cdkey", "", 0, "Quake3 auth"); - Cvar_Set(cvar, keysrc); + cvarfuncs->SetString("cl_cdkey", keysrc); } break; @@ -1653,8 +1549,8 @@ static qintptr_t UI_SystemCalls(void *offset, quintptr_t mask, qintptr_t fn, con break; } VM_LONG(ret) = sizeof(vidinfo_t); - vi->width = vid.width; - vi->height = vid.height; + vi->width = vsize[0]; + vi->height = vsize[1]; vi->refreshrate = 60; vi->fullscreen = 1; Q_strncpyz(vi->renderername, q_renderername, sizeof(vi->renderername)); @@ -1662,6 +1558,18 @@ static qintptr_t UI_SystemCalls(void *offset, quintptr_t mask, qintptr_t fn, con break; */ +#if 1//def BOTLIB_STATIC + case UI_PC_ADD_GLOBAL_DEFINE: + return botlib->PC_AddGlobalDefine(VM_POINTER(arg[0])); + case UI_PC_LOAD_SOURCE: + return botlib->PC_LoadSourceHandle(VM_POINTER(arg[0])); + case UI_PC_FREE_SOURCE: + return botlib->PC_FreeSourceHandle(VM_LONG(arg[0])); + case UI_PC_READ_TOKEN: + return botlib->PC_ReadTokenHandle(VM_LONG(arg[0]), VM_POINTER(arg[1])); + case UI_PC_SOURCE_FILE_AND_LINE: + return botlib->PC_SourceFileAndLine(VM_LONG(arg[0]), VM_POINTER(arg[1]), VM_POINTER(arg[2])); +#else case UI_PC_ADD_GLOBAL_DEFINE: Con_Printf("UI_PC_ADD_GLOBAL_DEFINE not supported\n"); break; @@ -1677,6 +1585,7 @@ static qintptr_t UI_SystemCalls(void *offset, quintptr_t mask, qintptr_t fn, con case UI_PC_READ_TOKEN: //fixme: memory protect. return Script_Read(arg[0], VM_POINTER(arg[1])); +#endif case UI_CIN_PLAYCINEMATIC: return UI_Cin_Play(VM_POINTER(arg[0]), VM_LONG(arg[1]), VM_LONG(arg[2]), VM_LONG(arg[3]), VM_LONG(arg[4]), VM_LONG(arg[5])); @@ -1689,7 +1598,17 @@ static qintptr_t UI_SystemCalls(void *offset, quintptr_t mask, qintptr_t fn, con case UI_CIN_SETEXTENTS: return UI_Cin_SetExtents(VM_LONG(arg[0]), VM_LONG(arg[1]), VM_LONG(arg[2]), VM_LONG(arg[3]), VM_LONG(arg[4])); + + + + + + + + +#ifndef _DEBUG default: +#endif Con_Printf("Q3UI: Unknown system trap: %i\n", (int)fn); return 0; } @@ -1748,25 +1667,27 @@ static void UI_DrawMenu(menu_t *m) { if (uivm) { - if (qrenderer != QR_NONE && (ui_width != vid.width || ui_height != vid.height)) + float vsize[2]; + + if (drawfuncs->GetVideoSize(vsize, NULL) && (ui_size[0] != vsize[0] || ui_size[1] != vsize[1])) { //should probably just rescale stuff instead. qboolean hadfocus = keycatcher&2; keycatcher &= ~2; - ui_width = vid.width; - ui_height = vid.height; - VM_Call(uivm, UI_INIT); + ui_size[0] = vsize[0]; + ui_size[1] = vsize[1]; + vmfuncs->Call(uivm, UI_INIT); if (hadfocus) { - if (cls.state) - VM_Call(uivm, UI_SET_ACTIVE_MENU, 2); + if (ccs.state) + vmfuncs->Call(uivm, UI_SET_ACTIVE_MENU, 2); else - VM_Call(uivm, UI_SET_ACTIVE_MENU, 1); + vmfuncs->Call(uivm, UI_SET_ACTIVE_MENU, 1); } } - VM_Call(uivm, UI_REFRESH, (int)(realtime * 1000)); + vmfuncs->Call(uivm, UI_REFRESH, plugfuncs->GetMilliseconds()); - uimenu.isopaque = VM_Call(uivm, UI_IS_FULLSCREEN); + uimenu.isopaque = vmfuncs->Call(uivm, UI_IS_FULLSCREEN); } } qboolean UI_KeyPress(struct menu_s *m, qboolean isdown, unsigned int devid, int key, int unicode) @@ -1838,9 +1759,9 @@ qboolean UI_KeyPress(struct menu_s *m, qboolean isdown, unsigned int devid, int } if (key && key < 1024) - /*result = */VM_Call(uivm, UI_KEY_EVENT, key, isdown); + /*result = */vmfuncs->Call(uivm, UI_KEY_EVENT, key, isdown); if (unicode && unicode < 1024) - /*result = */VM_Call(uivm, UI_KEY_EVENT, unicode|1024, isdown); + /*result = */vmfuncs->Call(uivm, UI_KEY_EVENT, unicode|1024, isdown); return true; } @@ -1853,7 +1774,7 @@ static qboolean UI_MousePosition(struct menu_s *m, qboolean abs, unsigned int de if (uivm && !abs) { int px = x, py = y; - VM_Call(uivm, UI_MOUSE_EVENT, px, py); + vmfuncs->Call(uivm, UI_MOUSE_EVENT, px, py); return true; } return false; @@ -1861,31 +1782,30 @@ static qboolean UI_MousePosition(struct menu_s *m, qboolean abs, unsigned int de void UI_Reset(void) { - Menu_Unlink(&uimenu, true); + inputfuncs->Menu_Unlink(&uimenu, true); - if (qrenderer == QR_NONE) //no renderer loaded + if (!drawfuncs->GetVideoSize(NULL,NULL)) //no renderer loaded UI_Stop(); else if (uivm) - VM_Call(uivm, UI_INIT); + vmfuncs->Call(uivm, UI_INIT); } void UI_Stop (void) { - Menu_Unlink(&uimenu, true); + inputfuncs->Menu_Unlink(&uimenu, true); if (uivm) { - VM_Call(uivm, UI_SHUTDOWN); - VM_Destroy(uivm); + vmfuncs->Call(uivm, UI_SHUTDOWN); + vmfuncs->Destroy(uivm); VM_fcloseall(0); uivm = NULL; //mimic Q3 and save the config if anything got changed. //note that q3 checks every frame. we only check when the ui is closed. - if (Cvar_UnsavedArchive()) - Cmd_ExecuteString("cfg_save", RESTRICT_LOCAL); + cmdfuncs->AddText("cfg_save_ifmodified\n", true); #if defined(CL_MASTER) - MasterInfo_WriteServers(); + masterfuncs->WriteServers(); #endif } } @@ -1894,7 +1814,9 @@ void UI_Start (void) { int i; int apiversion; - if (qrenderer == QR_NONE) + if (!cl_shownet_ptr) + return; //make sure UI_Init was called. if it wasn't then something messed up and we can't do client stuff. + if (!drawfuncs->GetVideoSize(ui_size,NULL)) return; UI_Stop(); @@ -1906,22 +1828,22 @@ void UI_Start (void) uimenu.mousemove = UI_MousePosition; uimenu.keyevent = UI_KeyPress; uimenu.release = UI_Release; + uimenu.lowpriority = true; - ui_width = vid.width; - ui_height = vid.height; - uivm = VM_Create("ui", com_nogamedirnativecode.ival?NULL:UI_SystemCallsNative, "vm/ui", UI_SystemCallsVM); + SV_InitBotLib(); + uivm = vmfuncs->Create("ui", cvarfuncs->GetFloat("com_gamedirnativecode")?UI_SystemCallsNative:NULL, "vm/ui", UI_SystemCallsVM); if (uivm) { - apiversion = VM_Call(uivm, UI_GETAPIVERSION, 6); + apiversion = vmfuncs->Call(uivm, UI_GETAPIVERSION, 6); if (apiversion != 4 && apiversion != 6) //make sure we can run the thing { Con_Printf("User-Interface VM uses incompatible API version (%i)\n", apiversion); - VM_Destroy(uivm); + vmfuncs->Destroy(uivm); VM_fcloseall(0); uivm = NULL; return; } - VM_Call(uivm, UI_INIT); + vmfuncs->Call(uivm, UI_INIT); UI_OpenMenu(); } @@ -1929,38 +1851,42 @@ void UI_Start (void) void UI_Restart_f(void) { + char arg1[256]; + cmdfuncs->Argv(1, arg1, sizeof(arg1)); UI_Stop(); - if (strcmp(Cmd_Argv(1), "off")) + if (strcmp(arg1, "off")) { UI_Start(); if (uivm) { - if (cls.state) - VM_Call(uivm, UI_SET_ACTIVE_MENU, 2); + if (ccs.state) + vmfuncs->Call(uivm, UI_SET_ACTIVE_MENU, 2); else - VM_Call(uivm, UI_SET_ACTIVE_MENU, 1); + vmfuncs->Call(uivm, UI_SET_ACTIVE_MENU, 1); } } } qboolean UI_OpenMenu(void) { + if (!uivm) + UI_Start(); if (uivm) { - if (cls.state) - VM_Call(uivm, UI_SET_ACTIVE_MENU, 2); + if (ccs.state) + vmfuncs->Call(uivm, UI_SET_ACTIVE_MENU, 2); else - VM_Call(uivm, UI_SET_ACTIVE_MENU, 1); + vmfuncs->Call(uivm, UI_SET_ACTIVE_MENU, 1); return true; } return false; } -qboolean UI_Command(void) +qboolean UI_ConsoleCommand(void) { if (uivm) - return VM_Call(uivm, UI_CONSOLE_COMMAND, (int)(realtime * 1000)); + return vmfuncs->Call(uivm, UI_CONSOLE_COMMAND, plugfuncs->GetMilliseconds()); return false; } @@ -1971,9 +1897,19 @@ qboolean UI_IsRunning(void) return false; } +vm_t *UI_GetUIVM(void) +{ + return uivm; +} + + void UI_Init (void) { - Cmd_AddCommand("ui_restart", UI_Restart_f); + cl_shownet_ptr = cvarfuncs->GetNVFDG("cl_shownet", "", 0, NULL, "Q3 Compat"); + cl_c2sdupe_ptr = cvarfuncs->GetNVFDG("cl_c2sdupe", "", 0, NULL, "Q3 Compat"); + cl_nodelta_ptr = cvarfuncs->GetNVFDG("cl_nodelta", "", 0, NULL, "Q3 Compat"); + + cmdfuncs->AddCommand("ui_restart", UI_Restart_f, "Reload the Q3-based User Interface module"); } #endif diff --git a/engine/client/client.h b/engine/client/client.h index f48bd9c6..574757eb 100644 --- a/engine/client/client.h +++ b/engine/client/client.h @@ -919,7 +919,6 @@ typedef struct char *particle_csname[MAX_CSPARTICLESPRE]; int particle_csprecache[MAX_CSPARTICLESPRE]; //these are actually 1-based, so we can be lazy and do a simple negate. - qboolean model_precaches_added; qboolean particle_ssprecaches; //says to not try to do any dp-compat hacks. qboolean particle_csprecaches; //says to not try to do any dp-compat hacks. @@ -1117,8 +1116,9 @@ extern qboolean nomaster; // void CL_InitDlights(void); void CL_FreeDlights(void); -dlight_t *CL_AllocDlight (int key); -dlight_t *CL_AllocSlight (void); //allocates a static light +dlight_t *CL_AllocDlight (int key); //allocates or reuses the light with the specified key index +dlight_t *CL_AllocDlightOrg (int keyidx, vec3_t keyorg); //reuses the light at the specified origin... +dlight_t *CL_AllocSlight (void); //allocates a new static light dlight_t *CL_NewDlight (int key, const vec3_t origin, float radius, float time, float r, float g, float b); dlight_t *CL_NewDlightCube (int key, const vec3_t origin, vec3_t angles, float radius, float time, vec3_t colours); void CL_CloneDlight(dlight_t *dl, dlight_t *src); //copies one light to another safely @@ -1196,7 +1196,7 @@ extern char emodel_name[], pmodel_name[], prespawn_name[], modellist_name[], sou //CL_TraceLine traces against network(positive)+csqc(negative) ents. returns frac(1 on failure), and impact, normal, ent values float CL_TraceLine (vec3_t start, vec3_t end, vec3_t impact, vec3_t normal, int *ent); -entity_t *TraceLineR (vec3_t start, vec3_t end, vec3_t impact, vec3_t normal); +entity_t *TraceLineR (vec3_t start, vec3_t end, vec3_t impact, vec3_t normal, qboolean bsponly); // // cl_input @@ -1445,25 +1445,6 @@ void CL_LinkProjectiles (void); void CL_ClearLerpEntsParticleState (void); qboolean CL_MayLerp(void); -// -//clq3_parse.c -// -#ifdef Q3CLIENT -void VARGS CLQ3_SendClientCommand(const char *fmt, ...) LIKEPRINTF(1); -void CLQ3_SendAuthPacket(netadr_t *gameserver); -void CLQ3_SendConnectPacket(netadr_t *to, int challenge, int qport); -void CLQ3_SendCmd(usercmd_t *cmd); -qboolean CLQ3_Netchan_Process(void); -void CLQ3_ParseServerMessage (void); -struct snapshot_s; -qboolean CG_FillQ3Snapshot(int snapnum, struct snapshot_s *snapshot); - -void CG_InsertIntoGameState(int num, char *str); -void CG_Restart_f(void); - -char *CG_GetConfigString(int num); -#endif - // //pr_csqc.c // diff --git a/engine/client/clq3_parse.c b/engine/client/clq3_parse.c index 0677acea..281a1b0b 100644 --- a/engine/client/clq3_parse.c +++ b/engine/client/clq3_parse.c @@ -1,18 +1,55 @@ -#include "quakedef.h" +#include "q3common.h" #include "shader.h" + +#include "glquake.h" +#include "shader.h" +#include "cl_master.h" + +#ifndef STATIC_Q3 +void Cvar_ForceCheatVars(qboolean semicheats, qboolean absolutecheats){} //locks/unlocks cheat cvars depending on weather we are allowed them. +//int Cvar_ApplyLatches(int latchflag){return 0;} + +unsigned int utf8_decode(int *error, const void *in, char const**out){return 0;} + +void Con_PrintFlags(const char *txt, unsigned int setflags, unsigned int clearflags){} +void Con_ClearNotify (void){} + +unsigned int key_dest_mask; +float in_sensitivityscale; +void Sys_Clipboard_PasteText(clipboardtype_t clipboardtype, void (*callback)(void *cb, const char *utf8), void *ctx){}; //calls the callback once the text is available (maybe instantly). utf8 arg may be NULL if the clipboard was unavailable. +void SCR_SetLoadingStage(int stage){} +void SCR_BeginLoadingPlaque (void){} +void SCR_EndLoadingPlaque (void){} + +void Shader_DefaultCinematic (struct shaderparsestate_s *ps, const char *shortname, const void *args){} +shader_t *R_RegisterCustom (model_t *mod, const char *name, unsigned int usageflags, shader_gen_t *defaultgen, const void *args){return NULL;} +cin_t *R_ShaderGetCinematic(shader_t *s){return NULL;} +void Media_SetState(cin_t *cin, cinstates_t newstate){} +void R_UnloadShader(shader_t *shader){} +cinstates_t Media_GetState(cin_t *cin){return 0;} +void Media_Send_Reset(cin_t *cin){} +char *CL_TryingToConnect(void){return NULL;} + +downloadlist_t *CL_DownloadFailed(const char *name, qdownload_t *qdl, enum dlfailreason_e failreason){return NULL;} +qboolean DL_Begun(qdownload_t *dl){return 0;} +void CL_DownloadFinished(qdownload_t *dl){} +int Sys_EnumerateFiles (const char *gpath, const char *match, int (QDECL *func)(const char *fname, qofs_t fsize, time_t modtime, void *parm, searchpathfuncs_t *spath), void *parm, searchpathfuncs_t *spath){return 0;} +#endif + //urm, yeah, this is more than just parse. #ifdef Q3CLIENT #include "clq3defs.h" -#define SHOWSTRING(s) if(cl_shownet.value==2)Con_Printf ("%s\n", s); -#define SHOWNET(x) if(cl_shownet.value==2)Con_Printf ("%3i:%s\n", msg_readcount-1, x); -#define SHOWNET2(x, y) if(cl_shownet.value==2)Con_Printf ("%3i:%3i:%s\n", msg_readcount-1, y, x); +#define SHOWSTRING(s) if(cl_shownet_ptr->value==2)Con_Printf ("%s\n", s); +#define SHOWNET(x) if(cl_shownet_ptr->value==2)Con_Printf ("%3i:%s\n", msg->currentbit-8, x); +#define SHOWNET2(x, y) if(cl_shownet_ptr->value==2)Con_Printf ("%3i:%3i:%s\n", msg->currentbit-8, y, x); void MSG_WriteBits(sizebuf_t *msg, int value, int bits); +static qboolean CLQ3_Netchan_Process(sizebuf_t *msg); ClientConnectionState_t ccs; @@ -26,7 +63,7 @@ qboolean CG_FillQ3Snapshot(int snapnum, snapshot_t *snapshot) if (snapnum > ccs.serverMessageNum) { - Host_EndGame("CG_FillQ3Snapshot: snapshotNumber > cl.snap.serverMessageNum"); + plugfuncs->EndGame("CG_FillQ3Snapshot: snapshotNumber > cl.snap.serverMessageNum"); } if (ccs.serverMessageNum - snapnum >= Q3UPDATE_BACKUP) @@ -70,10 +107,10 @@ void CLQ3_ParseServerCommand(void) int number; char *string; - number = MSG_ReadLong(); - SHOWNET(va("%i", number)); + number = msgfuncs->ReadLong(); +// SHOWNET(va("%i", number)); - string = MSG_ReadString(); + string = msgfuncs->ReadString(); SHOWSTRING(string); if( number <= ccs.lastServerCommandNum ) @@ -158,16 +195,11 @@ static void CLQ3_ParsePacketEntities( clientSnap_t *oldframe, clientSnap_t *newf while( 1 ) { - newnum = MSG_ReadBits( GENTITYNUM_BITS ); - if( newnum < 0 || newnum >= MAX_GENTITIES ) - { - Host_EndGame("CLQ3_ParsePacketEntities: bad number %i", newnum); - } - - if( msg_readcount > net_message.cursize ) - { - Host_EndGame("CLQ3_ParsePacketEntities: end of message"); - } + newnum = msgfuncs->ReadBits( GENTITYNUM_BITS ); + if (newnum < 0) + plugfuncs->EndGame("CLQ3_ParsePacketEntities: end of message"); + else if (newnum >= MAX_GENTITIES ) + plugfuncs->EndGame("CLQ3_ParsePacketEntities: bad number %i", newnum); // end of packetentities if( newnum == ENTITYNUM_NONE ) @@ -252,26 +284,23 @@ void CLQ3_ParseSnapshot(void) clientSnap_t snap, *oldsnap; int delta; int len; - int i; - outframe_t *frame; +// int i; +// outframe_t *frame; // usercmd_t *ucmd; // int commandTime; memset(&snap, 0, sizeof(snap)); snap.serverMessageNum = ccs.serverMessageNum; snap.serverCommandNum = ccs.lastServerCommandNum; - snap.serverTime = MSG_ReadLong(); + snap.serverTime = msgfuncs->ReadLong(); //so we can delta to it properly. - cl.oldgametime = cl.gametime; - cl.oldgametimemark = cl.gametimemark; - cl.gametime = snap.serverTime / 1000.0f; - cl.gametimemark = Sys_DoubleTime(); + clientfuncs->UpdateGameTime(snap.serverTime / 1000.0f); // If the frame is delta compressed from data that we // no longer have available, we must suck up the rest of // the frame, but not use it, then ask for a non-compressed message - delta = MSG_ReadByte(); + delta = msgfuncs->ReadByte(); if(delta) { snap.deltaFrame = ccs.serverMessageNum - delta; @@ -306,11 +335,11 @@ void CLQ3_ParseSnapshot(void) } // read snapFlags - snap.snapFlags = MSG_ReadByte(); + snap.snapFlags = msgfuncs->ReadByte(); // read areabits - len = MSG_ReadByte(); - MSG_ReadData(snap.areabits, len ); + len = msgfuncs->ReadByte(); + msgfuncs->ReadData(snap.areabits, len ); // read playerinfo SHOWSTRING("playerstate"); @@ -330,15 +359,15 @@ void CLQ3_ParseSnapshot(void) // Find last usercmd server has processed and calculate snap.ping snap.ping = 3; - for (i=cls.netchan.outgoing_sequence-1 ; i>cls.netchan.outgoing_sequence-Q3CMD_BACKUP ; i--) +/* for (i=ccs.netchan.outgoing_sequence-1 ; i>ccs.netchan.outgoing_sequence-Q3CMD_BACKUP ; i--) { frame = &cl.outframes[i & Q3CMD_MASK]; if (frame->server_message_num == snap.deltaFrame) { - snap.ping = Sys_Milliseconds() - frame->client_time; + snap.ping = plugfuncs->GetMilliseconds() - frame->client_time; break; } - } + }*/ memcpy(&ccs.snap, &snap, sizeof(snap)); memcpy(&ccs.snapshots[ccs.serverMessageNum & Q3UPDATE_MASK], &snap, sizeof(snap)); @@ -349,37 +378,37 @@ void CLQ3_ParseSnapshot(void) #define MAXCHUNKSIZE 65536 void CLQ3_ParseDownload(void) { - qdownload_t *dl = cls.download; + qdownload_t *dl = ccs.download; unsigned int chunknum; unsigned int chunksize; unsigned char chunkdata[MAXCHUNKSIZE]; int i; char *s; - chunknum = (unsigned short) MSG_ReadShort(); + chunknum = (unsigned short) msgfuncs->ReadShort(); chunknum |= ccs.downloadchunknum&~0xffff; //add the chunk number, truncated by the network protocol. if (!chunknum) { - dl->size = (unsigned int)MSG_ReadLong(); - Cvar_SetValue( Cvar_Get("cl_downloadSize", "0", 0, "Download stuff"), dl->size ); + dl->size = (unsigned int)msgfuncs->ReadLong(); + cvarfuncs->SetFloat( cvarfuncs->GetNVFDG("cl_downloadSize", "0", 0, NULL, "Q3 Compat")->name, dl->size ); //so the gamecode knows download progress. } if (dl->size == (unsigned int)-1) { //the only downloads we should be getting is pk3s. //if they're advertised-but-failing then its probably due to permissions rather than file-not-found - s = MSG_ReadString(); + s = msgfuncs->ReadString(); CL_DownloadFailed(dl->remotename, dl, DLFAIL_SERVERCVAR); - Host_EndGame("%s", s); + plugfuncs->EndGame("%s", s); return; } - chunksize = (unsigned short)MSG_ReadShort(); + chunksize = (unsigned short)msgfuncs->ReadShort(); if (chunksize > MAXCHUNKSIZE) - Host_EndGame("Server sent a download chunk of size %i (it's too damn big!)\n", chunksize); + plugfuncs->EndGame("Server sent a download chunk of size %i (it's too damn big!)\n", chunksize); for (i = 0; i < chunksize; i++) - chunkdata[i] = MSG_ReadByte(); + chunkdata[i] = msgfuncs->ReadByte(); if (ccs.downloadchunknum != chunknum) //the q3 client is rather lame. { //ccs.downloadchunknum holds the chunk number. @@ -410,9 +439,7 @@ void CLQ3_ParseDownload(void) { CL_DownloadFinished(dl); - FS_ReloadPackFiles(); - - cl.servercount = -1; //make sure the server resends us that vital gamestate. + ccs.servercount = -1; //make sure the server resends us that vital gamestate. ccs.downloadchunknum = -1; return; } @@ -437,45 +464,45 @@ static qboolean CLQ3_SendDownloads(char *rc, char *rn) qdownload_t *dl; char localname[MAX_QPATH]; char tempname[MAX_QPATH]; + char filename[MAX_QPATH]; char crc[64]; vfsfile_t *f; - extern cvar_t cl_downloads; - rc = COM_ParseOut(rc, crc, sizeof(crc)); - rn = COM_Parse(rn); - if (!*com_token) + rc = cmdfuncs->ParseToken(rc, crc, sizeof(crc), NULL); + rn = cmdfuncs->ParseToken(rn, filename, sizeof(filename), NULL); + if (!*filename) break; - if (!strchr(com_token, '/')) //don't let some muppet tell us to download quake3.exe + if (!strchr(filename, '/')) //don't let some muppet tell us to download quake3.exe break; //as much as I'd like to use COM_FCheckExists, this stuf is relative to root, not the gamedir. - f = FS_OpenVFS(va("%s.pk3", com_token), "rb", FS_ROOT); + f = fsfuncs->OpenVFS(va("%s.pk3", filename), "rb", FS_ROOT); if (f) { VFS_CLOSE(f); continue; } - if (!FS_GenCachedPakName(va("%s.pk3", com_token), crc, localname, sizeof(localname))) + if (!fsfuncs->GenCachedPakName(va("%s.pk3", filename), crc, localname, sizeof(localname))) continue; - f = FS_OpenVFS(localname, "rb", FS_ROOT); + f = fsfuncs->OpenVFS(localname, "rb", FS_ROOT); if (f) { VFS_CLOSE(f); continue; } - if (!FS_GenCachedPakName(va("%s.tmp", com_token), crc, tempname, sizeof(tempname))) + if (!fsfuncs->GenCachedPakName(va("%s.tmp", filename), crc, tempname, sizeof(tempname))) continue; - if (!cl_downloads.ival) + if (!cvarfuncs->GetFloat("cl_downloads")) { - Con_Printf(CON_WARNING "Need to download %s.pk3, but downloads are disabled\n", com_token); + Con_Printf(CON_WARNING "Need to download %s.pk3, but downloads are disabled\n", filename); continue; } //fixme: request to download it - Con_Printf("Sending request to download %s.pk3\n", com_token); - CLQ3_SendClientCommand("download %s.pk3", com_token); + Con_Printf("Sending request to download %s.pk3\n", filename); + CLQ3_SendClientCommand("download %s.pk3", filename); ccs.downloadchunknum = 0; dl = Z_Malloc(sizeof(*dl)); //q3's downloads are relative to root, but they do at least force a pk3 extension. @@ -484,84 +511,73 @@ static qboolean CLQ3_SendDownloads(char *rc, char *rn) dl->prefixbytes = 8; dl->fsroot = FS_ROOT; - Q_snprintfz(dl->remotename, sizeof(dl->remotename), "%s.pk3", com_token); + Q_snprintfz(dl->remotename, sizeof(dl->remotename), "%s.pk3", filename); dl->method = DL_Q3; dl->percent = 0; - cls.download = dl; + ccs.download = dl; return true; } return false; } -qboolean CLQ3_SystemInfoChanged(char *str) +qboolean CLQ3_SystemInfoChanged(const char *str) { qboolean usingpure, usingcheats; char *value; char *pc, *pn; char *rc, *rn; - Con_Printf("Server's sv_pure: \"%s\"\n", Info_ValueForKey(str, "sv_pure")); - usingpure = atoi(Info_ValueForKey(str, "sv_pure")); - usingcheats = atoi(Info_ValueForKey(str, "sv_cheats")); + Con_Printf("Server's sv_pure: \"%s\"\n", worldfuncs->GetInfoKey(str, "sv_pure")); + usingpure = atoi(worldfuncs->GetInfoKey(str, "sv_pure")); + usingcheats = atoi(worldfuncs->GetInfoKey(str, "sv_cheats")); Cvar_ForceCheatVars(usingpure||usingcheats, usingcheats); -// if (atoi(value)) -// Host_EndGame("Unable to connect to Q3 Pure Servers\n"); - value = Info_ValueForKey(str, "fs_game"); +// if (atoi(value)) +// Host_EndGame("Unable to connect to Q3 Pure Servers\n"); + value = worldfuncs->GetInfoKey(str, "fs_game"); -#ifndef CLIENTONLY - if (!sv.state) -#endif + if (!*value) { - COM_FlushTempoaryPacks(); - if (!*value) - value = "baseq3"; - COM_Gamedir(value, NULL); -#ifndef CLIENTONLY - InfoBuf_SetStarKey (&svs.info, "*gamedir", value); -#endif + value = "baseq3"; } - rc = Info_ValueForKey(str, "sv_referencedPaks"); //the ones that we should download. - rn = Info_ValueForKey(str, "sv_referencedPakNames"); + rc = worldfuncs->GetInfoKey(str, "sv_referencedPaks"); //the ones that we should download. + rn = worldfuncs->GetInfoKey(str, "sv_referencedPakNames"); if (CLQ3_SendDownloads(rc, rn)) return false; - pc = Info_ValueForKey(str, "sv_paks"); //the ones that we are allowed to use (in order!) - pn = Info_ValueForKey(str, "sv_pakNames"); - FS_PureMode(usingpure?2:0, pn, pc, rn, rc, ccs.fs_key); + pc = worldfuncs->GetInfoKey(str, "sv_paks"); //the ones that we are allowed to use (in order!) + pn = worldfuncs->GetInfoKey(str, "sv_pakNames"); + fsfuncs->PureMode(value, usingpure?2:0, pn, pc, rn, rc, ccs.fs_key); return true; //yay, we're in } -void CLQ3_ParseGameState(void) +void CLQ3_ParseGameState(sizebuf_t *msg) { int c; int index; char *configString; - cvar_t *cl_paused; // // wipe the client_state_t struct // - CL_ClearState(true); + clientfuncs->ClearClientState(); + CG_ClearGameState(); ccs.firstParseEntity = 0; memset(ccs.parseEntities, 0, sizeof(ccs.parseEntities)); memset(ccs.baselines, 0, sizeof(ccs.baselines)); - - cl.minpitch = -90; - cl.maxpitch = 90; - - ccs.lastServerCommandNum = MSG_ReadLong(); + ccs.lastServerCommandNum = msgfuncs->ReadLong(); for(;;) { - c = MSG_ReadByte(); + c = msgfuncs->ReadByte(); - if(msg_badread) + if(c < 0) { - Host_EndGame("CLQ3_ParseGameState: read past end of server message"); + plugfuncs->EndGame("CLQ3_ParseGameState: read past end of server message"); + break; } if(c == svcq3_eom) @@ -574,33 +590,33 @@ void CLQ3_ParseGameState(void) switch(c) { default: - Host_EndGame("CLQ3_ParseGameState: bad command byte %i", c); + plugfuncs->EndGame("CLQ3_ParseGameState: bad command byte %i", c); break; case svcq3_configstring: - index = MSG_ReadBits(16); + index = msgfuncs->ReadBits(16); if (index < 0 || index >= MAX_Q3_CONFIGSTRINGS) { - Host_EndGame("CLQ3_ParseGameState: configString index %i out of range", index); + plugfuncs->EndGame("CLQ3_ParseGameState: configString index %i out of range", index); } - configString = MSG_ReadString(); + configString = msgfuncs->ReadString(); CG_InsertIntoGameState(index, configString); break; case svcq3_baseline: - index = MSG_ReadBits(GENTITYNUM_BITS); + index = msgfuncs->ReadBits(GENTITYNUM_BITS); if (index < 0 || index >= MAX_GENTITIES) { - Host_EndGame("CLQ3_ParseGameState: baseline index %i out of range", index); + plugfuncs->EndGame("CLQ3_ParseGameState: baseline index %i out of range", index); } MSG_Q3_ReadDeltaEntity(NULL, &ccs.baselines[index], index); break; } } - cl.playerview[0].playernum = MSG_ReadLong(); - ccs.fs_key = MSG_ReadLong(); + ccs.playernum = msgfuncs->ReadLong(); + ccs.fs_key = msgfuncs->ReadLong(); if (!CLQ3_SystemInfoChanged(CG_GetConfigString(CFGSTR_SYSINFO))) { @@ -608,56 +624,48 @@ void CLQ3_ParseGameState(void) return; } - CG_Restart_f(); + CG_Restart(); UI_Restart_f(); - if (!cl.worldmodel) - Host_EndGame("CGame didn't set a map.\n"); + if (!ccs.worldmodel) + plugfuncs->EndGame("CGame didn't set a map.\n"); - cl.model_precaches_added = false; - Surf_NewMap (); + scenefuncs->NewMap (ccs.worldmodel); SCR_EndLoadingPlaque(); - CL_MakeActive("Quake3Arena"); - - cl.splitclients = 1; + ccs.state = ca_active; { char buffer[2048]; - strcpy(buffer, va("cp %i ", cl.servercount)); - FSQ3_GenerateClientPacksList(buffer, sizeof(buffer), ccs.fs_key); + strcpy(buffer, va("cp %i ", ccs.servercount)); + fsfuncs->GenerateClientPacksList(buffer, sizeof(buffer), ccs.fs_key); CLQ3_SendClientCommand("%s", buffer); // warning: format not a string literal and no format arguments } // load cgame, etc // CL_ChangeLevel(); - cl_paused = Cvar_FindVar("cl_paused"); - if (cl_paused && cl_paused->ival) - Cvar_ForceSet(cl_paused, "0"); - + cvarfuncs->ForceSetString("cl_paused", "0"); } -void CLQ3_ParseServerMessage (void) +int CLQ3_ParseServerMessage (sizebuf_t *msg) { int cmd; - if (!CLQ3_Netchan_Process()) - return; //was a fragment. + if (!CLQ3_Netchan_Process(msg)) + return ccs.state; //was a fragment. - if (cl_shownet.value == 1) - Con_Printf ("%i ",net_message.cursize); - else if (cl_shownet.value == 2) + if (cl_shownet_ptr->value == 1) + Con_Printf ("%i ", msg->cursize); + else if (cl_shownet_ptr->value == 2) Con_Printf ("------------------\n"); - net_message.packing = SZ_RAWBYTES; - MSG_BeginReading(msg_nullnetprim); - ccs.serverMessageNum = MSG_ReadLong(); - net_message.packing = SZ_HUFFMAN; //the rest is huffman compressed. - net_message.currentbit = msg_readcount*8; + msgfuncs->BeginReading(msg, msg_nullnetprim); + ccs.serverMessageNum = msgfuncs->ReadLong(); + msg->packing = SZ_HUFFMAN; //the rest is huffman compressed. // read last client command number server received - ccs.lastClientCommandNum = MSG_ReadLong(); + ccs.lastClientCommandNum = msgfuncs->ReadLong(); if( ccs.lastClientCommandNum <= ccs.numClientCommands - Q3TEXTCMD_BACKUP ) { ccs.lastClientCommandNum = ccs.numClientCommands - Q3TEXTCMD_BACKUP + 1; @@ -672,11 +680,11 @@ void CLQ3_ParseServerMessage (void) // for(;;) { - cmd = MSG_ReadByte(); + cmd = msgfuncs->ReadByte(); - if(msg_badread) //hm, we have an eom, so only stop when the message is bad. + if(cmd < 0) //hm, we have an eom, so only stop when the message is bad. { - Host_EndGame("CLQ3_ParseServerMessage: read past end of server message"); + plugfuncs->EndGame("CLQ3_ParseServerMessage: read past end of server message"); break; } @@ -692,12 +700,12 @@ void CLQ3_ParseServerMessage (void) switch(cmd) { default: - Host_EndGame("CLQ3_ParseServerMessage: Illegible server message"); + plugfuncs->EndGame("CLQ3_ParseServerMessage: Illegible server message"); break; case svcq3_nop: break; case svcq3_gamestate: - CLQ3_ParseGameState(); + CLQ3_ParseGameState(msg); break; case svcq3_serverCommand: CLQ3_ParseServerCommand(); @@ -710,71 +718,58 @@ void CLQ3_ParseServerMessage (void) break; } } + return ccs.state; } -qboolean CLQ3_Netchan_Process(void) +static qboolean CLQ3_Netchan_Process(sizebuf_t *msg) { -#ifndef Q3_NOENCRYPT - int sequence; - int lastClientCommandNum; - qbyte bitmask; - qbyte c; - int i, j; - char *string; - int bit; - int readcount; -#endif - - if(!Netchan_ProcessQ3(&cls.netchan)) + if(Netchan_ProcessQ3(&ccs.netchan, msg)) { - return false; - } - #ifndef Q3_NOENCRYPT - // archive buffer state - bit = net_message.currentbit; - readcount = msg_readcount; - net_message.packing = SZ_HUFFMAN; - net_message.currentbit = 32; + int sequence; + int lastClientCommandNum; + qbyte bitmask; + qbyte c; + int i, j; + char *string; + int readcount; - lastClientCommandNum = MSG_ReadLong(); - sequence = LittleLong(*(int *)net_message.data); + msgfuncs->BeginReading(msg, msg_nullnetprim); + sequence = msgfuncs->ReadLong(); + msg->packing = SZ_HUFFMAN; + readcount = msg->currentbit>>3; + lastClientCommandNum = msgfuncs->ReadLong(); - // restore buffer state - net_message.currentbit = bit; - msg_readcount = readcount; + // calculate bitmask + bitmask = (sequence ^ ccs.challenge) & 0xff; + string = ccs.clientCommands[lastClientCommandNum & Q3TEXTCMD_MASK]; - // calculate bitmask - bitmask = (sequence ^ cls.challenge) & 0xff; - string = ccs.clientCommands[lastClientCommandNum & Q3TEXTCMD_MASK]; - - // decrypt the packet - for(i=msg_readcount+4,j=0 ; icursize ; i++,j++) { - j = 0; // another way around + if(!string[j]) + j = 0; // another way around + c = string[j]; + if(c > 127 || c == '%') + c = '.'; + bitmask ^= c << ((i-readcount) & 1); + msg->data[i] ^= bitmask; } - c = string[j]; - if(c > 127 || c == '%') - { - c = '.'; - } - bitmask ^= c << ((i-msg_readcount) & 1); - net_message.data[i] ^= bitmask; - } + msg->packing = SZ_RAWBITS; //first bit was plain... #endif - - return true; + return true; //all good + } + return false; //its bad dude, bad. } -void CL_Netchan_Transmit( int length, const qbyte *data ) +void CL_Netchan_Transmit(struct ftenet_connections_s *socket, int length, const qbyte *data ) { -#define msg net_message #ifndef Q3_NOENCRYPT + sizebuf_t msg; + char msgdata[MAX_OVERALLMSGLEN]; int serverid; int lastSequence; int lastServerCommandNum; @@ -782,47 +777,45 @@ void CL_Netchan_Transmit( int length, const qbyte *data ) qbyte c; int i, j; char *string; -#endif - net_message.cursize = 0; - SZ_Write(&msg, data, length); - if(msg.overflowed) + msgfuncs->BeginWriting(&msg, msg_nullnetprim, msgdata, sizeof(msgdata)); + msgfuncs->WriteData(&msg, data, length); + + if (msg.overflowed) { - Host_EndGame("Client message overflowed"); + plugfuncs->EndGame("Client message overflowed"); } -#ifndef Q3_NOENCRYPT - msg_readcount = 0; - msg.currentbit = 0; + msgfuncs->BeginReading(&msg, msg_nullnetprim); msg.packing = SZ_HUFFMAN; - serverid = MSG_ReadLong(); - lastSequence = MSG_ReadLong(); - lastServerCommandNum = MSG_ReadLong(); + serverid = msgfuncs->ReadLong(); + lastSequence = msgfuncs->ReadLong(); + lastServerCommandNum = msgfuncs->ReadLong(); // calculate bitmask - bitmask = (lastSequence ^ serverid ^ cls.challenge) & 0xff; + bitmask = (lastSequence ^ serverid ^ ccs.challenge) & 0xff; string = ccs.serverCommands[lastServerCommandNum & Q3TEXTCMD_MASK]; // encrypt the packet - for( i=12,j=0 ; i 127 || c == '%' ) + if (c > 127 || c == '%') { c = '.'; } bitmask ^= c << (i & 1); msg.data[i] ^= bitmask; } + data = msg.data; + length = msg.cursize; #endif - - Netchan_TransmitQ3( &cls.netchan, msg.cursize, msg.data ); -#undef msg + Netchan_TransmitQ3(socket, &ccs.netchan, length, data); } @@ -832,12 +825,12 @@ static void MSG_WriteDeltaKey( sizebuf_t *msg, int key, int from, int to, int bi { if( from == to ) { - MSG_WriteBits( msg, 0, 1 ); + msgfuncs->WriteBits( msg, 0, 1 ); return; // unchanged } - MSG_WriteBits( msg, 1, 1 ); - MSG_WriteBits( msg, to ^ key, bits ); + msgfuncs->WriteBits( msg, 1, 1 ); + msgfuncs->WriteBits( msg, to ^ key, bits ); } void MSG_Q3_WriteDeltaUsercmd( sizebuf_t *msg, int key, const usercmd_t *from, const usercmd_t *to ) @@ -845,29 +838,27 @@ void MSG_Q3_WriteDeltaUsercmd( sizebuf_t *msg, int key, const usercmd_t *from, c // figure out how to pack serverTime if( to->servertime - from->servertime < 255 ) { - MSG_WriteBits(msg, 1, 1); - MSG_WriteBits(msg, to->servertime - from->servertime, 8); + msgfuncs->WriteBits(msg, 1, 1); + msgfuncs->WriteBits(msg, to->servertime - from->servertime, 8); } else { - MSG_WriteBits( msg, 0, 1 ); - MSG_WriteBits( msg, to->servertime, 32); + msgfuncs->WriteBits( msg, 0, 1 ); + msgfuncs->WriteBits( msg, to->servertime, 32); } if( !memcmp( (qbyte *)from + 4, (qbyte *)to + 4, sizeof( usercmd_t ) - 4 ) ) { - MSG_WriteBits(msg, 0, 1); + msgfuncs->WriteBits(msg, 0, 1); return; // nothing changed } - MSG_WriteBits(msg, 1, 1); - key ^= to->servertime; - + msgfuncs->WriteBits(msg, 1, 1); MSG_WriteDeltaKey(msg, key, from->angles[0], to->angles[0], 16); MSG_WriteDeltaKey(msg, key, from->angles[1], to->angles[1], 16); MSG_WriteDeltaKey(msg, key, from->angles[2], to->angles[2], 16); MSG_WriteDeltaKey(msg, key, from->forwardmove, to->forwardmove, 8); - MSG_WriteDeltaKey(msg, key, from->sidemove, to->sidemove, 8 ); + MSG_WriteDeltaKey(msg, key, from->sidemove, to->sidemove, 8); MSG_WriteDeltaKey(msg, key, from->upmove, to->upmove, 8); MSG_WriteDeltaKey(msg, key, from->buttons, to->buttons, 16); MSG_WriteDeltaKey(msg, key, from->weapon, to->weapon, 8); @@ -889,28 +880,29 @@ void VARGS CLQ3_SendClientCommand(const char *fmt, ...) // check if server will lose some of our clientCommands if(ccs.numClientCommands - ccs.lastClientCommandNum >= Q3TEXTCMD_BACKUP) - Host_EndGame("Client command overflow"); + plugfuncs->EndGame("Client command overflow"); Q_strncpyz(ccs.clientCommands[ccs.numClientCommands & Q3TEXTCMD_MASK], command, sizeof(ccs.clientCommands[0])); Con_DPrintf("Sending %s\n", command); } -void CLQ3_SendCmd(usercmd_t *cmd) +void CLQ3_SendCmd(struct ftenet_connections_s *socket, usercmd_t *cmd, unsigned int movesequence, double gametime) { char *string; int i; char data[MAX_OVERALLMSGLEN]; sizebuf_t msg; - outframe_t *frame, *oldframe; +// outframe_t *frame; + unsigned int oldsequence; int cmdcount, key; - usercmd_t *to; - const usercmd_t *from; - extern cvar_t cl_nodelta, cl_c2sdupe; + const usercmd_t *to, *from; + static usercmd_t nullcmd; //reuse the q1 array - cmd->servertime = cl.servertime*1000; + cmd->servertime = gametime*1000; cmd->weapon = ccs.selected_weapon; + cmd->forwardmove *= 127/400.0f; cmd->sidemove *= 127/400.0f; cmd->upmove *= 127/400.0f; @@ -935,59 +927,55 @@ void CLQ3_SendCmd(usercmd_t *cmd) if (Key_Dest_Has(~kdm_game)) cmd->buttons |= 2; //add in the 'at console' button - cl.outframes[cl.movesequence&Q3CMD_MASK].cmd[0] = *cmd; - cl.movesequence++; - //FIXME: q3 generates a new command every video frame, but a new packet at a more limited rate. //FIXME: we should return here if its not yet time for a network frame. - frame = &cl.outframes[cls.netchan.outgoing_sequence & Q3CMD_MASK]; - frame->cmd_sequence = cl.movesequence; +/* frame = &cl.outframes[ccs.netchan.outgoing_sequence & Q3CMD_MASK]; + frame->cmd_sequence = movesequence; frame->server_message_num = ccs.serverMessageNum; - frame->server_time = cl.gametime; - frame->client_time = Sys_DoubleTime()*1000; - + frame->server_time = gametime; + frame->client_time = plugfuncs->GetMilliseconds(); +*/ memset(&msg, 0, sizeof(msg)); msg.maxsize = sizeof(data); msg.data = data; msg.packing = SZ_HUFFMAN; - MSG_WriteBits(&msg, cl.servercount, 32); - MSG_WriteBits(&msg, ccs.serverMessageNum, 32); - MSG_WriteBits(&msg, ccs.lastServerCommandNum, 32); + msgfuncs->WriteBits(&msg, ccs.servercount, 32); + msgfuncs->WriteBits(&msg, ccs.serverMessageNum, 32); + msgfuncs->WriteBits(&msg, ccs.lastServerCommandNum, 32); // write clientCommands not acknowledged by server yet for (i=ccs.lastClientCommandNum+1; i<=ccs.numClientCommands; i++) { - MSG_WriteBits(&msg, clcq3_clientCommand, 8); - MSG_WriteBits(&msg, i, 32); + msgfuncs->WriteBits(&msg, clcq3_clientCommand, 8); + msgfuncs->WriteBits(&msg, i, 32); string = ccs.clientCommands[i & Q3TEXTCMD_MASK]; while(*string) - MSG_WriteBits(&msg, *string++, 8); - MSG_WriteBits(&msg, 0, 8); + msgfuncs->WriteBits(&msg, *string++, 8); + msgfuncs->WriteBits(&msg, 0, 8); } - i = cls.netchan.outgoing_sequence; - i -= bound(0, cl_c2sdupe.ival, 5); //extra age, if desired + i = ccs.netchan.outgoing_sequence; + i -= bound(0, cl_c2sdupe_ptr->ival, 5); //extra age, if desired i--; - if (i < cls.netchan.outgoing_sequence-Q3CMD_MASK) - i = cls.netchan.outgoing_sequence-Q3CMD_MASK; - oldframe = &cl.outframes[i & Q3CMD_MASK]; - cmdcount = cl.movesequence - oldframe->cmd_sequence; + if (i < ccs.netchan.outgoing_sequence-Q3CMD_MASK) + i = ccs.netchan.outgoing_sequence-Q3CMD_MASK; + oldsequence = movesequence-1;//cl.outframes[i & Q3CMD_MASK].cmd_sequence; + cmdcount = movesequence - oldsequence; if (cmdcount > Q3CMD_MASK) cmdcount = Q3CMD_MASK; // begin a client move command, if any if (cmdcount) { - if(cl_nodelta.value || !ccs.snap.valid || - ccs.snap.serverMessageNum != ccs.serverMessageNum) - MSG_WriteBits(&msg, clcq3_nodeltaMove, 8); // no compression + if(cl_nodelta_ptr->value || !ccs.snap.valid || ccs.snap.serverMessageNum != ccs.serverMessageNum) + msgfuncs->WriteBits(&msg, clcq3_nodeltaMove, 8); // no compression else - MSG_WriteBits(&msg, clcq3_move, 8); + msgfuncs->WriteBits(&msg, clcq3_move, 8); // write cmdcount - MSG_WriteBits(&msg, cmdcount, 8); + msgfuncs->WriteBits(&msg, cmdcount, 8); // calculate key string = ccs.serverCommands[ccs.lastServerCommandNum & Q3TEXTCMD_MASK]; @@ -996,22 +984,24 @@ void CLQ3_SendCmd(usercmd_t *cmd) //note that q3 uses timestamps so sequences are not important //we can also send dupes without issue. from = &nullcmd; - for (i = cl.movesequence-cmdcount; i < cl.movesequence; i++) + for (i = movesequence-cmdcount; i < movesequence; i++) { - to = &cl.outframes[i&Q3CMD_MASK].cmd[0]; + to = inputfuncs->GetMoveEntry(i); + if (!to) + to = from; MSG_Q3_WriteDeltaUsercmd( &msg, key, from, to ); from = to; } } - MSG_WriteBits(&msg, clcq3_eom, 8); + msgfuncs->WriteBits(&msg, clcq3_eom, 8); - CL_Netchan_Transmit( msg.cursize, msg.data ); - while(cls.netchan.reliable_length) - Netchan_TransmitNextFragment(&cls.netchan); + CL_Netchan_Transmit(socket, msg.cursize, msg.data ); + while(ccs.netchan.reliable_length) + Netchan_TransmitNextFragment(socket, &ccs.netchan); } -void CLQ3_SendAuthPacket(netadr_t *gameserver) +void CLQ3_SendAuthPacket(struct ftenet_connections_s *socket, netadr_t *gameserver) { #ifdef HAVE_PACKET char data[2048]; @@ -1021,30 +1011,27 @@ void CLQ3_SendAuthPacket(netadr_t *gameserver) //this should be the right code, but it doesn't work. if (gameserver->type == NA_IP) { - char *key = Cvar_Get("cl_cdkey", "", 0, "Quake3 auth")->string; + char *key = cvarfuncs->GetNVFDG("cl_cdkey", "", CVAR_ARCHIVE, "Quake3 auth", "Q3 Compat")->string; netadr_t authaddr; #define Q3_AUTHORIZE_SERVER_NAME "authorize.quake3arena.com:27952" if (*key) { Con_Printf("Resolving %s\n", Q3_AUTHORIZE_SERVER_NAME); - if (NET_StringToAdr(Q3_AUTHORIZE_SERVER_NAME, 0, &authaddr)) + if (masterfuncs->StringToAdr(Q3_AUTHORIZE_SERVER_NAME, 0, &authaddr, 1, NULL)) { - msg.data = data; - msg.cursize = 0; - msg.overflowed = msg.allowoverflow = 0; - msg.maxsize = sizeof(data); - MSG_WriteLong(&msg, -1); - MSG_WriteString(&msg, "getKeyAuthorize 0 "); + msgfuncs->BeginWriting(&msg, msg_nullnetprim, data, sizeof(data)); + msgfuncs->WriteLong(&msg, -1); + msgfuncs->WriteString(&msg, "getKeyAuthorize 0 "); msg.cursize--; while(*key) { if ((*key >= 'a' && *key <= 'z') || (*key >= 'A' && *key <= 'Z') || (*key >= '0' && *key <= '9')) - MSG_WriteByte(&msg, *key); + msgfuncs->WriteByte(&msg, *key); key++; } - MSG_WriteByte(&msg, 0); + msgfuncs->WriteByte(&msg, 0); - NET_SendPacket (cls.sockets, msg.cursize, msg.data, &authaddr); + msgfuncs->SendPacket(socket, msg.cursize, msg.data, &authaddr); } else Con_Printf(" failed\n"); @@ -1053,33 +1040,45 @@ void CLQ3_SendAuthPacket(netadr_t *gameserver) #endif } -void CLQ3_SendConnectPacket(netadr_t *to, int challenge, int qport) +void CLQ3_SendConnectPacket(struct ftenet_connections_s *socket, netadr_t *to, int challenge, int qport, infobuf_t *userinfo) { char infostr[1024]; char data[2048]; sizebuf_t msg; + static const char *priorityq3[] = {"*", "name", NULL}; static const char *nonq3[] = {"challenge", "qport", "protocol", "ip", "chat", NULL}; + int protocol = cvarfuncs->GetFloat("com_protocolversion"); memset(&ccs, 0, sizeof(ccs)); + ccs.servercount = -1; + ccs.challenge = challenge; + Netchan_SetupQ3(NS_CLIENT, &ccs.netchan, to, qport); - InfoBuf_ToString(&cls.userinfo[0], infostr, sizeof(infostr), basicuserinfos, nonq3, NULL, &cls.userinfosync, &cls.userinfo[0]); + worldfuncs->IBufToInfo(userinfo, infostr, sizeof(infostr), priorityq3, nonq3, NULL, NULL,/*&cls.userinfosync,*/ userinfo); - cl.splitclients = 1; - msg.data = data; - msg.cursize = 0; - msg.overflowed = msg.allowoverflow = 0; - msg.maxsize = sizeof(data); - MSG_WriteLong(&msg, -1); - MSG_WriteString(&msg, va("connect \"\\challenge\\%i\\qport\\%i\\protocol\\%i%s\"", challenge, qport, PROTOCOL_VERSION_Q3, infostr)); + msgfuncs->BeginWriting(&msg, msg_nullnetprim, data, sizeof(data)); + msgfuncs->WriteLong(&msg, -1); + msgfuncs->WriteString(&msg, va("connect \"\\challenge\\%i\\qport\\%i\\protocol\\%i%s\"", challenge, qport, protocol, infostr)); #ifdef HUFFNETWORK - Huff_EncryptPacket(&msg, 12); - if (!Huff_CompressionCRC(HUFFCRC_QUAKE3)) + if (msgfuncs->Huff_EncryptPacket) + msgfuncs->Huff_EncryptPacket(&msg, 12); + if (!msgfuncs->Huff_CompressionCRC || !msgfuncs->Huff_CompressionCRC(HUFFCRC_QUAKE3)) { Con_Printf("Huffman compression error\n"); return; } #endif - NET_SendPacket (cls.sockets, msg.cursize, msg.data, to); + msgfuncs->SendPacket (socket, msg.cursize, msg.data, to); +} + +void CLQ3_Established(void) +{ + ccs.state = ca_connected; +} + +void CLQ3_Disconnect(struct ftenet_connections_s *socket) +{ + ccs.state = ca_disconnected; } #endif diff --git a/engine/client/clq3defs.h b/engine/client/clq3defs.h index 07f19242..f3fc1048 100644 --- a/engine/client/clq3defs.h +++ b/engine/client/clq3defs.h @@ -1,11 +1,6 @@ #ifndef _Q3DEFS_H_ #define _Q3DEFS_H_ -//#define Q3_NOENCRYPT //a debugging property, makes it incompatible with q3 - - -#define PROTOCOL_VERSION_Q3 68 - void Q3_SetKeyCatcher(int newcatcher); int Q3_GetKeyCatcher(void); @@ -24,10 +19,9 @@ typedef struct { #define MAX_Q3_STATS 16 #define MAX_Q3_PERSISTANT 16 -#define MAX_Q3_POWERUPS 16 +#define MAX_Q3_POWERUPS 16 #define MAX_Q3_WEAPONS 16 - -#define MAX_PS_EVENTS 2 +#define MAX_PS_EVENTS 2 typedef struct q3playerState_s { int commandTime; // cmd->serverTime of last executed command int pm_type; @@ -85,16 +79,15 @@ typedef struct q3playerState_s { int persistant[MAX_Q3_PERSISTANT]; // stats that aren't cleared on death int powerups[MAX_Q3_POWERUPS]; // level.time that the powerup runs out int ammo[MAX_Q3_WEAPONS]; - int generic1; int loopSound; int jumppad_ent; // jumppad entity hit this frame - // not communicated over the net at all int ping; // server to game info for scoreboard int pmove_framecount; // FIXME: don't transmit over the network int jumppad_frame; int entityEventSequence; + } q3playerState_t; @@ -149,6 +142,7 @@ typedef struct q3entityState_s { int event; // impulse events -- muzzle flashes, footsteps, etc int eventParm; + // for players int powerups; // bit flags int weapon; // determines weapon and flash model, etc @@ -162,6 +156,7 @@ typedef struct q3entityState_s { #define MAX_MAP_AREA_BYTES 32 #define MAX_ENTITIES_IN_SNAPSHOT 256 +//This struct is exposed to the cgame typedef struct snapshot_s { int snapFlags; // SNAPFLAG_RATE_DELAYED, etc int ping; @@ -182,9 +177,7 @@ typedef struct snapshot_s { -// -// clientSnap_t is will be converted to snapshot_t for internal cgame use -// +//this struct is used internally, using a ringbuffer for entities instead of worst-case memory usage. typedef struct clientSnap_s { qboolean valid; // cleared if delta parsing was invalid int snapFlags; @@ -220,32 +213,45 @@ typedef struct { #define Q3MAX_PARSE_ENTITIES 2048 #define Q3PARSE_ENTITIES_MASK (Q3MAX_PARSE_ENTITIES-1) +#define MAX_Q3_GAMESTATE_CHARS 16000 #define MAX_STRING_CHARS 1024 -#define Q3TEXTCMD_BACKUP 64 //number of reliable text commands that can be queued, must be power of two + #define MAX_Q3_CONFIGSTRINGS 1024 + #define Q3TEXTCMD_BACKUP 64 //number of reliable text commands that can be queued, must be power of two #define Q3TEXTCMD_MASK (Q3TEXTCMD_BACKUP-1) -#define MAX_Q3_CONFIGSTRINGS 1024 #define CFGSTR_SYSINFO 1 + #define MODELINDEX_BITS 8 #define GENTITYNUM_BITS 10 #define MAX_GENTITIES (1<name, "player")) - { - ent.bottomcolour = genhsv(realtime*0.1 + 0, 1, 1); - ent.topcolour = genhsv(realtime*0.1 + 0.5, 1, 1); - } - else*/ - { - ent.topcolour = TOP_DEFAULT; - ent.bottomcolour = BOTTOM_DEFAULT; - } + ent.topcolour = TOP_DEFAULT; + ent.bottomcolour = BOTTOM_DEFAULT; // ent.fatness = sin(realtime)*5; ent.playerindex = -1; ent.skinnum = 0; ent.shaderTime = 0;//realtime; ent.framestate.g[FS_REG].lerpweight[0] = 1; -// ent.framestate.g[FS_REG].frame[0] = animationnum; ent.framestate.g[FS_REG].frametime[0] = ent.framestate.g[FS_REG].frametime[1] = realtime; ent.framestate.g[FS_REG].endbone = 0x7fffffff; -// ent.customskin = Mod_RegisterSkinFile(va("%s_0.skin", mods->modelname)); + ent.customskin = Mod_RegisterSkinFile(va("%s_0.skin", model->publicname)); + if (ent.customskin == 0) + { + char haxxor[MAX_QPATH]; + COM_StripExtension(model->publicname, haxxor, sizeof(haxxor)); + ent.customskin = Mod_RegisterSkinFile(va("%s_default.skin", haxxor)); + } Vector4Set(ent.shaderRGBAf, 1,1,1,1); VectorSet(ent.glowmod, 1,1,1); diff --git a/engine/client/fragstats.c b/engine/client/fragstats.c index 91b1b7e0..4e894b52 100644 --- a/engine/client/fragstats.c +++ b/engine/client/fragstats.c @@ -839,4 +839,4 @@ void Stats_NewMap(void) { Stats_LoadFragFile("fragfile"); } -#endif \ No newline at end of file +#endif diff --git a/engine/client/keys.c b/engine/client/keys.c index 7408039f..bd7c8340 100644 --- a/engine/client/keys.c +++ b/engine/client/keys.c @@ -50,7 +50,6 @@ qbyte bindcmdlevel[K_MAX][KEY_MODIFIERSTATES]; //should be a struct, but not due qboolean consolekeys[K_MAX]; // if true, can't be rebound while in console int keyshift[K_MAX]; // key to map to if shift held down in console unsigned int keydown[K_MAX]; // bitmask, for each device (to block autorepeat binds per-seat). -//unsigned int key_modifier[K_MAX]; #define MAX_INDEVS 8 @@ -273,6 +272,8 @@ keyname_t keynames[] = {"PLUS", '+'}, // because "shift++" is inferior to shift+plus {"MINUS", '-'}, // because "shift+-" is inferior to shift+minus + {"APOSTROPHE", '\''}, //can mess up string parsing, unfortunately + {"QUOTES", '\"'}, //can mess up string parsing, unfortunately {"TILDE", '~'}, {"BACKQUOTE", '`'}, {"BACKSLASH", '\\'}, @@ -2845,32 +2846,6 @@ void Key_Init (void) consolekeys[K_MWHEELUP] = true; consolekeys[K_MWHEELDOWN] = true; - for (i=0 ; icg.KeyPressed(key, unicode, down)) return; #endif } diff --git a/engine/client/m_download.c b/engine/client/m_download.c index 875d5299..6c88684a 100644 --- a/engine/client/m_download.c +++ b/engine/client/m_download.c @@ -32,9 +32,9 @@ static char enginerevision[256] = STRINGIFY(SVNREVISION); #ifdef ENABLEPLUGINSBYDEFAULT -cvar_t pkg_autoupdate = CVARFD("pkg_autoupdate", "1", CVAR_NOTFROMSERVER|CVAR_NOSAVE|CVAR_NOSET, "Controls autoupdates, can only be changed via the downloads menu.\n0: off.\n1: enabled (stable only).\n2: enabled (unstable).\nNote that autoupdate will still prompt the user to actually apply the changes."); //read from the package list only. +cvar_t pkg_autoupdate = CVARFD("pkg_autoupdate", "1", CVAR_NOTFROMSERVER|CVAR_NOSAVE|CVAR_NOSET|CVAR_NORESET, "Controls autoupdates, can only be changed via the downloads menu.\n0: off.\n1: enabled (stable only).\n2: enabled (unstable).\nNote that autoupdate will still prompt the user to actually apply the changes."); //read from the package list only. #else -cvar_t pkg_autoupdate = CVARFD("pkg_autoupdate", "-1", CVAR_NOTFROMSERVER|CVAR_NOSAVE|CVAR_NOSET, "Controls autoupdates, can only be changed via the downloads menu.\n0: off.\n1: enabled (stable only).\n2: enabled (unstable).\nNote that autoupdate will still prompt the user to actually apply the changes."); //read from the package list only. +cvar_t pkg_autoupdate = CVARFD("pkg_autoupdate", "-1", CVAR_NOTFROMSERVER|CVAR_NOSAVE|CVAR_NOSET|CVAR_NORESET, "Controls autoupdates, can only be changed via the downloads menu.\n0: off.\n1: enabled (stable only).\n2: enabled (unstable).\nNote that autoupdate will still prompt the user to actually apply the changes."); //read from the package list only. #endif #define INSTALLEDFILES "installed.lst" //the file that resides in the quakedir (saying what's installed). @@ -198,6 +198,8 @@ static char *manifestpackages; //metapackage named by the manicfest. static char *declinedpackages; //metapackage named by the manicfest. static int domanifestinstall; //SECURITY_MANIFEST_* +static int pluginsadded; //so we only show prompts for new externally-installed plugins once, instead of every time the file is reloaded. + #ifdef WEBCLIENT static struct { @@ -1638,8 +1640,19 @@ static qboolean PM_ParsePackageList(const char *f, unsigned int parseflags, cons return forcewrite; } +static qboolean PM_NameIsInStrings(const char *strings, const char *match) +{ + char tok[1024]; + while (strings && *strings) + { + strings = COM_ParseStringSetSep(strings, ';', tok, sizeof(tok)); + if (!Q_strcasecmp(tok, match)) //okay its here. + return true; + } + return false; +} #ifdef PLUGINS -void PM_EnumeratePlugins(void (*callback)(const char *name)) +void PM_EnumeratePlugins(void (*callback)(const char *name, qboolean blocked)) { package_t *p; struct packagedep_s *d; @@ -1655,7 +1668,10 @@ void PM_EnumeratePlugins(void (*callback)(const char *name)) if (d->dtype == DEP_FILE) { if (!Q_strncasecmp(d->name, PLUGINPREFIX, strlen(PLUGINPREFIX))) - callback(d->name); + { + qboolean blocked = PM_NameIsInStrings(manifestpackages, va("!%s", p->name)); + callback(d->name, blocked); + } } } } @@ -2050,20 +2066,10 @@ static void PM_PreparePackageList(void) #ifdef PLUGINS { - int foundone = false; char nat[MAX_OSPATH]; FS_NativePath("", FS_BINARYPATH, nat, sizeof(nat)); Con_DPrintf("Loading plugins from \"%s\"\n", nat); - Sys_EnumerateFiles(nat, PLUGINPREFIX"*" ARCH_DL_POSTFIX, PM_EnumeratedPlugin, &foundone, NULL); -#ifndef ENABLEPLUGINSBYDEFAULT - if (foundone && !pluginpromptshown) - { - pluginpromptshown = true; -#ifndef SERVERONLY - Menu_Prompt(PM_PluginDetected, NULL, "Plugin(s) appears to have\nbeen installed externally.\nUse the updates menu\nto enable them.", "View", "Disable", "Later..."); -#endif - } -#endif + Sys_EnumerateFiles(nat, PLUGINPREFIX"*" ARCH_DL_POSTFIX, PM_EnumeratedPlugin, &pluginsadded, NULL); } #endif } @@ -2462,18 +2468,6 @@ static qboolean PM_MarkPackage(package_t *package, unsigned int markflag) return true; } -static qboolean PM_NameIsInStrings(const char *strings, const char *match) -{ - char tok[1024]; - while (strings && *strings) - { - strings = COM_ParseStringSetSep(strings, ';', tok, sizeof(tok)); - if (!Q_strcasecmp(tok, match)) //okay its here. - return true; - } - return false; -} - //just flag stuff as needing updating unsigned int PM_MarkUpdates (void) { @@ -2491,13 +2485,14 @@ unsigned int PM_MarkUpdates (void) char *strings = manifestpackages; while (strings && *strings) { - strings = COM_ParseStringSetSep(strings, ';', tok, sizeof(tok)); - if (PM_NameIsInStrings(declinedpackages, tok)) - continue; + qboolean isunwanted = (*tok=='!'); + strings = COM_ParseStringSetSep(strings, ';', tok+isunwanted, sizeof(tok)); p = PM_MarkedPackage(tok, DPF_MARKED); if (!p) { + if (PM_NameIsInStrings(declinedpackages, tok)) + continue; p = PM_FindPackage(tok); if (p) { @@ -2505,6 +2500,11 @@ unsigned int PM_MarkUpdates (void) changecount++; } } + else if (isunwanted) + { + PM_UnmarkPackage(p, DPF_AUTOMARKED); //try and unmark it. + changecount++; + } else if (!(p->flags & DPF_ENABLED)) changecount++; } @@ -2685,6 +2685,7 @@ static void PM_ListDownloaded(struct dl_download *dl) if (f) { pm_source[listidx].status = SRCSTAT_OBTAINED; + downloadablessequence++; if (pm_source[listidx].flags & SRCFL_UNSAFE) PM_ParsePackageList(f, DPF_SIGNATUREACCEPTED, dl->url, pm_source[listidx].prefix); else @@ -2837,7 +2838,7 @@ static void PM_UpdatePackageList(qboolean autoupdate, int retry) else if (allowphonehome == -1) { if (retry) - Menu_Prompt(PM_AllowPackageListQuery_Callback, NULL, "Query updates list?\n", "Okay", NULL, "Nope"); + Menu_Prompt(PM_AllowPackageListQuery_Callback, NULL, "Query updates list?\n", "Okay", NULL, "Nope", true); return; } #else @@ -2888,6 +2889,7 @@ static void PM_UpdatePackageList(qboolean autoupdate, int retry) } } } +#endif if (autoupdate) { @@ -2902,7 +2904,6 @@ static void PM_UpdatePackageList(qboolean autoupdate, int retry) PM_PrintChanges(); } } -#endif } qboolean PM_RegisterUpdateSource(void *module, plugupdatesourcefuncs_t *funcs) @@ -3304,16 +3305,16 @@ static void PM_PackageEnabled(package_t *p) } #ifndef HAVE_CLIENT -#define Menu_Prompt(cb,ctx,msg,yes,no,cancel) Con_Printf(CON_WARNING msg "\n") +#define Menu_Prompt(cb,ctx,msg,yes,no,cancel,highpri) Con_Printf(CON_WARNING msg "\n") #endif if (FS_NativePath(ef->name, p->fsroot, native, sizeof(native)) && Sys_SetUpdatedBinary(native)) { Q_strncpyz(enginerevision, p->version, sizeof(enginerevision)); //make sure 'revert' picks up the new binary... - Menu_Prompt(NULL, NULL, "Engine binary updated.\nRestart to use.", NULL, NULL, NULL); + Menu_Prompt(NULL, NULL, "Engine binary updated.\nRestart to use.", NULL, NULL, NULL, true); } else - Menu_Prompt(NULL, NULL, "Engine update failed.\nManual update required.", NULL, NULL, NULL); + Menu_Prompt(NULL, NULL, "Engine update failed.\nManual update required.", NULL, NULL, NULL, true); } #endif } @@ -4381,7 +4382,7 @@ static void PM_PromptApplyChanges(void) //lock it down, so noone can make any changes while this prompt is still displayed if (pkg_updating) { - Menu_Prompt(PM_PromptApplyChanges_Callback, NULL, "An update is already in progress\nPlease wait\n", NULL, NULL, "Cancel"); + Menu_Prompt(PM_PromptApplyChanges_Callback, NULL, "An update is already in progress\nPlease wait\n", NULL, NULL, "Cancel", true); return; } pkg_updating = true; @@ -4389,7 +4390,7 @@ static void PM_PromptApplyChanges(void) strcpy(text, "Really decline the following\nrecommended packages?\n\n"); if (PM_DeclinedPackages(text+strlen(text), sizeof(text)-strlen(text))) - Menu_Prompt(PM_PromptApplyDecline_Callback, NULL, text, NULL, "Confirm", "Cancel"); + Menu_Prompt(PM_PromptApplyDecline_Callback, NULL, text, NULL, "Confirm", "Cancel", true); else { strcpy(text, "Apply the following changes?\n\n"); @@ -4401,7 +4402,7 @@ static void PM_PromptApplyChanges(void) #endif } else - Menu_Prompt(PM_PromptApplyChanges_Callback, NULL, text, "Apply", NULL, "Cancel"); + Menu_Prompt(PM_PromptApplyChanges_Callback, NULL, text, "Apply", NULL, "Cancel", true); } } #endif @@ -4499,7 +4500,7 @@ void PM_Command_f(void) else { #ifdef HAVE_CLIENT - Menu_Prompt(PM_AddSubList_Callback, Z_StrDup(Cmd_Argv(2)), va("Add updates source?\n%s", Cmd_Argv(2)), "Confirm", NULL, "Cancel"); + Menu_Prompt(PM_AddSubList_Callback, Z_StrDup(Cmd_Argv(2)), va("Add updates source?\n%s", Cmd_Argv(2)), "Confirm", NULL, "Cancel", true); #else PM_AddSubList(Cmd_Argv(2), "", SRCFL_USER|SRCFL_ENABLED); PM_WriteInstalledPackages(); @@ -5176,7 +5177,7 @@ qboolean PM_CanInstall(const char *packagename) { return false; } -void PM_EnumeratePlugins(void (*callback)(const char *name)) +void PM_EnumeratePlugins(void (*callback)(const char *name, qboolean blocked)) { } void PM_ManifestPackage(const char *metaname, int security) @@ -5215,6 +5216,15 @@ static void MD_Draw (int x, int y, struct menucustom_s *c, struct emenu_s *m) if (c->dint != downloadablessequence) return; //probably stale + + if (allowphonehome == -2) + { + allowphonehome = false; +#ifdef HAVE_CLIENT + Menu_Prompt(PM_AllowPackageListQuery_Callback, NULL, "Query updates list?\n", "Okay", NULL, "Nope", true); +#endif + } + p = c->dptr; if (p) { @@ -5251,16 +5261,16 @@ static void MD_Draw (int x, int y, struct menucustom_s *c, struct emenu_s *m) if (!(p->flags & DPF_ENABLED)) { //DPF_MARKED|!DPF_ENABLED: if (p->flags & DPF_PURGE) - Draw_FunStringWidth (x, y, "GET", 48, 2, false); + Draw_FunStringWidth (x, y, S_COLOR_GREEN"GET", 48, 2, false); else if (p->flags & (DPF_PRESENT)) - Draw_FunStringWidth (x, y, "USE", 48, 2, false); + Draw_FunStringWidth (x, y, S_COLOR_GREEN"USE", 48, 2, false); else - Draw_FunStringWidth (x, y, "GET", 48, 2, false); + Draw_FunStringWidth (x, y, S_COLOR_GREEN"GET", 48, 2, false); } else { //DPF_MARKED|DPF_ENABLED: if (p->flags & DPF_PURGE) - Draw_FunStringWidth (x, y, "GET", 48, 2, false); //purge and reinstall. + Draw_FunStringWidth (x, y, S_COLOR_GREEN"GET", 48, 2, false); //purge and reinstall. else if (p->flags & DPF_CORRUPT) Draw_FunStringWidth (x, y, "?""?""?", 48, 2, false); else @@ -5272,20 +5282,20 @@ static void MD_Draw (int x, int y, struct menucustom_s *c, struct emenu_s *m) } } else if (p->flags & DPF_MARKED) - { + { //auto-use options. draw with half alpha to darken them a little. if (!(p->flags & DPF_ENABLED)) { //DPF_MARKED|!DPF_ENABLED: if (p->flags & DPF_PURGE) - Draw_FunStringWidth (x, y, "^hGET", 48, 2, false); + Draw_FunStringWidth (x, y, S_COLOR_GREEN"^hGET", 48, 2, false); else if (p->flags & (DPF_PRESENT)) - Draw_FunStringWidth (x, y, "^hUSE", 48, 2, false); + Draw_FunStringWidth (x, y, S_COLOR_GREEN"^hUSE", 48, 2, false); else - Draw_FunStringWidth (x, y, "^hGET", 48, 2, false); + Draw_FunStringWidth (x, y, S_COLOR_GREEN"^hGET", 48, 2, false); } else { //DPF_MARKED|DPF_ENABLED: if (p->flags & DPF_PURGE) - Draw_FunStringWidth (x, y, "^hGET", 48, 2, false); //purge and reinstall. + Draw_FunStringWidth (x, y, S_COLOR_GREEN"^hGET", 48, 2, false); //purge and reinstall. else if (p->flags & DPF_CORRUPT) Draw_FunStringWidth (x, y, "?""?""?", 48, 2, false); else @@ -5301,7 +5311,7 @@ static void MD_Draw (int x, int y, struct menucustom_s *c, struct emenu_s *m) if (!(p->flags & DPF_ENABLED)) { //!DPF_MARKED|!DPF_ENABLED: if (p->flags & DPF_PURGE) - Draw_FunStringWidth (x, y, "DEL", 48, 2, false); //purge + Draw_FunStringWidth (x, y, S_COLOR_RED"DEL", 48, 2, false); //purge else if (p->flags & DPF_HIDDEN) Draw_FunStringWidth (x, y, "---", 48, 2, false); else if (p->flags & DPF_CORRUPT) @@ -5322,9 +5332,9 @@ static void MD_Draw (int x, int y, struct menucustom_s *c, struct emenu_s *m) else { //!DPF_MARKED|DPF_ENABLED: if ((p->flags & DPF_PURGE) || PM_PurgeOnDisable(p)) - Draw_FunStringWidth (x, y, "DEL", 48, 2, false); + Draw_FunStringWidth (x, y, S_COLOR_RED"DEL", 48, 2, false); else - Draw_FunStringWidth (x, y, "DIS", 48, 2, false); + Draw_FunStringWidth (x, y, S_COLOR_YELLOW"DIS", 48, 2, false); } } } @@ -6007,22 +6017,28 @@ static void MD_Download_UpdateStatus(struct emenu_s *m) b->rightalign = false; y+=8; #ifdef WEBCLIENT - b = MC_AddCommand(m, 48, 320-16, y, "Mark Updates", MD_MarkUpdatesButton); - b->rightalign = false; - b->common.tooltip = "Select any updated versions of packages that are already installed."; - y+=8; + if (pm_numsources) + { + b = MC_AddCommand(m, 48, 320-16, y, "Mark Updates", MD_MarkUpdatesButton); + b->rightalign = false; + b->common.tooltip = "Select any updated versions of packages that are already installed."; + y+=8; + } #endif - b = MC_AddCommand(m, 48, 320-16, y, "Revert Updates", MD_RevertUpdates); + b = MC_AddCommand(m, 48, 320-16, y, "Undo Changes", MD_RevertUpdates); b->rightalign = false; b->common.tooltip = "Reset selection to only those packages that are currently installed."; y+=8; #ifdef WEBCLIENT - c = MC_AddCustom(m, 48, y, p, 0, NULL); - c->draw = MD_AutoUpdate_Draw; - c->key = MD_AutoUpdate_Key; - c->common.width = 320-48-16; - c->common.height = 8; - y += 8; + if (pm_numsources) + { + c = MC_AddCustom(m, 48, y, p, 0, NULL); + c->draw = MD_AutoUpdate_Draw; + c->key = MD_AutoUpdate_Key; + c->common.width = 320-48-16; + c->common.height = 8; + y += 8; + } #endif y+=4; //small gap MC_AddBufferedText(m, 48, 320-16, y, "Packages", false, true), y += 8; @@ -6148,7 +6164,7 @@ qboolean PM_AreSourcesNew(qboolean doprompt) if (doprompt) { const char *msg = va("Enable update source\n\n^x66F%s", (pm_source[i].flags&SRCFL_MANIFEST)?PrettyHostFromURL(pm_source[i].url):pm_source[i].url); - Menu_Prompt(PM_ConfirmSource, Z_StrDup(pm_source[i].url), msg, "Enable", "Configure", "Later"); + Menu_Prompt(PM_ConfirmSource, Z_StrDup(pm_source[i].url), msg, "Enable", "Configure", "Later", true); pm_source[i].flags |= SRCFL_PROMPTED; } break; @@ -6157,7 +6173,7 @@ qboolean PM_AreSourcesNew(qboolean doprompt) /*if (!pluginpromptshown && i < pm_numsources) { pluginpromptshown = true; - Menu_Prompt(PM_AutoUpdateQuery, NULL, "Configure update sources now?", "View", NULL, "Later"); + Menu_Prompt(PM_AutoUpdateQuery, NULL, "Configure update sources now?", "View", NULL, "Later", true); }*/ } #endif diff --git a/engine/client/m_items.c b/engine/client/m_items.c index e2c86872..75f6284b 100644 --- a/engine/client/m_items.c +++ b/engine/client/m_items.c @@ -2587,7 +2587,7 @@ void M_Menu_Main_f (void) if (!mainm) { mainm = M_CreateMenu(0); - MC_AddRedText(mainm, 16, 170, 0, "MAIN MENU", false); + MC_AddRedText(mainm, 72, 320, 0, "Main Menu", false); y = 36; mainm->selecteditem = (menuoption_t *) diff --git a/engine/client/m_master.c b/engine/client/m_master.c index 7e07ca10..8c62a2c1 100644 --- a/engine/client/m_master.c +++ b/engine/client/m_master.c @@ -292,7 +292,7 @@ static void SL_ServerDraw (int x, int y, menucustom_t *ths, emenu_t *menu) servertypes_t stype; char adr[MAX_ADR_SIZE]; - if (sb_filtertext.modified != info->filtermodcount) + if (sb_filtertext.modifiedcount != info->filtermodcount) CalcFilters(menu); si = Master_SortedServer(thisone); @@ -1097,7 +1097,7 @@ static qboolean SL_SliderKey (menucustom_t *ths, emenu_t *menu, int key, unsigne static void CalcFilters(emenu_t *menu) { serverlist_t *info = (serverlist_t*)(menu + 1); - info->filtermodcount = sb_filtertext.modified; + info->filtermodcount = sb_filtertext.modifiedcount; Master_ClearMasks(); diff --git a/engine/client/m_mp3.c b/engine/client/m_mp3.c index 38aeac3b..3749c2da 100644 --- a/engine/client/m_mp3.c +++ b/engine/client/m_mp3.c @@ -2181,6 +2181,12 @@ static void Media_Roq_Shutdown(struct cin_s *cin) cin->roq.roqfilm=NULL; } +static void Media_Roq_Rewind(struct cin_s *cin) +{ + roq_rewind(cin->roq.roqfilm); + cin->roq.nextframetime = 0; +} + static qboolean Media_Roq_DecodeFrame (cin_t *cin, qboolean nosound, qboolean forcevideo, double mediatime, void (QDECL *uploadtexture)(void *ctx, uploadfmt_t fmt, int width, int height, void *data, void *palette), void *ctx) { qboolean doupdate = forcevideo; @@ -2296,6 +2302,7 @@ static cin_t *Media_RoQ_TryLoad(char *name) { cin = Z_Malloc(sizeof(cin_t)); cin->decodeframe = Media_Roq_DecodeFrame; + cin->rewind = Media_Roq_Rewind; cin->shutdown = Media_Roq_Shutdown; cin->getsize = Media_Roq_GetSize; diff --git a/engine/client/m_native.c b/engine/client/m_native.c index b69ce594..4627c787 100644 --- a/engine/client/m_native.c +++ b/engine/client/m_native.c @@ -463,7 +463,7 @@ qboolean MN_Init(void) while(COM_IteratePaths(&iterator, syspath, sizeof(syspath), gamepath, sizeof(gamepath))) { - if (!com_nogamedirnativecode.ival) + if (com_gamedirnativecode.ival) libmenu = Sys_LoadLibrary(va("%smenu_"ARCH_CPU_POSTFIX ARCH_DL_POSTFIX, syspath), funcs); if (libmenu) break; diff --git a/engine/client/m_options.c b/engine/client/m_options.c index 5aee6503..fe2cd419 100644 --- a/engine/client/m_options.c +++ b/engine/client/m_options.c @@ -3317,7 +3317,7 @@ typedef struct float dist; char modelname[MAX_QPATH]; - char forceshader[MAX_QPATH]; + char skinname[MAX_QPATH]; char shaderfile[MAX_QPATH]; char *shadertext; @@ -3528,7 +3528,18 @@ static void M_ModelViewerDraw(int x, int y, struct menucustom_s *c, struct emenu ent.framestate.g[FS_REG].frame[0] = mods->framegroup; ent.framestate.g[FS_REG].frametime[0] = ent.framestate.g[FS_REG].frametime[1] = realtime - mods->framechangetime; ent.framestate.g[FS_REG].endbone = 0x7fffffff; - ent.customskin = Mod_RegisterSkinFile(va("%s_%i.skin", mods->modelname, ent.skinnum)); + if (*mods->skinname) + ent.customskin = Mod_RegisterSkinFile(mods->skinname); //explicit .skin file to use + else + { + ent.customskin = Mod_RegisterSkinFile(va("%s_%i.skin", mods->modelname, ent.skinnum)); + if (ent.customskin == 0) + { + char haxxor[MAX_QPATH]; + COM_StripExtension(mods->modelname, haxxor, sizeof(haxxor)); + ent.customskin = Mod_RegisterSkinFile(va("%s_default.skin", haxxor)); //fall back to some default + } + } skin = Mod_LookupSkin(ent.customskin); ent.light_avg[0] = ent.light_avg[1] = ent.light_avg[2] = 0.66; @@ -4242,7 +4253,7 @@ void M_Menu_ModelViewer_f(void) mv->yaw = 180;// + crandom()*45; mv->dist = 150; Q_strncpyz(mv->modelname, Cmd_Argv(1), sizeof(mv->modelname)); - Q_strncpyz(mv->forceshader, Cmd_Argv(2), sizeof(mv->forceshader)); + Q_strncpyz(mv->skinname, Cmd_Argv(2), sizeof(mv->skinname)); mv->framechangetime = realtime; mv->skinchangetime = realtime; diff --git a/engine/client/menu.c b/engine/client/menu.c index cdddf4b1..e9f25194 100644 --- a/engine/client/menu.c +++ b/engine/client/menu.c @@ -107,16 +107,12 @@ void Menu_Push(menu_t *menu, qboolean prompt) { if (!Menu_IsLinked(menu)) { //only link once. - if (prompt) - { - menu->prev = promptmenu; - promptmenu = menu; - } - else - { - menu->prev = topmenu; - topmenu = menu; - } + //annoying logic so that persistent menus always appear on top of other stuff. + menu_t **prev = prompt?&promptmenu:&topmenu; + while (menu->lowpriority && *prev && !(*prev)->lowpriority) + prev = &(*prev)->prev; + menu->prev = *prev; + *prev = menu; } if (menu == promptmenu) { @@ -383,7 +379,7 @@ void M_ToggleMenu_f (void) } #endif #ifdef VM_UI - if (UI_OpenMenu()) + if (q3 && q3->ui.OpenMenu()) return; #endif @@ -410,6 +406,12 @@ void M_Restart_f(void) } else M_Reinit(); + + //start up the ui now we have a renderer +#ifdef VM_UI + if (q3) + q3->ui.Start(); +#endif } @@ -594,7 +596,7 @@ static void Prompt_Release(struct menu_s *gm, qboolean forced) callback(ctx, PROMPT_CANCEL); Z_Free(m); } -void Menu_Prompt (void (*callback)(void *, promptbutton_t), void *ctx, const char *messages, const char *optionyes, const char *optionno, const char *optioncancel) +void Menu_Prompt (void (*callback)(void *, promptbutton_t), void *ctx, const char *messages, const char *optionyes, const char *optionno, const char *optioncancel, qboolean highpri) { promptmenu_t *m; char *t; @@ -617,7 +619,8 @@ void Menu_Prompt (void (*callback)(void *, promptbutton_t), void *ctx, const cha m->m.release = Prompt_Release; m->mbutton = -1; m->kbutton = -1; - Menu_Push(&m->m, true); + m->m.persist = true; + Menu_Push(&m->m, highpri); m->callback = callback; m->ctx = ctx; @@ -1267,10 +1270,10 @@ void M_Menu_Quit_f (void) #endif break; case 2: - Menu_Prompt (M_Menu_DoQuitSave, NULL, "You have unsaved settings\nWould you like to\nsave them now?", "Yes", "No", "Cancel"); + Menu_Prompt (M_Menu_DoQuitSave, NULL, "You have unsaved settings\nWould you like to\nsave them now?", "Yes", "No", "Cancel", true); break; case 1: - Menu_Prompt (M_Menu_DoQuit, NULL, quitMessage[rand()%countof(quitMessage)], "Quit", NULL, "Cancel"); + Menu_Prompt (M_Menu_DoQuit, NULL, quitMessage[rand()%countof(quitMessage)], "Quit", NULL, "Cancel", true); break; } } @@ -1278,7 +1281,7 @@ void M_Menu_Quit_f (void) #ifdef HAVE_LEGACY void M_Menu_Credits_f (void) { - Menu_Prompt (NULL, NULL, "That's all folks!\nTry a different mod now.", NULL, NULL, "Sure!"); + Menu_Prompt (NULL, NULL, "That's all folks!\nTry a different mod now.", NULL, NULL, "Sure!", false); } #endif diff --git a/engine/client/menu.h b/engine/client/menu.h index bd6d22c6..e853c4c5 100644 --- a/engine/client/menu.h +++ b/engine/client/menu.h @@ -108,6 +108,7 @@ typedef struct menu_s { qboolean (*joyaxis) (struct menu_s *, unsigned int devid, int axis, float val); void (*drawmenu) (struct menu_s *); struct key_cursor_s *cursor; //NULL for relative motion + qboolean lowpriority; //appears underneath other menus. qboolean isopaque; //guarentees an opaque background qboolean persist; //try really hard to not kill this. } menu_t; @@ -128,7 +129,7 @@ typedef enum PROMPT_NO = 1, PROMPT_CANCEL = -1, } promptbutton_t; -void Menu_Prompt (void (*callback)(void *, promptbutton_t), void *ctx, const char *messages, const char *optionyes, const char *optionno, const char *optioncancel); +void Menu_Prompt (void (*callback)(void *, promptbutton_t), void *ctx, const char *messages, const char *optionyes, const char *optionno, const char *optioncancel, qboolean highpri); #ifndef NOBUILTINMENUS @@ -560,4 +561,4 @@ void Plug_FreeAllImages(void); #else #define PLUGINPREFIX "fteplug_" //this string defines what consitutes a plugin, as opposed to some other dll #endif -#endif \ No newline at end of file +#endif diff --git a/engine/client/merged.h b/engine/client/merged.h index 8f9fc568..b62c0c14 100644 --- a/engine/client/merged.h +++ b/engine/client/merged.h @@ -169,6 +169,7 @@ enum mod_purge_e enum mlverbosity_e { MLV_SILENT, + MLV_SILENTSYNC, MLV_WARN, MLV_WARNSYNC, MLV_ERROR @@ -202,7 +203,7 @@ extern int Mod_GetFrameCount (struct model_s *model); #undef FNC extern qboolean Mod_GetTag (struct model_s *model, int tagnum, framestate_t *framestate, float *transforms); -extern int Mod_TagNumForName (struct model_s *model, const char *name); +extern int Mod_TagNumForName (struct model_s *model, const char *name, int firsttag); void Mod_AddSingleSurface(struct entity_s *ent, int surfaceidx, shader_t *shader, int mode); int Mod_GetNumBones(struct model_s *model, qboolean allowtags); diff --git a/engine/client/net_master.c b/engine/client/net_master.c index 2ab74c74..e99c63dc 100644 --- a/engine/client/net_master.c +++ b/engine/client/net_master.c @@ -1354,13 +1354,13 @@ int Master_NumSorted(void) } -float Master_ReadKeyFloat(serverinfo_t *server, hostcachekey_t keynum) +float Master_ReadKeyFloat(serverinfo_t *server, unsigned int keynum) { if (!server) return -1; else if (keynum < SLKEY_CUSTOM) { - switch(keynum) + switch((hostcachekey_t)keynum) { case SLKEY_PING: return server->ping; @@ -1416,7 +1416,7 @@ void Master_DecodeColour(vec3_t ret, int col) VectorSet(ret, ((col&0xff0000)>>16)/255.0, ((col&0x00ff00)>>8)/255.0, ((col&0x0000ff)>>0)/255.0); } -char *Master_ReadKeyString(serverinfo_t *server, hostcachekey_t keynum) +char *Master_ReadKeyString(serverinfo_t *server, unsigned int keynum) { static char adr[MAX_ADR_SIZE]; @@ -1459,7 +1459,7 @@ char *Master_ReadKeyString(serverinfo_t *server, hostcachekey_t keynum) } else { - switch(keynum) + switch((hostcachekey_t)keynum) { case SLKEY_MAP: return server->map; @@ -2225,10 +2225,10 @@ void Master_CheckPollSockets(void) int c; char *s; - MSG_BeginReading (msg_nullnetprim); + MSG_BeginReading (&net_message, msg_nullnetprim); MSG_ReadLong (); // skip the -1 - c = msg_readcount; + c = net_message.currentbit; s = MSG_ReadStringLine(); //peek for q2 messages. #ifdef Q2CLIENT if (!strcmp(s, "print")) @@ -2244,14 +2244,14 @@ void Master_CheckPollSockets(void) #ifdef HAVE_IPV6 if (!strncmp(s, "server6", 7)) //parse a bit more... { - msg_readcount = c+7; + net_message.currentbit = (c+7)<<3; CL_MasterListParse(NA_IPV6, SS_QUAKE2, false); continue; } #endif if (!strncmp(s, "servers", 7)) //parse a bit more... { - msg_readcount = c+7; + net_message.currentbit = (c+7)<<3; CL_MasterListParse(NA_IP, SS_QUAKE2, false); continue; } @@ -2267,20 +2267,20 @@ void Master_CheckPollSockets(void) #ifdef HAVE_IPV6 if (!strncmp(s, "getserversResponse6", 19) && (s[19] == '\\' || s[19] == '/')) //parse a bit more... { - msg_readcount = c+19-1; + net_message.currentbit = (c+19-1)<<3; CL_MasterListParse(NA_IPV6, SS_DARKPLACES, true); continue; } #endif if (!strncmp(s, "getserversExtResponse", 21) && (s[21] == '\\' || s[21] == '/')) //parse a bit more... { - msg_readcount = c+21-1; + net_message.currentbit = (c+21-1)<<3; CL_MasterListParse(NA_IP, SS_DARKPLACES, true); continue; } if (!strncmp(s, "getserversResponse", 18) && (s[18] == '\\' || s[18] == '/')) //parse a bit more... { - msg_readcount = c+18-1; + net_message.currentbit = (c+18-1)<<3; CL_MasterListParse(NA_IP, SS_DARKPLACES, true); continue; } @@ -2293,13 +2293,13 @@ void Master_CheckPollSockets(void) #ifdef HAVE_IPV6 if (!strncmp(s, "qw_slist6\\", 10)) //parse a bit more... { - msg_readcount = c+9-1; + net_message.currentbit = (c+9-1)<<3; CL_MasterListParse(NA_IPV6, SS_QUAKEWORLD, false); continue; } #endif - msg_readcount = c; + net_message.currentbit = c; c = MSG_ReadByte (); @@ -2325,7 +2325,7 @@ void Master_CheckPollSockets(void) int control; int ccrep; - MSG_BeginReading (msg_nullnetprim); + MSG_BeginReading (&net_message, msg_nullnetprim); control = BigLong(*((int *)net_message.data)); MSG_ReadLong(); if (control == -1) @@ -3578,7 +3578,7 @@ void CL_MasterListParse(netadrtype_t adrtype, int type, qboolean slashpad) last = firstserver; - while(msg_readcount+1+2 < net_message.cursize) + while((net_message.currentbit>>3)+1+2 < net_message.cursize) { if (slashpad) { diff --git a/engine/client/pr_csqc.c b/engine/client/pr_csqc.c index 7d5f61c6..15677922 100644 --- a/engine/client/pr_csqc.c +++ b/engine/client/pr_csqc.c @@ -2748,7 +2748,7 @@ static void QCBUILTIN PF_R_RenderScene(pubprogfuncs_t *prinst, struct globalvars csqc_worldchanged = false; cl.worldmodel = r_worldentity.model = csqc_world.worldmodel; FS_LoadMapPackFile(cl.worldmodel->name, cl.worldmodel->archive); - Surf_NewMap(); + Surf_NewMap(csqc_world.worldmodel); CL_UpdateWindowTitle(); World_RBE_Shutdown(&csqc_world); diff --git a/engine/client/pr_skelobj.c b/engine/client/pr_skelobj.c index e8544469..5d6ac9d0 100644 --- a/engine/client/pr_skelobj.c +++ b/engine/client/pr_skelobj.c @@ -380,7 +380,7 @@ static qboolean rag_dollline(dollcreatectx_t *ctx, int linenum) //create a new body else if (argc == 3 && !stricmp(cmd, "body")) { - int boneidx = Mod_TagNumForName(d->model, Cmd_Argv(2))-1; + int boneidx = Mod_TagNumForName(d->model, Cmd_Argv(2), 0)-1; ctx->joint = NULL; ctx->body = NULL; if (boneidx >= 0) @@ -576,7 +576,7 @@ static qboolean rag_dollline(dollcreatectx_t *ctx, int linenum) //the origin is specified in base-frame model space //we need to make it relative to the joint's bodies char *bone = val; - i = Mod_TagNumForName(d->model, bone)-1; + i = Mod_TagNumForName(d->model, bone, 0)-1; if (argc > 2) { ctx->joint->offset[0] = atof(Cmd_Argv(2)); @@ -2256,7 +2256,7 @@ void QCBUILTIN PF_skel_find_bone (pubprogfuncs_t *prinst, struct globalvars_s *p if (!skelobj) G_FLOAT(OFS_RETURN) = 0; else - G_FLOAT(OFS_RETURN) = Mod_TagNumForName(skelobj->model, bname); + G_FLOAT(OFS_RETURN) = Mod_TagNumForName(skelobj->model, bname, 0); } //vector(float skel, float bonenum) skel_get_bonerel (FTE_CSQC_SKELETONOBJECTS) (sets v_forward etc) @@ -2661,7 +2661,7 @@ void QCBUILTIN PF_gettagindex (pubprogfuncs_t *prinst, struct globalvars_s *pr_g const char *tagname = PR_GetStringOfs(prinst, OFS_PARM1); model_t *mod = *tagname?w->Get_CModel(w, ent->v->modelindex):NULL; if (mod) - G_FLOAT(OFS_RETURN) = Mod_TagNumForName(mod, tagname); + G_FLOAT(OFS_RETURN) = Mod_TagNumForName(mod, tagname, 0); else G_FLOAT(OFS_RETURN) = 0; } diff --git a/engine/client/quakedef.h b/engine/client/quakedef.h index 5a77d7b1..bd8a2d50 100644 --- a/engine/client/quakedef.h +++ b/engine/client/quakedef.h @@ -207,6 +207,8 @@ extern "C" { #endif #endif +#include "q3api.h" + #ifdef __cplusplus #define q_max(a,b) ((a) > (b) ? (a) : (b)) #define q_min(a,b) ((a) < (b) ? (a) : (b)) @@ -323,7 +325,7 @@ extern cvar_t pkg_autoupdate; #endif extern cvar_t com_protocolname; extern cvar_t com_protocolversion; -extern cvar_t com_nogamedirnativecode; +extern cvar_t com_gamedirnativecode; extern cvar_t com_parseutf8; #ifdef HAVE_LEGACY extern cvar_t scr_usekfont; diff --git a/engine/client/r_2d.c b/engine/client/r_2d.c index b554c054..d6c6f975 100644 --- a/engine/client/r_2d.c +++ b/engine/client/r_2d.c @@ -223,10 +223,6 @@ void R2D_Shutdown(void) Z_Free(atlas.data); memset(&atlas, 0, sizeof(atlas)); - -#ifdef PLUGINS - Plug_FreeAllImages(); -#endif } /* @@ -460,10 +456,6 @@ void R2D_Init(void) Cvar_ForceCallback(&crosshair); Cvar_ForceCallback(&crosshaircolor); -#ifdef PLUGINS - Plug_DrawReloadImages(); -#endif - R2D_Font_Changed(); R_NetgraphInit(); diff --git a/engine/client/r_part.c b/engine/client/r_part.c index ca0b5914..6ffd00a3 100644 --- a/engine/client/r_part.c +++ b/engine/client/r_part.c @@ -789,7 +789,7 @@ void P_Shutdown(void) //0 says hit nothing. //1 says hit world //>1 says hit some entity -entity_t *TraceLineR (vec3_t start, vec3_t end, vec3_t impact, vec3_t normal) +entity_t *TraceLineR (vec3_t start, vec3_t end, vec3_t impact, vec3_t normal, qboolean bsponly) { trace_t trace; float len, bestlen; @@ -827,9 +827,11 @@ entity_t *TraceLineR (vec3_t start, vec3_t end, vec3_t impact, vec3_t normal) pe = &r_worldentity; else pe = &cl_visedicts[i]; - if (pe->rtype != RT_MODEL || pe->shaderRGBAf[3] < 1 || (pe->flags & (RF_ADDITIVE|RF_NODEPTHTEST|RF_TRANSLUCENT|RF_EXTERNALMODEL))) + if (pe->rtype != RT_MODEL || !pe->model || (pe->shaderRGBAf[3] < 1&&(pe->flags&RF_TRANSLUCENT)) || (pe->flags & (RF_ADDITIVE|RF_NODEPTHTEST|RF_TRANSLUCENT|RF_EXTERNALMODEL))) continue; - if (pe->model && pe->model->funcs.NativeTrace && pe->model->loadstate == MLS_LOADED) + if (bsponly && pe->model->type != mod_brush) + continue; + if (pe->model->funcs.NativeTrace && pe->model->loadstate == MLS_LOADED) { //try to trivially reject the mesh. float ext = 0; diff --git a/engine/client/r_surf.c b/engine/client/r_surf.c index 265dcf40..11124899 100644 --- a/engine/client/r_surf.c +++ b/engine/client/r_surf.c @@ -3971,7 +3971,7 @@ void Surf_BuildLightmaps (void) Surf_NewMap =============== */ -void Surf_NewMap (void) +void Surf_NewMap (model_t *worldmodel) { char namebuf[MAX_QPATH]; extern cvar_t host_mapname; @@ -3981,6 +3981,8 @@ void Surf_NewMap (void) #endif int i; + cl.worldmodel = worldmodel; + //evil haxx r_dynamic.ival = r_dynamic.value; if (r_dynamic.ival > 0 && cl.worldmodel->fromgame == fg_quake3) //quake3 has no lightmaps, disable r_dynamic @@ -4046,7 +4048,8 @@ TRACE(("dbg: Surf_NewMap: building lightmaps\n")); TRACE(("dbg: Surf_NewMap: ui\n")); #ifdef VM_UI - UI_Reset(); + if (q3) + q3->ui.Reset(); #endif TRACE(("dbg: Surf_NewMap: tp\n")); TP_NewMap(); diff --git a/engine/client/render.h b/engine/client/render.h index 12971523..7d8a94e8 100644 --- a/engine/client/render.h +++ b/engine/client/render.h @@ -251,7 +251,7 @@ typedef struct { #define R_MAX_RECURSE 6 #endif #define RDFD_FOV 1 -typedef struct +typedef struct refdef_s { vrect_t grect; // game rectangle. fullscreen except for csqc/splitscreen/hud. vrect_t vrect; // subwindow in grect for 3d view. equal to grect if no hud. @@ -346,7 +346,7 @@ void R_Clutter_Emit(struct batch_s **batches); void R_Clutter_Purge(void); //r_surf.c -void Surf_NewMap (void); +void Surf_NewMap (struct model_s *worldmodel); void Surf_PreNewMap(void); void Surf_SetupFrame(void); //determine pvs+viewcontents void Surf_DrawWorld(void); @@ -552,7 +552,7 @@ skinfile_t *Mod_LookupSkin(skinid_t id); void Mod_Init (qboolean initial); void Mod_Shutdown (qboolean final); -int Mod_TagNumForName(struct model_s *model, const char *name); +int Mod_TagNumForName(struct model_s *model, const char *name, int firsttag); int Mod_SkinNumForName(struct model_s *model, int surfaceidx, const char *name); int Mod_FrameNumForName(struct model_s *model, int surfaceidx, const char *name); int Mod_FrameNumForAction(struct model_s *model, int surfaceidx, int actionid); @@ -624,6 +624,7 @@ void R_AnimateLight (void); void R_UpdateHDR(vec3_t org); void R_UpdateLightStyle(unsigned int style, const char *stylestring, float r, float g, float b); void R_BumpLightstyles(unsigned int maxstyle); //bumps the cl_max_lightstyles array size, if needed. +qboolean R_CalcModelLighting(entity_t *e, struct model_s *clmodel); struct texture_s *R_TextureAnimation (int frame, struct texture_s *base); //mostly deprecated, only lingers for rtlights so world only. struct texture_s *R_TextureAnimation_Q2 (struct texture_s *base); //mostly deprecated, only lingers for rtlights so world only. void RQ_Init(void); diff --git a/engine/client/renderer.c b/engine/client/renderer.c index 17b1b327..6f50b399 100644 --- a/engine/client/renderer.c +++ b/engine/client/renderer.c @@ -378,7 +378,7 @@ cvar_t r_deluxemapping_cvar = CVARAFD ("r_deluxemapping", "1", "r_glsl_delux cvar_t mod_loadsurfenvmaps = CVARD ("r_loadsurfenvmaps", "1", "Load local reflection environment-maps, where available. These are normally defined via env_cubemap entities dotted around the place."); qboolean r_deluxemapping; cvar_t r_shaderblobs = CVARD ("r_shaderblobs", "0", "If enabled, can massively accelerate vid restarts / loading (especially with the d3d renderer). Can cause issues when upgrading engine versions, so this is disabled by default."); -cvar_t gl_compress = CVARFD ("gl_compress", "0", CVAR_ARCHIVE, "Enable automatic texture compression even for textures which are not pre-compressed."); +cvar_t gl_compress = CVARAFD ("gl_compress", "0", "r_ext_compressed_textures"/*q3*/, CVAR_ARCHIVE, "Enable automatic texture compression even for textures which are not pre-compressed."); cvar_t gl_conback = CVARFCD ("gl_conback", "", CVAR_RENDERERCALLBACK, R2D_Conback_Callback, "Specifies which conback shader/image to use. The Quake fallback is gfx/conback.lmp"); //cvar_t gl_detail = CVARF ("gl_detail", "0", @@ -440,7 +440,7 @@ cvar_t gl_specular_fallbackexp = CVARF ("gl_specular_fallbackexp", "1", CVAR cvar_t gl_texture_anisotropic_filtering = CVARAFCD("gl_texture_anisotropy", "4", "gl_texture_anisotropic_filtering"/*old*/, CVAR_ARCHIVE | CVAR_RENDERERCALLBACK, Image_TextureMode_Callback, "Allows for higher quality textures on surfaces that slope away from the camera (like the floor). Set to 16 or something. Only supported with trilinear filtering."); -cvar_t gl_texturemode = CVARFCD("gl_texturemode", "GL_LINEAR_MIPMAP_LINEAR", +cvar_t gl_texturemode = CVARAFCD("gl_texturemode", "GL_LINEAR_MIPMAP_LINEAR", "r_texturemode"/*q3*/, CVAR_ARCHIVE | CVAR_RENDERERCALLBACK | CVAR_SAVE, Image_TextureMode_Callback, "Specifies how world/model textures appear. Typically 3 letters eg "S_COLOR_GREEN"nll"S_COLOR_WHITE" or "S_COLOR_GREEN"lll"S_COLOR_WHITE".\nFirst letter can be l(inear) or n(earest) and says how to upscale low-res textures (n for the classic look - often favoured for embedded textures, l for blurry - best for high-res textures).\nThe middle letter can be set to '.' to disable mipmaps, or n for ugly banding with distance, or l for smooth mipmap transitions.\nThe third letter says what to do when the texture is too high resolution, and should generally be set to 'l' to reduce sparkles including when aiming for the classic lego look."); cvar_t gl_texture_lodbias = CVARAFCD("d_lodbias", "0", "gl_texture_lodbias", @@ -1775,15 +1775,17 @@ TRACE(("dbg: R_ApplyRenderer: starting on client state\n")); if (!isDedicated) S_DoRestart(true); +#ifdef VM_UI + if (q3) + q3->ui.Reset(); +#endif + #ifdef Q3SERVER if (svs.gametype == GT_QUAKE3) { cl.worldmodel = NULL; - CG_Stop(); - memset(cl.model_precache, 0, sizeof(cl.model_precache)); - CG_Start(); - if (cl.worldmodel) - Surf_NewMap(); + if (q3) + q3->cg.VideoRestarted(); } else #endif @@ -1847,9 +1849,7 @@ TRACE(("dbg: R_ApplyRenderer: done the models\n")); // Con_Printf ("You may need to download or purchase a client pack in order to play on this server.\n\n"); CL_Disconnect ("Worldmodel missing after video reload"); -#ifdef VM_UI - UI_Reset(); -#endif + if (newr) memcpy(¤trendererstate, newr, sizeof(currentrendererstate)); return true; @@ -1862,19 +1862,13 @@ TRACE(("dbg: R_ApplyRenderer: checking any wad textures\n")); cl_static_entities[i].ent.model = NULL; TRACE(("dbg: R_ApplyRenderer: Surf_NewMap\n")); - Surf_NewMap(); + Surf_NewMap(cl.worldmodel); TRACE(("dbg: R_ApplyRenderer: efrags\n")); // Skin_FlushAll(); Skin_FlushPlayers(); } - else - { -#ifdef VM_UI - UI_Reset(); -#endif - } #ifdef SKELETALOBJECTS skel_reload(); diff --git a/engine/client/roq.h b/engine/client/roq.h index 2cd315e7..5255682d 100644 --- a/engine/client/roq.h +++ b/engine/client/roq.h @@ -39,9 +39,10 @@ typedef struct roq_info_s { } roq_info; /* -------------------------------------------------------------------------- */ -void roq_init(void); -void roq_cleanup(void); +//void roq_init(void); +//void roq_cleanup(void); roq_info *roq_open(char *fname); +void roq_rewind(roq_info *ri); void roq_close(roq_info *ri); int roq_read_frame(roq_info *ri); int roq_read_audio(roq_info *ri); diff --git a/engine/client/roq_read.c b/engine/client/roq_read.c index befc4482..e248b061 100644 --- a/engine/client/roq_read.c +++ b/engine/client/roq_read.c @@ -361,6 +361,12 @@ int i; return ri; } +//reset enough that we'll start decoding from the start next time we try to read a frame. +void roq_rewind(roq_info *ri) +{ + ri->frame_num = 0; + ri->aud_pos = ri->vid_pos = ri->roq_start; +} /* -------------------------------------------------------------------------- */ void roq_close(roq_info *ri) diff --git a/engine/client/snd_dma.c b/engine/client/snd_dma.c index 6ce605b4..2cdeb9a6 100644 --- a/engine/client/snd_dma.c +++ b/engine/client/snd_dma.c @@ -3679,7 +3679,7 @@ static void S_Q2_AddEntitySounds(soundcardinfo_t *sc) #endif #ifdef VM_CG if (cls.protocol == CP_QUAKE3) - count = CG_GatherLoopingSounds(positions, entnums, sounds, countof(sounds)); + count = q3->cg.GatherLoopingSounds(positions, entnums, sounds, countof(sounds)); else #endif return; diff --git a/engine/client/textedit.c b/engine/client/textedit.c index 2c387cfb..1ef13a7f 100644 --- a/engine/client/textedit.c +++ b/engine/client/textedit.c @@ -850,7 +850,7 @@ qboolean Con_Editor_Close(console_t *con, qboolean force) { if (!strncmp(con->title, "MODIFIED: ", 10)) { - Menu_Prompt(Con_Editor_CloseCallback, con, va("Save changes?\n%s\n", con->name), "Yes", "No", "Cancel"); + Menu_Prompt(Con_Editor_CloseCallback, con, va("Save changes?\n%s\n", con->name), "Yes", "No", "Cancel", true); return false; } } diff --git a/engine/client/zqtp.c b/engine/client/zqtp.c index a3895175..1b898ba8 100644 --- a/engine/client/zqtp.c +++ b/engine/client/zqtp.c @@ -3872,7 +3872,7 @@ void CL_Say (qboolean team, char *extra) #ifdef Q3CLIENT if (cls.protocol == CP_QUAKE3) - CLQ3_SendClientCommand("%s %s%s", team ? "say_team" : "say", extra?extra:"", sendtext); + q3->cl.SendClientCommand("%s %s%s", team ? "say_team" : "say", extra?extra:"", sendtext); else #endif { diff --git a/engine/common/cmd.c b/engine/common/cmd.c index 11a9fbeb..0f9e11b2 100644 --- a/engine/common/cmd.c +++ b/engine/common/cmd.c @@ -934,7 +934,7 @@ static void Cmd_Exec_f (void) #ifdef HAVE_CLIENT if (!cl_warncmd.ival && foundone && (!strcmp(name, "quake.rc") || !strcmp(name, "default.cfg") || !strcmp(name, "autoexec.cfg"))) { -#if defined(HAVE_LEGACY) && defined(HAVE_CLIENT) +#if defined(HAVE_LEGACY) if (!strcmp(name, "default.cfg")) { s = (char*)replacementq1binds; @@ -943,7 +943,7 @@ static void Cmd_Exec_f (void) else #endif { - Menu_Prompt(NULL, NULL, va("WARNING: nquake %s file detected. The file has been ignored.", name), NULL, NULL, "Argh"); + Menu_Prompt(NULL, NULL, va("WARNING: nquake %s file detected. The file has been ignored.", name), NULL, NULL, "Argh", false); *s = 0; foundone = 0; } @@ -2730,7 +2730,7 @@ void Cmd_ForwardToServer (void) #ifdef Q3CLIENT if (cls.protocol == CP_QUAKE3) { - CLQ3_SendClientCommand("%s %s", Cmd_Argv(0), Cmd_Args()); + q3->cl.SendClientCommand("%s %s", Cmd_Argv(0), Cmd_Args()); return; } #endif @@ -2810,6 +2810,84 @@ void Cmd_ForwardToServer (void) } #endif + + +static void Cmd_FindForExecution (const char *name, int level, cmd_function_t **foundcmd, cmdalias_t **foundalias, cvar_t **foundcvar) +{ + //WARNING: PF_checkcommand should match the order. + cmd_function_t *cmd; + cmdalias_t *a; + + *foundcmd = NULL; + *foundalias = NULL; + *foundcvar = NULL; + + for (cmd=cmd_functions ; cmd ; cmd=cmd->next) + { + if (!Q_strcasecmp (name, cmd->name)) + { + *foundcmd = cmd; + if (!strcmp (name, cmd->name)) + break; //don't keep looking for others when we get an exact match. + } + } + cmd = *foundcmd; + if (!cmd) + ; + else if (level == RESTRICT_TEAMPLAY) + { //extra weirdness so that teamplay macros can only execute certain known commands + static char *tpcmds[] = + { + "if", "wait", /*would be nice to include alias in here*/ + "say", "say_team", "echo", /*display stuff, because it would be useless otherwise*/ + "set_tp", "set", "set_calc", "inc", /*because scripting variables is fun. not.*/ + "tp_point", "tp_pickup", "tp_took" /*updates what the $took etc macros are allowed to generate*/ + }; + size_t i; + for (i = 0; i < countof(tpcmds); i++) + if (!strcmp(cmd->name, tpcmds[i])) + break; + if (i == countof(tpcmds)) + *foundcmd = NULL; + else 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]); + *foundcmd = NULL; + } + } + else if ((cmd->restriction?cmd->restriction:rcon_level.ival) > level) + { + Con_TPrintf("cmd '%s' was restricted.\n", name); + *foundcmd = NULL; + } + +// check alias + for (a=cmd_alias ; a ; a=a->next) + { + if (!Q_strcasecmp (cmd_argv[0], a->name)) + { + //teamplay restrictions block any execlevel elevations, so the contents are what matter + //(there's no reason to restrict aliases other than for exec level promotion) + if (level!=RESTRICT_TEAMPLAY) + if ((a->restriction?a->restriction:rcon_level.ival) > level) + { + Con_TPrintf("alias '%s' was restricted.\n", cmd_argv[0]); + return; + } + + *foundalias = a; + if (!strcmp (name, a->name)) + break; + } + } + +// check cvars + *foundcvar = Cvar_FindVar(name); +} + /* ============ Cmd_ExecuteString @@ -2818,14 +2896,15 @@ A complete command line has been parsed, so try to execute it FIXME: lookupnoadd the token to speed search? ============ */ -static void Cmd_ExecuteStringGlobalsAreEvil (const char *text, int level) +void Cmd_ExecuteString (const char *text, int level) { //WARNING: PF_checkcommand should match the order. cmd_function_t *cmd; cmdalias_t *a; + cvar_t *var; + int olev = Cmd_ExecLevel; char dest[65536]; - Cmd_ExecLevel = level; while (*text == ' ' || *text == '\n') text++; @@ -2839,234 +2918,134 @@ static void Cmd_ExecuteStringGlobalsAreEvil (const char *text, int level) if (!Cmd_Argc()) return; // no tokens -// check functions - for (cmd=cmd_functions ; cmd ; cmd=cmd->next) + Cmd_FindForExecution (cmd_argv[0], level, &cmd, &a, &var); + +//check (explicit) functions + if (cmd && cmd->function) { - if (!Q_strcasecmp (cmd_argv[0],cmd->name)) - { - if (strcmp (cmd_argv[0],cmd->name)) - break; //yes, I know we found it... (but it's the wrong case, go for an alias or cvar instead FIRST) - - if (!level) - break; - - if ((cmd->restriction?cmd->restriction:rcon_level.ival) > level) - Con_TPrintf("cmd '%s' was restricted.\n", cmd_argv[0]); - else if (!cmd->function) - { -#if defined(VM_CG) && defined(HAVE_CLIENT) - if (CG_Command()) - return; -#endif -#if defined(Q3SERVER) && defined(HAVE_SERVER) - if (SVQ3_Command()) - return; -#endif -#if defined(VM_UI) && defined(HAVE_CLIENT) - if (UI_Command()) - return; -#endif - if (Cmd_AliasExist(cmd_argv[0], level)) - break; //server stuffed an alias for a command that it would already have received. use that instead. -#if defined(CSQC_DAT) && defined(HAVE_CLIENT) - if (CSQC_ConsoleCommand(-1, text)) - return; //let the csqc handle it if it wants. -#endif -#if defined(MENU_DAT) && defined(HAVE_CLIENT) - if (MP_ConsoleCommand(text)) - return; //let the csqc handle it if it wants. -#endif -#if defined(MENU_NATIVECODE) && defined(HAVE_CLIENT) - if (mn_entry && mn_entry->ConsoleCommand(text, cmd_argc, (char const*const*)cmd_argv)) - return; -#endif - Cmd_ForwardToServer (); - } - else - cmd->function (); - return; - } + Cmd_ExecLevel = level; + cmd->function(); + Cmd_ExecLevel = olev; + return; } -// check alias - for (a=cmd_alias ; a ; a=a->next) + //priority is cmd>alias>cvar + //but this means that user aliases can override cvars + //which means users can use aliases to block cvar access, aka cheat. + //so favour the cvar when its a server command (unless the alias was also created by the server) + if (a && (!var || Cmd_ExecLevelflags&ALIAS_FROMSERVER)) { - if (!Q_strcasecmp (cmd_argv[0], a->name)) - { - int execlevel; + int execlevel; #ifdef HAVE_CLIENT //an emergency escape mechansim, to avoid infinatly recursing aliases. - extern unsigned int con_splitmodifier; + extern unsigned int con_splitmodifier; - if (keydown[K_SHIFT] && (keydown[K_LCTRL]||keydown[K_RCTRL]) && (keydown[K_LALT]||keydown[K_RALT]) && !isDedicated) - return; + if (keydown[K_SHIFT] && (keydown[K_LCTRL]||keydown[K_RCTRL]) && (keydown[K_LALT]||keydown[K_RALT]) && !isDedicated) + return; #endif - if (!level) - execlevel = level; + Cmd_ExecLevel = level; + + if (level == RESTRICT_TEAMPLAY) + execlevel = level; //teamplay aliases can't let the user's settings promote them out of their restrictions. + else + { + if (a->execlevel) + execlevel = a->execlevel; else - { - if ((a->restriction?a->restriction:rcon_level.ival) > level) + execlevel = level; + } + + Cbuf_InsertText ("\n", execlevel, false); + + // if the alias value is a command or cvar and + // the alias is called with parameters, add them + //unless we're mimicing dp, or the alias has explicit expansions (or macros) in which case it can do its own damn args + { + char *ignoringquoteswasstupid; + Cmd_ExpandString(a->value, dest, sizeof(dest), &execlevel, !Cmd_IsInsecure()?true:false, true); + for (ignoringquoteswasstupid = dest; *ignoringquoteswasstupid; ) + { //double up dollars, to prevent expansion when its actually execed. + if (*ignoringquoteswasstupid == '$') { - Con_TPrintf("alias '%s' was restricted.\n", cmd_argv[0]); - return; - } - if (a->execlevel) - execlevel = a->execlevel; - else - execlevel = level; - } - - Cbuf_InsertText ("\n", execlevel, false); - - // if the alias value is a command or cvar and - // the alias is called with parameters, add them - //unless we're mimicing dp, or the alias has explicit expansions (or macros) in which case it can do its own damn args - { - char *ignoringquoteswasstupid; - Cmd_ExpandString(a->value, dest, sizeof(dest), &execlevel, !Cmd_IsInsecure()?true:false, true); - for (ignoringquoteswasstupid = dest; *ignoringquoteswasstupid; ) - { //double up dollars, to prevent expansion when its actually execed. - if (*ignoringquoteswasstupid == '$') - { - memmove(ignoringquoteswasstupid+1, ignoringquoteswasstupid, strlen(ignoringquoteswasstupid)+1); - ignoringquoteswasstupid++; - } + memmove(ignoringquoteswasstupid+1, ignoringquoteswasstupid, strlen(ignoringquoteswasstupid)+1); ignoringquoteswasstupid++; } - if ((a->restriction?a->restriction:rcon_level.ival) > execlevel) - return; + ignoringquoteswasstupid++; } - if (!dpcompat_console.ival) + if ((a->restriction?a->restriction:rcon_level.ival) > execlevel) + return; + } + if (!dpcompat_console.ival) + { + if (Cmd_Argc() > 1 && (!strncmp(a->value, "cmd ", 4) || (!strchr(a->value, ' ') && !strchr(a->value, '\t') && + (Cvar_FindVar(a->value) || (Cmd_Exists(a->value) && a->value[0] != '+' && a->value[0] != '-')))) + ) { - if (Cmd_Argc() > 1 && (!strncmp(a->value, "cmd ", 4) || (!strchr(a->value, ' ') && !strchr(a->value, '\t') && - (Cvar_FindVar(a->value) || (Cmd_Exists(a->value) && a->value[0] != '+' && a->value[0] != '-')))) - ) - { - Cbuf_InsertText (Cmd_Args(), execlevel, false); - Cbuf_InsertText (" ", execlevel, false); - } + Cbuf_InsertText (Cmd_Args(), execlevel, false); + Cbuf_InsertText (" ", execlevel, false); } - Cbuf_InsertText (dest, execlevel, false); + } + Cbuf_InsertText (dest, execlevel, false); #ifdef HAVE_CLIENT - if (con_splitmodifier > 0) - { //if the alias was execed via p1/p2 etc, make sure that propagates properly (at least for simple aliases like impulses) - //fixme: should probably prefix each line. that may have different issues however. - //don't need to care about + etc - Cbuf_InsertText (va("p %i ", con_splitmodifier), execlevel, false); - } + if (con_splitmodifier > 0) + { //if the alias was execed via p1/p2 etc, make sure that propagates properly (at least for simple aliases like impulses) + //fixme: should probably prefix each line. that may have different issues however. + //don't need to care about + etc + Cbuf_InsertText (va("p %i ", con_splitmodifier), execlevel, false); + } #endif - Con_DPrintf("Execing alias %s ^3%s:\n^1%s\n^2%s\n", a->name, Cmd_Args(), a->value, dest); - return; - } + Con_DPrintf("Execing alias %s ^3%s:\n^1%s\n^2%s\n", a->name, Cmd_Args(), a->value, dest); + Cmd_ExecLevel = olev; + return; } // check cvars - if (Cvar_Command (level)) - return; - - 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*/ - "say", "say_team", "echo", /*display stuff, because it would be useless otherwise*/ - "set_tp", "set", "set_calc", "inc", /*because scripting variables is fun. not.*/ - "tp_point", "tp_pickup", "tp_took" /*updates what the $took etc macros are allowed to generate*/ - }; - if (cmd) - { - for (level = 0; level < countof(tpcmds); level++) - { - if (!strcmp(cmd_argv[0], tpcmds[level])) - { - 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 (); - else - cmd->function(); - return; - } - } - } - Con_TPrintf("'%s' is not permitted in combination with teamplay macros.\n", cmd_argv[0]); - return; - } - - if (cmd) //go for skipped ones - { - if ((cmd->restriction?cmd->restriction:rcon_level.ival) > level) - Con_TPrintf("'%s' was restricted.\n", cmd_argv[0]); - else if (!cmd->function) - Cmd_ForwardToServer (); - else - cmd->function (); - return; - } - + Cmd_ExecLevel = level; + if (!cmd && Cvar_Command (var, level)) + ; #if defined(CSQC_DAT) && defined(HAVE_CLIENT) - if (CSQC_ConsoleCommand(-1, text)) - return; + else if (CSQC_ConsoleCommand(-1, text)) + ; #endif #if defined(MENU_DAT) && defined(HAVE_CLIENT) - if (MP_ConsoleCommand(text)) - return; //let the csqc handle it if it wants. + else if (MP_ConsoleCommand(text)) + ; //let the csqc handle it if it wants. #endif #if defined(MENU_NATIVECODE) && defined(HAVE_CLIENT) if (mn_entry && mn_entry->ConsoleCommand(text, cmd_argc, (char const*const*)cmd_argv)) - return; -#endif - -#ifdef PLUGINS - if (Plugin_ExecuteString()) - return; + ; #endif #ifdef HAVE_SERVER - if (sv.state) - { - if (PR_ConsoleCmd(text)) - return; - } + else if (sv.state && PR_ConsoleCmd(text)) + ; #endif #if defined(VM_CG) && defined(HAVE_CLIENT) - if (CG_Command()) - return; + else if (q3 && q3->cg.ConsoleCommand()) + ; #endif #if defined(Q3SERVER) && defined(HAVE_SERVER) - if (SVQ3_Command()) - return; + else if (q3 && q3->sv.ConsoleCommand()) + ; #endif #if defined(VM_UI) && defined(HAVE_CLIENT) - if (UI_Command()) - return; + else if (q3 && q3->ui.ConsoleCommand()) + ; #endif + else if (cmd #if defined(Q2CLIENT) && defined(HAVE_CLIENT) - if (cls.protocol == CP_QUAKE2 || cls.protocol == CP_QUAKE3) + || (cls.state!=ca_disconnected && (cls.protocol == CP_QUAKE2 || cls.protocol == CP_QUAKE3)) +#endif + ) { //q2 servers convert unknown commands to text. Cmd_ForwardToServer(); - return; } -#endif - if ((cl_warncmd.value && level <= RESTRICT_LOCAL) || developer.value) + else if ((cl_warncmd.value && level <= RESTRICT_LOCAL) || developer.value) Con_TPrintf ("Unknown command \"%s\"\n", Cmd_Argv(0)); -} -void Cmd_ExecuteString (const char *text, int level) -{ //inserted a small wrapper due to all the returns in the original function. - //a number of things check for seats if nothing else, and security says is safer to do this than to be in doubt. - int olev = Cmd_ExecLevel; - Cmd_ExecuteStringGlobalsAreEvil(text, level); Cmd_ExecLevel = olev; } @@ -3917,7 +3896,7 @@ static void Cmd_set_f(void) forceflags |= 0; } - var = Cvar_Get2 (name, text, CVAR_TEAMPLAYTAINT, desc, "Custom variables"); + var = Cvar_Get2 (name, text, CVAR_TEAMPLAYTAINT|forceflags, desc, "Custom variables"); mark = If_Token_GetMark(); @@ -4093,6 +4072,11 @@ static void Cmd_WriteConfig_f(void) char sysname[MAX_OSPATH]; qboolean all = true; + //special variation that only saves if an archived cvar was actually modified. + if (!Q_strcasecmp(Cmd_Argv(0), "cfg_save_ifmodified")) + if (!Cvar_UnsavedArchive()) + return; + filename = Cmd_Argv(1); if (!*filename) { @@ -4379,6 +4363,7 @@ void Cmd_Init (void) // register our commands // Cmd_AddCommandAD ("cfg_save",Cmd_WriteConfig_f, Cmd_Exec_c, NULL); + Cmd_AddCommandAD ("cfg_save_ifmodified",Cmd_WriteConfig_f, Cmd_Exec_c, NULL); Cmd_AddCommandAD ("saveconfig",Cmd_WriteConfig_f, Cmd_Exec_c, NULL); //for dpcompat Cmd_AddCommandAD ("cfg_load",Cmd_Exec_f, Cmd_Exec_c, NULL); diff --git a/engine/common/cmd.h b/engine/common/cmd.h index e65ee4f2..2c7e4d6a 100644 --- a/engine/common/cmd.h +++ b/engine/common/cmd.h @@ -224,7 +224,7 @@ void Cmd_Args_Set(const char *newargs, size_t len); #define RESTRICT_MAX_USER 29 #define RESTRICT_DEFAULT 20 #define RESTRICT_MIN 1 -#define RESTRICT_TEAMPLAY 0 +#define RESTRICT_TEAMPLAY 0 //this is blocked from everything but aliases. #define RESTRICT_MAX RESTRICT_MAX_USER diff --git a/engine/common/com_mesh.c b/engine/common/com_mesh.c index 4f4b7896..c66de8cf 100644 --- a/engine/common/com_mesh.c +++ b/engine/common/com_mesh.c @@ -5426,7 +5426,7 @@ qboolean Mod_GetTag(model_t *model, int tagnum, framestate_t *fstate, float *res return false; } -int Mod_TagNumForName(model_t *model, const char *name) +int Mod_TagNumForName(model_t *model, const char *name, int firsttag) { #ifdef SKELORTAGS int i; @@ -5457,7 +5457,7 @@ int Mod_TagNumForName(model_t *model, const char *name) { galiasbone_t *b; b = inf->ofsbones; - for (i = 0; i < inf->numbones; i++) + for (i = firsttag; i < inf->numbones; i++) { if (!strcmp(b[i].name, name)) return i+1; @@ -5468,7 +5468,7 @@ int Mod_TagNumForName(model_t *model, const char *name) if (inf->numtags) { md3tag_t *t = inf->ofstags; - for (i = 0; i < inf->numtags; i++) + for (i = firsttag; i < inf->numtags; i++) { if (!strcmp(t[i].name, name)) return i+1; @@ -6327,6 +6327,13 @@ static qboolean QDECL Mod_LoadQ3Model(model_t *mod, void *buffer, size_t fsize) + + + + + + + #ifdef ZYMOTICMODELS @@ -10114,6 +10121,8 @@ void Alias_Register(void) Mod_RegisterModelFormatText(NULL, "MD5 Mesh/Anim (md5mesh)", "MD5Version", Mod_LoadMD5MeshModel); Mod_RegisterModelFormatText(NULL, "External Anim", "EXTERNALANIM", Mod_LoadCompositeAnim); #endif + + #ifdef MODELFMT_OBJ Mod_RegisterModelFormatText(NULL, "Wavefront Object (obj)", ".obj", Mod_LoadObjModel); Cvar_Register(&mod_obj_orientation, NULL); diff --git a/engine/common/common.c b/engine/common/common.c index d1e86e81..3ed84822 100644 --- a/engine/common/common.c +++ b/engine/common/common.c @@ -86,7 +86,7 @@ cvar_t com_protocolname = CVARAD("com_protocolname", NULL, "com_gamename", "The cvar_t com_protocolversion = CVARAD("com_protocolversion", "3", NULL, "The protocol version used for dpmaster queries."); //3 by default, for compat with DP/NQ, even if our QW protocol uses different versions entirely. really it only matters for master servers. cvar_t com_parseutf8 = CVARD("com_parseutf8", "1", "Interpret console messages/playernames/etc as UTF-8. Requires special fonts. -1=iso 8859-1. 0=quakeascii(chat uses high chars). 1=utf8, revert to ascii on decode errors. 2=utf8 ignoring errors"); //1 parse. 2 parse, but stop parsing that string if a char was malformed. cvar_t com_highlightcolor = CVARD("com_highlightcolor", STRINGIFY(COLOR_RED), "ANSI colour to be used for highlighted text, used when com_parseutf8 is active."); -cvar_t com_nogamedirnativecode = CVARFD("com_nogamedirnativecode", "1", CVAR_NOTFROMSERVER, FULLENGINENAME" blocks all downloads of files with a .dll or .so extension, however other engines (eg: ezquake and fodquake) do not - this omission can be used to trigger delayed eremote exploits in any engine (including "DISTRIBUTION") which is later run from the same gamedir.\nQuake2, Quake3(when debugging), and KTX typically run native gamecode from within gamedirs, so if you wish to run any of these games you will need to ensure this cvar is changed to 0, as well as ensure that you don't run unsafe clients."); +cvar_t com_gamedirnativecode = CVARFD("com_gamedirnativecode", "0", CVAR_NOTFROMSERVER, FULLENGINENAME" blocks all downloads of files with a .dll or .so extension, however other engines (eg: ezquake and fodquake) do not - this omission can be used to trigger delayed eremote exploits in any engine (including "DISTRIBUTION") which is later run from the same gamedir.\nQuake2, Quake3(when debugging), and KTX typically run native gamecode from within gamedirs, so if you wish to run any of these games you will need to ensure this cvar is changed to 1, as well as ensure that you don't run unsafe clients."); cvar_t sys_platform = CVAR("sys_platform", PLATFORM); cvar_t host_mapname = CVARAFD("mapname", "", "host_mapname", 0, "Cvar that holds the short name of the current map, for scripting type stuff"); #ifdef HAVE_LEGACY @@ -868,6 +868,147 @@ Handles qbyte ordering and avoids alignment errors // writing functions // +void MSG_BeginWriting (sizebuf_t *msg, struct netprim_s prim, void *bufferstorage, size_t buffersize) +{ + if (bufferstorage || buffersize) + { //otherwise just clear it. + msg->data = bufferstorage; + msg->maxsize = buffersize; + } + msg->overflowed = false; + msg->cursize = 0; + msg->currentbit = 0; + msg->packing = SZ_RAWBYTES; + msg->prim = prim; + msg->allowoverflow = false; +} + +static void MSG_WriteRawBytes(sizebuf_t *msg, int value, int bits) +{ + qbyte *buf; + + if (bits <= 8) + { + buf = SZ_GetSpace(msg, 1); + buf[0] = value; + } + else if (bits <= 16) + { + buf = SZ_GetSpace(msg, 2); + buf[0] = value & 0xFF; + buf[1] = value >> 8; + } + else //if (bits <= 32) + { + buf = SZ_GetSpace(msg, 4); + buf[0] = value & 0xFF; + buf[1] = (value >> 8) & 0xFF; + buf[2] = (value >> 16) & 0xFF; + buf[3] = value >> 24; + } +} + +static void MSG_WriteRawBits(sizebuf_t *msg, int value, int bits) +{ + int i; + for (i=0; icurrentbit&7)) + { //we need another byte now... + msg->cursize++; + if (bits >= 8) + { //splurge an entire byte + msg->data[msg->currentbit>>3] = (value>>i)&0xff; + i += 8; + msg->currentbit += 8; + continue; + } + //clear it for the following 8 bits to splurge + msg->data[msg->currentbit>>3] = 0; + } + msg->data[msg->currentbit>>3] |= ((value>>i)&1) << (msg->currentbit & 7); + msg->currentbit++; + i++; + } +} + +#ifdef HUFFNETWORK +static void MSG_WriteHuffBits(sizebuf_t *msg, int value, int bits) +{ + int remaining; + int i; + + value &= 0xFFFFFFFFu >> (32 - bits); + remaining = bits & 7; + + for( i=0; icurrentbit & 7) ) + { + msg->data[msg->currentbit >> 3] = 0; + } + msg->data[msg->currentbit >> 3] |= (value & 1) << (msg->currentbit & 7); + msg->currentbit++; + value >>= 1; + } + bits -= remaining; + + if( bits > 0 ) + { + for( i=0 ; i<(bits+7)>>3 ; i++ ) + { + Huff_EmitByte( value & 255, msg->data, &msg->currentbit ); + value >>= 8; + } + } + + msg->cursize = (msg->currentbit >> 3) + 1; +} +#endif + +/* +============ +MSG_WriteBits +============ +*/ +void MSG_WriteBits(sizebuf_t *msg, int value, int bits) +{ + if( !bits || bits < -31 || bits > 32 ) + Sys_Error("MSG_WriteBits: bad bits %i", bits); + + if (bits < 0) + { //negative means sign extension on reading + if (value & (1u<<(bits-1))) + value |= ~1u<packing ) + { + default: + case SZ_BAD: + Sys_Error("MSG_WriteBits: bad msg->packing %i", msg->packing ); + break; + case SZ_RAWBYTES: + MSG_WriteRawBytes( msg, value, bits ); + break; + case SZ_RAWBITS: + MSG_WriteRawBits( msg, value, bits ); + break; +#ifdef HUFFNETWORK + case SZ_HUFFMAN: + if( msg->maxsize - msg->cursize < 4 ) + { + if (!msg->allowoverflow) + msg->overflowed = true; + return; + } + MSG_WriteHuffBits( msg, value, bits ); + break; +#endif + } +} + void MSG_WriteChar (sizebuf_t *sb, int c) { qbyte *buf; @@ -1760,14 +1901,16 @@ void MSGCL_WriteDeltaUsercmd (sizebuf_t *buf, const usercmd_t *from, const userc int msg_readcount; qboolean msg_badread; struct netprim_s msg_nullnetprim; +static sizebuf_t *msg_readmsg; -void MSG_BeginReading (struct netprim_s prim) +void MSG_BeginReading (sizebuf_t *sb, struct netprim_s prim) { + msg_readmsg = sb; msg_readcount = 0; msg_badread = false; - net_message.currentbit = 0; - net_message.packing = SZ_RAWBYTES; - net_message.prim = prim; + sb->currentbit = 0; + sb->packing = SZ_RAWBYTES; + sb->prim = prim; } void MSG_ChangePrimitives(struct netprim_s prim) @@ -1777,7 +1920,7 @@ void MSG_ChangePrimitives(struct netprim_s prim) int MSG_GetReadCount(void) { - return msg_readcount; + return msg_readmsg->currentbit>>3; } @@ -1827,6 +1970,13 @@ static int MSG_ReadRawBits(sizebuf_t *msg, int bits) int val; int bitmask = 0; + if (msg->currentbit + bits > (msg->cursize<<3)) + { + msg_badread = true; + msg->currentbit = msg->cursize<<3; + return -1; + } + for(i=0 ; idata[msg->currentbit >> 3] >> (msg->currentbit & 7); @@ -1858,6 +2008,12 @@ static int MSG_ReadHuffBits(sizebuf_t *msg, int bits) bitmask |= val << (i + remaining); } + if (msg->currentbit > (msg->cursize<<3)) + { + msg_badread = true; + msg->currentbit = msg->cursize<<3; + return -1; + } msg_readcount = (msg->currentbit >> 3) + 1; return bitmask; @@ -1880,21 +2036,21 @@ int MSG_ReadBits(int bits) extend = true; } - switch(net_message.packing) + switch(msg_readmsg->packing) { default: case SZ_BAD: - Sys_Error("MSG_ReadBits: bad net_message.packing"); + Sys_Error("MSG_ReadBits: bad msg_readmsg->packing"); break; case SZ_RAWBYTES: - bitmask = MSG_ReadRawBytes(&net_message, bits); + bitmask = MSG_ReadRawBytes(msg_readmsg, bits); break; case SZ_RAWBITS: - bitmask = MSG_ReadRawBits(&net_message, bits); + bitmask = MSG_ReadRawBits(msg_readmsg, bits); break; #ifdef HUFFNETWORK case SZ_HUFFMAN: - bitmask = MSG_ReadHuffBits(&net_message, bits); + bitmask = MSG_ReadHuffBits(msg_readmsg, bits); break; #endif } @@ -1912,7 +2068,7 @@ int MSG_ReadBits(int bits) void MSG_ReadSkip(int bytes) { - if (net_message.packing!=SZ_RAWBYTES) + if (msg_readmsg->packing!=SZ_RAWBYTES) { while (bytes > 4) { @@ -1925,13 +2081,14 @@ void MSG_ReadSkip(int bytes) bytes--; } } - if (msg_readcount+bytes > net_message.cursize) + if (msg_readcount+bytes > msg_readmsg->cursize) { - msg_readcount = net_message.cursize; + msg_readcount = msg_readmsg->cursize; msg_badread = true; return; } msg_readcount += bytes; + msg_readmsg->currentbit = msg_readcount<<3; } @@ -1940,17 +2097,19 @@ int MSG_ReadChar (void) { int c; - if (net_message.packing!=SZ_RAWBYTES) - return (signed char)MSG_ReadBits(8); + if (msg_readmsg->packing!=SZ_RAWBYTES) + return MSG_ReadBits(-8); - if (msg_readcount+1 > net_message.cursize) + msg_readcount = msg_readmsg->currentbit>>3; + if (msg_readcount+1 > msg_readmsg->cursize) { msg_badread = true; return -1; } - c = (signed char)net_message.data[msg_readcount]; + c = (signed char)msg_readmsg->data[msg_readcount]; msg_readcount++; + msg_readmsg->currentbit = msg_readcount<<3; return c; } @@ -1959,17 +2118,19 @@ int MSG_ReadByte (void) { unsigned char c; - if (net_message.packing!=SZ_RAWBYTES) - return (unsigned char)MSG_ReadBits(8); + if (msg_readmsg->packing!=SZ_RAWBYTES) + return MSG_ReadBits(8); - if (msg_readcount+1 > net_message.cursize) + msg_readcount = msg_readmsg->currentbit>>3; + if (msg_readcount+1 > msg_readmsg->cursize) { msg_badread = true; return -1; } - c = (unsigned char)net_message.data[msg_readcount]; + c = (unsigned char)msg_readmsg->data[msg_readcount]; msg_readcount++; + msg_readmsg->currentbit = msg_readcount<<3; return c; } @@ -1978,19 +2139,21 @@ int MSG_ReadShort (void) { int c; - if (net_message.packing!=SZ_RAWBYTES) + if (msg_readmsg->packing!=SZ_RAWBYTES) return (short)MSG_ReadBits(16); - if (msg_readcount+2 > net_message.cursize) + msg_readcount = msg_readmsg->currentbit>>3; + if (msg_readcount+2 > msg_readmsg->cursize) { msg_badread = true; return -1; } - c = (short)(net_message.data[msg_readcount] - + (net_message.data[msg_readcount+1]<<8)); + c = (short)(msg_readmsg->data[msg_readcount] + + (msg_readmsg->data[msg_readcount+1]<<8)); msg_readcount += 2; + msg_readmsg->currentbit = msg_readcount<<3; return c; } @@ -1999,21 +2162,23 @@ int MSG_ReadLong (void) { int c; - if (net_message.packing!=SZ_RAWBYTES) + if (msg_readmsg->packing!=SZ_RAWBYTES) return (int)MSG_ReadBits(32); - if (msg_readcount+4 > net_message.cursize) + msg_readcount = msg_readmsg->currentbit>>3; + if (msg_readcount+4 > msg_readmsg->cursize) { msg_badread = true; return -1; } - c = net_message.data[msg_readcount] - + (net_message.data[msg_readcount+1]<<8) - + (net_message.data[msg_readcount+2]<<16) - + (net_message.data[msg_readcount+3]<<24); + c = msg_readmsg->data[msg_readcount] + + (msg_readmsg->data[msg_readcount+1]<<8) + + (msg_readmsg->data[msg_readcount+2]<<16) + + (msg_readmsg->data[msg_readcount+3]<<24); msg_readcount += 4; + msg_readmsg->currentbit = msg_readcount<<3; return c; } @@ -2072,23 +2237,25 @@ float MSG_ReadFloat (void) int l; } dat; - if (net_message.packing!=SZ_RAWBYTES) + if (msg_readmsg->packing!=SZ_RAWBYTES) { dat.l = MSG_ReadBits(32); return dat.f; } - if (msg_readcount+4 > net_message.cursize) + msg_readcount = msg_readmsg->currentbit>>3; + if (msg_readcount+4 > msg_readmsg->cursize) { msg_badread = true; return -1; } - dat.b[0] = net_message.data[msg_readcount]; - dat.b[1] = net_message.data[msg_readcount+1]; - dat.b[2] = net_message.data[msg_readcount+2]; - dat.b[3] = net_message.data[msg_readcount+3]; + dat.b[0] = msg_readmsg->data[msg_readcount]; + dat.b[1] = msg_readmsg->data[msg_readcount+1]; + dat.b[2] = msg_readmsg->data[msg_readcount+2]; + dat.b[3] = msg_readmsg->data[msg_readcount+3]; msg_readcount += 4; + msg_readmsg->currentbit = msg_readcount<<3; if (bigendian) dat.l = LittleLong (dat.l); @@ -2185,7 +2352,7 @@ char *MSG_ReadStringLine (void) float MSG_ReadCoord (void) { coorddata c = {{0}}; - unsigned char coordtype = net_message.prim.coordtype; + unsigned char coordtype = msg_readmsg->prim.coordtype; if (coordtype == COORDTYPE_UNDEFINED) { static float throttle; @@ -2265,7 +2432,7 @@ float MSG_ReadAngle16 (void) } float MSG_ReadAngle (void) { - int sz = net_message.prim.anglesize; + int sz = msg_readmsg->prim.anglesize; if (!sz) { static float throttle; @@ -2360,7 +2527,7 @@ void MSGQ2_ReadDeltaUsercmd (const usercmd_t *from, usercmd_t *move) bits = MSG_ReadByte (); - if (net_message.prim.flags & NPQ2_R1Q2_UCMD) + if (msg_readmsg->prim.flags & NPQ2_R1Q2_UCMD) buttons = MSG_ReadByte(); // read current angles @@ -2407,7 +2574,7 @@ void MSGQ2_ReadDeltaUsercmd (const usercmd_t *from, usercmd_t *move) // read buttons if (bits & Q2CM_BUTTONS) { - if (net_message.prim.flags & NPQ2_R1Q2_UCMD) + if (msg_readmsg->prim.flags & NPQ2_R1Q2_UCMD) move->buttons = buttons & (1|2|128); //only use the bits that are actually buttons, so gamecode can't get excited despite being crippled by this. else move->buttons = MSG_ReadByte (); @@ -5601,13 +5768,13 @@ static void COM_Version_f (void) #ifdef BOTLIB_STATIC Con_Printf(" Quake3"); #else - Con_Printf(" Quake3^h(no-botlib)^h"); + Con_Printf(" Quake3^h(dynamic)^h"); #endif #elif defined(Q3SERVER) #ifdef BOTLIB_STATIC Con_Printf(" Quake3(server)"); #else - Con_Printf(" Quake3(server,no-botlib)"); + Con_Printf(" Quake3(server,dynamic)"); #endif #elif defined(Q3CLIENT) Con_Printf(" Quake3(client)"); @@ -6409,7 +6576,7 @@ void COM_Init (void) Cvar_Register (&gameversion, "Gamecode"); Cvar_Register (&gameversion_min, "Gamecode"); Cvar_Register (&gameversion_max, "Gamecode"); - Cvar_Register (&com_nogamedirnativecode, "Gamecode"); + Cvar_Register (&com_gamedirnativecode, "Gamecode"); Cvar_Register (&com_parseutf8, "Internationalisation"); #ifdef HAVE_LEGACY Cvar_Register (&scr_usekfont, NULL); diff --git a/engine/common/common.h b/engine/common/common.h index 0acb24c2..97d4a0f7 100644 --- a/engine/common/common.h +++ b/engine/common/common.h @@ -318,7 +318,9 @@ float MSG_FromCoord(coorddata c, int bytes); coorddata MSG_ToCoord(float f, int bytes); coorddata MSG_ToAngle(float f, int bytes); +void MSG_BeginWriting (sizebuf_t *msg, struct netprim_s prim, void *bufferstorage, size_t buffersize); void MSG_WriteChar (sizebuf_t *sb, int c); +void MSG_WriteBits (sizebuf_t *msg, int value, int bits); void MSG_WriteByte (sizebuf_t *sb, int c); void MSG_WriteShort (sizebuf_t *sb, int c); void MSG_WriteLong (sizebuf_t *sb, int c); @@ -344,7 +346,7 @@ extern int msg_readcount; extern qboolean msg_badread; // set if a read goes beyond end of message extern struct netprim_s msg_nullnetprim; -void MSG_BeginReading (struct netprim_s prim); +void MSG_BeginReading (sizebuf_t *sb, struct netprim_s prim); void MSG_ChangePrimitives(struct netprim_s prim); int MSG_GetReadCount(void); int MSG_ReadChar (void); @@ -452,7 +454,7 @@ char *COM_ParseType (const char *data, char *out, size_t outlen, com_tokentype_t char *COM_ParseStringSet (const char *data, char *out, size_t outlen); //whitespace or semi-colon separators char *COM_ParseStringSetSep (const char *data, char sep, char *out, size_t outsize); //single-char-separator, no whitespace char *COM_ParseCString (const char *data, char *out, size_t maxoutlen, size_t *writtenlen); -char *COM_StringParse (const char *data, char *token, unsigned int tokenlen, qboolean expandmacros, qboolean qctokenize); +char *COM_StringParse (const char *data, char *token, unsigned int tokenlen, qboolean expandmacros, qboolean qctokenize); //fancy version used for console etc parsing #define COM_ParseToken(data,punct) COM_ParseTokenOut(data, punct, com_token, sizeof(com_token), &com_tokentype) char *COM_ParseTokenOut (const char *data, const char *punctuation, char *token, size_t tokenlen, com_tokentype_t *tokentype); //note that line endings are a special type of token. char *COM_TrimString(char *str, char *buffer, int buffersize); @@ -572,7 +574,7 @@ typedef struct searchpath_s struct searchpath_s *next; struct searchpath_s *nextpure; } searchpath_t; -typedef struct { +typedef struct flocation_s{ struct searchpath_s *search; //used to say which filesystem driver to open the file from void *fhandle; //used by the filesystem driver as a simple reference to the file char rawname[MAX_OSPATH]; //blank means not readable directly @@ -660,7 +662,7 @@ enum fs_relative{ //note that many of theses paths can map to multiple system locations. FS_NativePath can vary somewhat in terms of what it returns, generally favouring writable locations rather then the path that actually contains a file. FS_BINARYPATH, //where the 'exe' is located. we'll check here for dlls too. FS_LIBRARYPATH, //for system dlls and stuff - FS_ROOT, //either homedir or basedir, + FS_ROOT, //./ (effectively -homedir if enabled, otherwise effectively -basedir arg) FS_SYSTEM, //a system path. absolute paths are explicitly allowed and expected, but not required. //after this point, all types must be relative to a gamedir @@ -708,7 +710,7 @@ void MyRegDeleteKeyValue(void *base, const char *keyname, const char *valuename) void FS_UnloadPackFiles(void); void FS_ReloadPackFiles(void); char *FSQ3_GenerateClientPacksList(char *buffer, int maxlen, int basechecksum); -void FS_PureMode(int mode, char *purenamelist, char *purecrclist, char *refnamelist, char *refcrclist, int seed); //implies an fs_restart. ref package names are optional, for q3 where pure names don't contain usable paths +void FS_PureMode(const char *gamedir, int mode, char *purenamelist, char *purecrclist, char *refnamelist, char *refcrclist, int seed); //implies an fs_restart. ref package names are optional, for q3 where pure names don't contain usable paths int FS_PureOkay(void); //recursively tries to open files until it can get a zip. @@ -828,7 +830,7 @@ int FS_GetManifestArgv(char **argv, int maxargs); struct zonegroup_s; void *FS_LoadMallocGroupFile(struct zonegroup_s *ctx, char *path, size_t *fsize, qboolean filters); -qbyte *FS_LoadMallocFile (const char *path, size_t *fsize); +void *FS_LoadMallocFile (const char *path, size_t *fsize); qbyte *FS_LoadMallocFileFlags (const char *path, unsigned int locateflags, size_t *fsize); qofs_t FS_LoadFile(const char *name, void **file); void FS_FreeFile(void *file); diff --git a/engine/common/cvar.c b/engine/common/cvar.c index 40f3f7bb..309e1f15 100644 --- a/engine/common/cvar.c +++ b/engine/common/cvar.c @@ -595,6 +595,40 @@ void Cvar_PurgeDefaults_f(void) } } +//we're changing games. reset everything to engine defaults and kill all user cvars +static void Cvar_Free(cvar_t *tbf); +void Cvar_GamedirChange(void) +{ + cvar_t *var, **link; + cvar_group_t *grp; + for (grp = cvar_groups; grp; grp = grp->next) + { + for (link = &grp->cvars; (var=*link); ) + { + if (var->flags & CVAR_NORESET) + ; //don't reset it (nor kill it). + else if (var->enginevalue) + Cvar_ForceSet(var, var->enginevalue); + else if (var->flags & CVAR_POINTER) + { + *link = var->next; + Z_Free(var->string); + if (var->defaultstr != var->enginevalue) + Cvar_DefaultFree(var->defaultstr); + if (var->latched_string) + Z_Free(var->latched_string); + if (var->name) + AHash_RemoveDataInsensitive(&cvar_hash, var->name, var); + if (var->name2) + AHash_RemoveDataInsensitive(&cvar_hash, var->name2, var); + Z_Free(var); + continue; + } + link = &(*link)->next; + } + } +} + void Cvar_ResetAll_f(void) { cvar_group_t *grp; @@ -992,7 +1026,8 @@ static cvar_t *Cvar_SetCore (cvar_t *var, const char *value, qboolean force) { if (strcmp(latch, value)) { - var->modified++; //only modified if it changed. + var->modified=true; //only modified if it changed. + var->modifiedcount++; if (var->callback) var->callback(var, latch); @@ -1226,6 +1261,7 @@ static void Cvar_Free(cvar_t *tbf) grp->cvars = tbf->next; goto unlinked; } + if (grp->cvars) for (var=grp->cvars ; var->next ; var=var->next) { if (var->next == tbf) @@ -1281,6 +1317,7 @@ qboolean Cvar_Register (cvar_t *variable, const char *groupname) group = Cvar_GetGroup(groupname); variable->modified = old->modified; + variable->modifiedcount = old->modifiedcount; variable->flags |= (old->flags & CVAR_ARCHIVE); // link the variable in @@ -1358,7 +1395,23 @@ cvar_t *Cvar_Get2(const char *name, const char *defaultvalue, int flags, const c var = Cvar_FindVar(name); if (var) + { +#ifdef HAVE_CLIENT + if ((flags & CVAR_USERINFO) && !(var->flags & CVAR_USERINFO)) + { + var->flags |= CVAR_USERINFO; + InfoBuf_SetKey(&cls.userinfo[0], var->name, var->string); + } +#endif +#ifdef HAVE_SERVER + if ((flags & CVAR_SERVERINFO) && !(var->flags & CVAR_SERVERINFO)) + { + var->flags |= CVAR_SERVERINFO; + InfoBuf_SetKey (&svs.info, var->name, var->string); + } +#endif return var; + } if (!description || !*description) description = NULL; @@ -1371,6 +1424,7 @@ cvar_t *Cvar_Get2(const char *name, const char *defaultvalue, int flags, const c strcpy(var->name, name); var->string = (char*)defaultvalue; var->flags = flags|CVAR_POINTER|CVAR_USERCREATED; + var->modifiedcount = 1; //this counter always starts at 1, for q3 compat if (description) { char *desc = var->name+strlen(var->name)+1; @@ -1419,19 +1473,17 @@ Cvar_Command Handles variable inspection and changing from the console ============ */ -qboolean Cvar_Command (int level) +qboolean Cvar_Command (cvar_t *v, int level) { - cvar_t *v; char *str; char buffer[65536]; int olev; // check variables - v = Cvar_FindVar (Cmd_Argv(0)); if (!v) return false; - if (!level || (v->restriction?v->restriction:rcon_level.ival) > level) + if (level==RESTRICT_TEAMPLAY || (v->restriction?v->restriction:rcon_level.ival) > level) { Con_TPrintf ("You do not have the priveledges for %s\n", v->name); return true; diff --git a/engine/common/cvar.h b/engine/common/cvar.h index 653cd6c1..5f7d0d34 100644 --- a/engine/common/cvar.h +++ b/engine/common/cvar.h @@ -62,7 +62,7 @@ typedef struct cvar_s char *string; char *latched_string; // for CVAR_LATCHMASK vars unsigned int flags; - int modified; // increased each time the cvar is changed + qboolean modified; float value; struct cvar_s *next; @@ -73,11 +73,11 @@ typedef struct cvar_s const char *description; char *enginevalue; //when changing manifest dir, the cvar will be reset to this value. never freed. char *defaultstr; //this is the current mod's default value. set on first update. - + qbyte restriction; int ival; vec4_t vec4; //0,0,0,1 if something didn't parse. - qbyte restriction; + int modifiedcount; #ifdef HLSERVER struct hlcvar_s *hlcvar; @@ -206,7 +206,7 @@ char *Cvar_CompleteVariable (const char *partial); // attempts to match a partial variable name for command line completion // returns NULL if nothing fits -qboolean Cvar_Command (int level); +qboolean Cvar_Command (cvar_t *v, int level); // called by Cmd_ExecuteString when Cmd_Argv(0) doesn't match a known // command. Returns true if the command was a variable reference that // was handled. (print or change) diff --git a/engine/common/fs.c b/engine/common/fs.c index 992a8a22..4a0f062a 100644 --- a/engine/common/fs.c +++ b/engine/common/fs.c @@ -24,14 +24,13 @@ static unsigned int fs_restarts; void *fs_thread_mutex; float fs_accessed_time; //timestamp of read (does not include flocates, which should normally happen via a cache). -static cvar_t com_fs_cache = CVARF("fs_cache", IFMINIMAL("2","1"), CVAR_ARCHIVE); -static cvar_t fs_noreexec = CVARD("fs_noreexec", "0", "Disables automatic re-execing configs on gamedir switches.\nThis means your cvar defaults etc may be from the wrong mod, and cfg_save will leave that stuff corrupted!"); -static cvar_t cfg_reload_on_gamedir = CVAR("cfg_reload_on_gamedir", "1"); -static cvar_t fs_game = CVARAFCD("fs_game"/*q3*/, "", "game"/*q2/qs*/, CVAR_NOSAVE|CVAR_NORESET, fs_game_callback, "Provided for Q2 compat."); -#ifdef Q2SERVER -static cvar_t fs_gamedir = CVARFD("fs_gamedir", "", CVAR_NOUNSAFEEXPAND|CVAR_NOSET|CVAR_NOSAVE, "Provided for Q2 compat."); -static cvar_t fs_basedir = CVARFD("fs_basedir", "", CVAR_NOUNSAFEEXPAND|CVAR_NOSET|CVAR_NOSAVE, "Provided for Q2 compat."); -#endif +static cvar_t com_fs_cache = CVARFD ("fs_cache", IFMINIMAL("2","1"), CVAR_ARCHIVE, "0: Do individual lookups.\n1: Scan all files for accelerated lookups. This provides a performance boost on windows and avoids case sensitivity issues on linux.\n2: like 1, but don't bother checking for external changes (avoiding the cost of rebuild the cache)."); +static cvar_t fs_noreexec = CVARD ("fs_noreexec", "0", "Disables automatic re-execing configs on gamedir switches.\nThis means your cvar defaults etc may be from the wrong mod, and cfg_save will leave that stuff corrupted!"); +static cvar_t cfg_reload_on_gamedir = CVAR ("cfg_reload_on_gamedir", "1"); +static cvar_t fs_game = CVARAFCD ("fs_game"/*q3*/, "", "game"/*q2/qs*/, CVAR_NOSAVE|CVAR_NORESET, fs_game_callback, "Provided for Q2 compat. Contains the subdir of the current mod."); +static cvar_t fs_gamepath = CVARAFD ("fs_gamepath"/*q3ish*/, "", "fs_gamedir"/*q2*/, CVAR_NOUNSAFEEXPAND|CVAR_NOSET|CVAR_NOSAVE, "Provided for Q2/Q3 compat. System path of the active gamedir."); +static cvar_t fs_basepath = CVARAFD ("fs_basepath"/*q3*/, "", "fs_basedir"/*q2*/, CVAR_NOUNSAFEEXPAND|CVAR_NOSET|CVAR_NOSAVE, "Provided for Q2/Q3 compat. System path of the base directory."); +static cvar_t fs_homepath = CVARAFD ("fs_homepath"/*q3ish*/, "", "fs_homedir"/*q2ish*/, CVAR_NOUNSAFEEXPAND|CVAR_NOSET|CVAR_NOSAVE, "Provided for Q2/Q3 compat. System path of the base directory."); static cvar_t dpcompat_ignoremodificationtimes = CVARAFD("fs_packageprioritisation", "1", "dpcompat_ignoremodificationtimes", CVAR_NOUNSAFEEXPAND|CVAR_NOSAVE, "Favours the package that is:\n0: Most recently modified\n1: Is alphabetically last (favour z over a, 9 over 0)."); int active_fs_cachetype; static int fs_referencetype; @@ -2564,6 +2563,13 @@ qboolean FS_Rename2(const char *oldf, const char *newf, enum fs_relative oldrela } qboolean FS_Rename(const char *oldf, const char *newf, enum fs_relative relativeto) { + char cleanold[MAX_QPATH]; + char cleannew[MAX_QPATH]; + if (relativeto != FS_SYSTEM) + { + oldf = FS_GetCleanPath(oldf, false, cleanold, sizeof(cleanold)); + newf = FS_GetCleanPath(newf, false, cleannew, sizeof(cleannew)); + } return FS_Rename2(oldf, newf, relativeto, relativeto); } qboolean FS_Remove(const char *fname, enum fs_relative relativeto) @@ -2781,7 +2787,7 @@ qbyte *COM_LoadFile (const char *path, unsigned int locateflags, int usehunk, si return buf; } -qbyte *FS_LoadMallocFile (const char *path, size_t *fsize) +void *FS_LoadMallocFile (const char *path, size_t *fsize) { return COM_LoadFile (path, 0, 5, fsize); } @@ -3872,27 +3878,14 @@ qboolean FS_PathURLCache(const char *url, char *path, size_t pathsize) return true; } -/* -================ -COM_Gamedir - -Sets the gamedir and path to a different directory. -================ -*/ -void COM_Gamedir (const char *dir, const struct gamepacks *packagespaths) +static ftemanifest_t *FS_Manifest_ChangeGameDir(const char *newgamedir) { ftemanifest_t *man; - if (!fs_manifest) - FS_ChangeGame(NULL, true, false); - //we do allow empty here, for base. - if (*dir && !FS_GamedirIsOkay(dir)) - { - Con_Printf ("Gamedir should be a single filename, not \"%s\"\n", dir); - return; - } + if (*newgamedir && !FS_GamedirIsOkay(newgamedir)) + return fs_manifest; - man = FS_Manifest_ReadMod(dir); + man = FS_Manifest_ReadMod(newgamedir); if (!man) { @@ -3906,14 +3899,14 @@ void COM_Gamedir (const char *dir, const struct gamepacks *packagespaths) if (!man) man = FS_Manifest_Clone(fs_manifest); FS_Manifest_PurgeGamedirs(man); - if (*dir) + if (*newgamedir) { char token[MAX_QPATH], quot[MAX_QPATH]; - char *dup = Z_StrDup(dir); //FIXME: is this really needed? - dir = dup; - while ((dir = COM_ParseStringSet(dir, token, sizeof(token)))) + char *dup = Z_StrDup(newgamedir); //FIXME: is this really needed? + newgamedir = dup; + while ((newgamedir = COM_ParseStringSet(newgamedir, token, sizeof(token)))) { - if (!strcmp(dir, ";")) + if (!strcmp(newgamedir, ";")) continue; if (!*token) continue; @@ -3923,20 +3916,52 @@ void COM_Gamedir (const char *dir, const struct gamepacks *packagespaths) } Z_Free(dup); } - while(packagespaths && packagespaths->path) - { - char quot[MAX_QPATH]; - char quot2[MAX_OSPATH]; - char quot3[MAX_OSPATH]; - if (packagespaths->url) - Cmd_TokenizeString(va("package %s prefix %s %s", COM_QuotedString(packagespaths->path, quot, sizeof(quot), false), COM_QuotedString(packagespaths->subpath?packagespaths->subpath:"", quot3, sizeof(quot3), false), COM_QuotedString(packagespaths->url, quot2, sizeof(quot2), false)), false, false); - else - Cmd_TokenizeString(va("package %s prefix %s", COM_QuotedString(packagespaths->path, quot, sizeof(quot), false), COM_QuotedString(packagespaths->subpath?packagespaths->subpath:"", quot3, sizeof(quot3), false)), false, false); - FS_Manifest_ParseTokens(man); - packagespaths++; - } + } + return man; +} + +/* +================ +COM_Gamedir + +Sets the gamedir and path to a different directory. +================ +*/ +void COM_Gamedir (const char *dir, const struct gamepacks *packagespaths) +{ + ftemanifest_t *man; + COM_FlushTempoaryPacks(); + + if (!fs_manifest) + FS_ChangeGame(NULL, true, false); + + //we do allow empty here, for base. + if (*dir && !FS_GamedirIsOkay(dir)) + { + Con_Printf ("Gamedir should be a single filename, not \"%s\"\n", dir); + return; + } + + man = FS_Manifest_ChangeGameDir(dir); + while(packagespaths && packagespaths->path) + { + char quot[MAX_QPATH]; + char quot2[MAX_OSPATH]; + char quot3[MAX_OSPATH]; + if (packagespaths->url) + Cmd_TokenizeString(va("package %s prefix %s %s", COM_QuotedString(packagespaths->path, quot, sizeof(quot), false), COM_QuotedString(packagespaths->subpath?packagespaths->subpath:"", quot3, sizeof(quot3), false), COM_QuotedString(packagespaths->url, quot2, sizeof(quot2), false)), false, false); + else + Cmd_TokenizeString(va("package %s prefix %s", COM_QuotedString(packagespaths->path, quot, sizeof(quot), false), COM_QuotedString(packagespaths->subpath?packagespaths->subpath:"", quot3, sizeof(quot3), false)), false, false); + FS_Manifest_ParseTokens(man); + packagespaths++; } FS_ChangeGame(man, cfg_reload_on_gamedir.ival, false); + +#ifdef HAVE_SERVER + if (!*dir) + dir = FS_GetGamedir(true); + InfoBuf_SetStarKey (&svs.info, "*gamedir", dir); +#endif } #if !defined(HAVE_LEGACY) || !defined(HAVE_CLIENT) @@ -3980,15 +4005,17 @@ void COM_Gamedir (const char *dir, const struct gamepacks *packagespaths) /*set some stuff so our regular qw client appears more like hexen2. sv_mintic is required to 'fix' the ravenstaff so that its projectiles don't impact upon each other*/ #define HEX2CFG "//schemes hexen2\n" "set v_gammainverted 1\nset com_parseutf8 -1\nset gl_font gfx/hexen2\nset in_builtinkeymap 0\nset_calc cl_playerclass int (random * 5) + 1\nset cl_forwardspeed 200\nset cl_backspeed 200\ncl_sidespeed 225\nset sv_maxspeed 640\ncl_run 0\nset watervis 1\nset r_lavaalpha 1\nset r_lavastyle -2\nset r_wateralpha 0.5\nset sv_pupglow 1\ngl_shaftlight 0.5\nsv_mintic 0.015\nset r_meshpitch -1\nset r_meshroll -1\nr_sprite_backfacing 1\nset mod_warnmodels 0\nset cl_model_bobbing 1\nsv_sound_watersplash \"misc/hith2o.wav\"\nsv_sound_land \"fx/thngland.wav\"\nset sv_walkpitch 0\n" /*yay q2!*/ -#define Q2CFG "//schemes quake2\n" "set v_gammainverted 1\nset com_parseutf8 0\ncom_nogamedirnativecode 0\nset sv_bigcoords 0\nsv_port "STRINGIFY(PORT_Q2SERVER)"\n" +#define Q2CFG "//schemes quake2\n" "set v_gammainverted 1\nset com_parseutf8 0\ncom_gamedirnativecode 1\nset sv_bigcoords 0\nsv_port "STRINGIFY(PORT_Q2SERVER)"\ncl_defaultport "STRINGIFY(PORT_Q2SERVER)"\n" /*Q3's ui doesn't like empty model/headmodel/handicap cvars, even if the gamecode copes*/ -#define Q3CFG "//schemes quake3\n" "set v_gammainverted 0\nset snd_ignorecueloops 1\nsetfl g_gametype 0 s\nset gl_clear 1\nset r_clearcolour 0 0 0\nset com_parseutf8 0\ngl_overbright "FORWEB("0","2")"\nseta model sarge\nseta headmodel sarge\nseta handicap 100\ncom_nogamedirnativecode 0\nsv_port "STRINGIFY(PORT_Q3SERVER)"\n" +#define Q3CFG "//schemes quake3\n" "set v_gammainverted 0\nset snd_ignorecueloops 1\nsetfl g_gametype 0 s\nset gl_clear 1\nset r_clearcolour 0 0 0\nset com_parseutf8 0\ngl_overbright "FORWEB("0","2")"\nseta model sarge\nseta headmodel sarge\nseta handicap 100\ncom_gamedirnativecode 1\nsv_port "STRINGIFY(PORT_Q3SERVER)"\ncl_defaultport "STRINGIFY(PORT_Q3SERVER)"\ncom_protocolversion 68\n" //#define RMQCFG "sv_bigcoords 1\n" -#ifdef HAVE_SSL -#define UPDATEURL(g) "/downloadables.php?game=" #g -#else -#define UPDATEURL(g) NULL +#ifndef UPDATEURL + #ifdef HAVE_SSL + #define UPDATEURL(g) "/downloadables.php?game=" #g + #else + #define UPDATEURL(g) NULL + #endif #endif #define QUAKEPROT "FTE-Quake DarkPlaces-Quake" @@ -4002,9 +4029,10 @@ typedef struct { const char *customexec; const char *dir[4]; - const char *poshname; //Full name for the game. - const char *downloadsurl; - const char *manifestfile; + const char *poshname; //Full name for the game. + const char *downloadsurl; //url to check for updates. + const char *needpackages; //package name(s) that are considered mandatory for this game to work. + const char *manifestfile; //contents of manifest file to use. } gamemode_info_t; static const gamemode_info_t gamemode_info[] = { #ifdef GAME_SHORTNAME @@ -4027,7 +4055,7 @@ static const gamemode_info_t gamemode_info[] = { #define GAME_MANIFESTUPDATE NULL #endif - {"-"GAME_SHORTNAME, GAME_SHORTNAME, GAME_PROTOCOL, {GAME_IDENTIFYINGFILES}, GAME_DEFAULTCMDS, {GAME_BASEGAMES}, GAME_FULLNAME, GAME_MANIFESTUPDATE}, + {"-"GAME_SHORTNAME, GAME_SHORTNAME, GAME_PROTOCOL, {GAME_IDENTIFYINGFILES}, GAME_DEFAULTCMDS, {GAME_BASEGAMES}, GAME_FULLNAME, NULL/*updateurl*/, NULL/*needpackages*/, GAME_MANIFESTUPDATE}, #endif //note that there is no basic 'fte' gamemode, this is because we aim for network compatability. Darkplaces-Quake is the closest we get. //this is to avoid having too many gamemodes anyway. @@ -4089,8 +4117,8 @@ static const gamemode_info_t gamemode_info[] = { #endif #if defined(Q3CLIENT) || defined(Q3SERVER) - {"-quake3", "q3", "Quake3", {"baseq3/pak0.pk3"}, Q3CFG, {"baseq3", "*fteq3"}, "Quake III Arena", UPDATEURL(Q3)}, - {"-quake3demo", "q3demo", "Quake3Demo", {"demoq3/pak0.pk3"}, Q3CFG, {"demoq3", "*fteq3"}, "Quake III Arena Demo"}, + {"-quake3", "q3", "Quake3", {"baseq3/pak0.pk3"}, Q3CFG, {"baseq3", "*fteq3"}, "Quake III Arena", UPDATEURL(Q3), "quake3"}, + {"-quake3demo", "q3demo", "Quake3Demo", {"demoq3/pak0.pk3"}, Q3CFG, {"demoq3", "*fteq3"}, "Quake III Arena Demo", NULL, "quake3"}, //the rest are not supported in any real way. maps-only mostly, if that // {"-quake4", "q4", "FTE-Quake4", {"q4base/pak00.pk4"}, NULL, {"q4base", "*fteq4"}, "Quake 4"}, // {"-et", NULL, "FTE-EnemyTerritory", {"etmain/pak0.pk3"}, NULL, {"etmain", "*fteet"}, "Wolfenstein - Enemy Territory"}, @@ -4419,8 +4447,9 @@ qboolean CL_ListFilesInPackage(searchpathfuncs_t *search, char *name, int (QDECL return ret; } -void FS_PureMode(int puremode, char *purenamelist, char *purecrclist, char *refnamelist, char *refcrclist, int pureseed) +void FS_PureMode(const char *gamedir, int puremode, char *purenamelist, char *purecrclist, char *refnamelist, char *refcrclist, int pureseed) { + ftemanifest_t *man; qboolean pureflush; #ifdef HAVE_SERVER @@ -4451,7 +4480,12 @@ void FS_PureMode(int puremode, char *purenamelist, char *purecrclist, char *refn fs_refnames = refnamelist?Z_StrDup(refnamelist):NULL; fs_refcrcs = refcrclist?Z_StrDup(refcrclist):NULL; - FS_ChangeGame(fs_manifest, false, false); + if (gamedir) + man = FS_Manifest_ChangeGameDir(gamedir); + else + man = fs_manifest; + + FS_ChangeGame(man, false, false); if (pureflush) { @@ -6146,7 +6180,13 @@ qboolean FS_ChangeGame(ftemanifest_t *man, qboolean allowreloadconfigs, qboolean Cmd_TokenizeString(va("downloadsurl \"%s\"", gamemode_info[i].downloadsurl), false, false); FS_Manifest_ParseTokens(man); } + if (!man->installupd && gamemode_info[i].needpackages) + { + Cmd_TokenizeString(va("install \"%s\"", gamemode_info[i].needpackages), false, false); + FS_Manifest_ParseTokens(man); + } #endif + if (!man->protocolname) { Cmd_TokenizeString(va("protocolname \"%s\"", gamemode_info[i].protocolname), false, false); @@ -6357,10 +6397,9 @@ qboolean FS_ChangeGame(ftemanifest_t *man, qboolean allowreloadconfigs, qboolean Cvar_ForceSet(&fs_game, FS_GetGamedir(false)); fs_game.callback = callback; } -#ifdef Q2SERVER - Cvar_ForceSet(&fs_gamedir, va("%s%s", com_gamepath, FS_GetGamedir(false))); - Cvar_ForceSet(&fs_basedir, com_gamepath); -#endif + Cvar_ForceSet(&fs_gamepath, va("%s%s", com_gamepath, FS_GetGamedir(false))); + Cvar_ForceSet(&fs_basepath, com_gamepath); + Cvar_ForceSet(&fs_homepath, com_gamepath); Mods_FlushModList(); @@ -6624,7 +6663,8 @@ qboolean FS_FixupGamedirForExternalFile(char *input, char *filename, size_t fnam return false; } - +void Cvar_GamedirChange(void); +void Plug_Shutdown(qboolean preliminary); /*mod listing management*/ static struct modlist_s *modlist; @@ -6831,7 +6871,7 @@ static void FS_ModInstallGot(struct dl_download *dl) if (ctx->man && !strcmp(ctx->man->basedir, com_gamepath)) { //should probably show just the hostname for brevity. - Menu_Prompt(FS_ModInstallConfirmed, ctx, va("Install %s from\n%s ?", ctx->man->formalname, ctx->url), "Install", NULL, "Cancel"); + Menu_Prompt(FS_ModInstallConfirmed, ctx, va("Install %s from\n%s ?", ctx->man->formalname, ctx->url), "Install", NULL, "Cancel", true); return; } } @@ -6947,6 +6987,19 @@ static void FS_ChangeGame_f(void) } else { + arg = Z_StrDup(arg); +#ifdef HAVE_SERVER + if (sv.state) + SV_UnspawnServer(); +#endif +#ifdef HAVE_CLIENT + CL_Disconnect (NULL); +#endif +#ifdef PLUGINS + Plug_Shutdown(true); +#endif + Cvar_GamedirChange(); + if (strrchr(arg, '/') && !strrchr(arg, '/')[1]) { //ends in slash. a new basedir. Q_strncpyz(com_gamepath, arg, sizeof(com_gamepath)); @@ -6961,15 +7014,27 @@ static void FS_ChangeGame_f(void) { Con_Printf("Switching to %s\n", gamemode_info[i].argname+1); FS_ChangeGame(FS_GenerateLegacyManifest(i, NULL), true, true); - return; + break; } } + if (!gamemode_info[i].argname) + { #ifdef HAVE_CLIENT - if (!Host_RunFile(arg, strlen(arg), NULL)) - Con_Printf("Game unknown\n"); + if (!Host_RunFile(arg, strlen(arg), NULL)) + Con_Printf("Game unknown\n"); #endif + } } + Z_Free((char*)arg); + +#ifdef PLUGINS + Plug_Initialise(true); +#endif +#if defined(HAVE_CLIENT) && defined(Q3CLIENT) + if (q3) + q3->ui.Start(); +#endif } } @@ -7421,10 +7486,9 @@ void COM_InitFilesystem (void) Cvar_Register(&com_protocolname, "Server Info"); Cvar_Register(&com_protocolversion, "Server Info"); Cvar_Register(&fs_game, "Filesystem"); -#ifdef Q2SERVER - Cvar_Register(&fs_gamedir, "Filesystem"); - Cvar_Register(&fs_basedir, "Filesystem"); -#endif + Cvar_Register(&fs_gamepath, "Filesystem"); + Cvar_Register(&fs_basepath, "Filesystem"); + Cvar_Register(&fs_homepath, "Filesystem"); COM_InitHomedir(NULL); diff --git a/engine/common/fs.h b/engine/common/fs.h index 13eac6e0..cbf3a4e6 100644 --- a/engine/common/fs.h +++ b/engine/common/fs.h @@ -74,7 +74,7 @@ void FS_AddHashedPackage(searchpath_t **oldpaths, const char *parent_pure, const 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_GeneratePackageFromMeta(vfsfile_t *file, char *fname, size_t fnamesize, enum fs_relative *fsroot); void PM_FileInstalled(const char *filename, enum fs_relative fsroot, void *metainfo, qboolean enable); //we finished installing a file via some other mechanism (drag+drop or from server. insert it into the updates menu. -void PM_EnumeratePlugins(void (*callback)(const char *name)); +void PM_EnumeratePlugins(void (*callback)(const char *name, qboolean blocked)); struct xcommandargcompletioncb_s; void PM_EnumerateMaps(const char *partial, struct xcommandargcompletioncb_s *ctx); void PM_LoadMap(const char *package, const char *map); diff --git a/engine/common/huff.c b/engine/common/huff.c index 9dba84d9..28acb90f 100644 --- a/engine/common/huff.c +++ b/engine/common/huff.c @@ -486,6 +486,7 @@ static void Huff_Init(huffman_t *huff) Huff_addRef(&huff->decompressor, (qbyte)i); } } + huff->built = true; } diff --git a/engine/common/log.c b/engine/common/log.c index 88800ec6..1a9cbeba 100644 --- a/engine/common/log.c +++ b/engine/common/log.c @@ -848,7 +848,7 @@ qboolean CertLog_ConnectOkay(const char *hostname, void *cert, size_t certsize, text[len] = 0; //FIXME: display some sort of fingerprint - Menu_Prompt(CertLog_Add_Prompted, ctx, text, accepttext, NULL, localtext("Disconnect")); + Menu_Prompt(CertLog_Add_Prompted, ctx, text, accepttext, NULL, localtext("Disconnect"), true); } return false; //can't connect yet... } diff --git a/engine/common/net.h b/engine/common/net.h index 52319342..5c877a93 100644 --- a/engine/common/net.h +++ b/engine/common/net.h @@ -72,6 +72,10 @@ typedef struct netadr_s netadrtype_t type; netproto_t prot; + unsigned short port; + unsigned short connum; //which quake connection/socket the address is talking about. 1-based. 0 is unspecified. this is NOT used for address equivelency. + unsigned int scopeid; //ipv6 interface id thing. + union { qbyte ip[4]; qbyte ip6[16]; @@ -97,10 +101,6 @@ typedef struct netadr_s } un; #endif } address; - - unsigned short port; - unsigned short connum; //which quake connection/socket the address is talking about. 1-based. 0 is unspecified. this is NOT used for address equivelency. - unsigned int scopeid; //ipv6 interface id thing. } netadr_t; struct sockaddr_qstorage diff --git a/engine/common/net_chan.c b/engine/common/net_chan.c index 75c7ac11..d01d259c 100644 --- a/engine/common/net_chan.c +++ b/engine/common/net_chan.c @@ -451,7 +451,7 @@ enum nqnc_packettype_e NQNetChan_Process(netchan_t *chan) int drop; chan->bytesin += net_message.cursize; - MSG_BeginReading (chan->netprim); + MSG_BeginReading (&net_message, chan->netprim); header = LongSwap(MSG_ReadLong()); @@ -486,7 +486,7 @@ enum nqnc_packettype_e NQNetChan_Process(netchan_t *chan) } memcpy(net_message.data, tmp, net_message.cursize); - MSG_BeginReading (chan->netprim); + MSG_BeginReading (&net_message, chan->netprim); header = LongSwap(MSG_ReadLong()); //re-read the now-decompressed copy of the header for the real flags } #endif @@ -598,7 +598,7 @@ enum nqnc_packettype_e NQNetChan_Process(netchan_t *chan) SZ_Clear(&net_message); SZ_Write(&net_message, chan->in_fragment_buf, chan->in_fragment_length); chan->in_fragment_length = 0; - MSG_BeginReading(chan->netprim); + MSG_BeginReading(&net_message, chan->netprim); if (showpackets.value) Con_Printf ("in %s r=%i %i\n" @@ -1001,7 +1001,7 @@ qboolean Netchan_Process (netchan_t *chan) chan->bytesin += net_message.cursize; // get sequence numbers - MSG_BeginReading (chan->netprim); + MSG_BeginReading (&net_message, chan->netprim); sequence = MSG_ReadLong (); sequence_ack = MSG_ReadLong (); diff --git a/engine/common/net_ssl_gnutls.c b/engine/common/net_ssl_gnutls.c index 1df0eeb6..4b51db1f 100644 --- a/engine/common/net_ssl_gnutls.c +++ b/engine/common/net_ssl_gnutls.c @@ -12,88 +12,6 @@ #ifdef HAVE_GNUTLS -#if defined(_WIN32) && !defined(MINGW) && 0 - -#define GNUTLS_VERSION "2.12.23" -#define GNUTLS_SOPREFIX "" -#define GNUTLS_SONUM 26 - -#ifdef _MSC_VER -#if SIZE_MAX == ULONG_MAX -#define ssize_t long -#else -#define ssize_t int -#endif -#endif - -//lets rip stuff out of the header and supply a seperate dll. -//gnutls is huge. -//also this helps get around the whole msvc/mingw thing. - -struct DSTRUCT; -typedef struct DSTRUCT* gnutls_certificate_credentials_t; -typedef gnutls_certificate_credentials_t gnutls_certificate_client_credentials_t; -typedef struct DSTRUCT* gnutls_anon_client_credentials_t; -struct gnutls_session_int; -typedef struct gnutls_session_int* gnutls_session_t; -typedef void * gnutls_transport_ptr_t; -struct gnutls_x509_crt_int; -typedef struct gnutls_x509_crt_int *gnutls_x509_crt_t; -typedef struct -{ - unsigned char *data; - unsigned int size; -} gnutls_datum_t; - -typedef enum gnutls_kx_algorithm { GNUTLS_KX_RSA=1, GNUTLS_KX_DHE_DSS, - GNUTLS_KX_DHE_RSA, GNUTLS_KX_ANON_DH, GNUTLS_KX_SRP, - GNUTLS_KX_RSA_EXPORT, GNUTLS_KX_SRP_RSA, GNUTLS_KX_SRP_DSS -} gnutls_kx_algorithm; -typedef enum { - GNUTLS_CRT_UNKNOWN = 0, - GNUTLS_CRT_X509 = 1, - GNUTLS_CRT_OPENPGP = 2, - GNUTLS_CRT_RAW = 3 -} gnutls_certificate_type_t; -typedef enum { - GNUTLS_X509_FMT_DER = 0, - GNUTLS_X509_FMT_PEM = 1 -} gnutls_x509_crt_fmt_t; -typedef enum -{ - GNUTLS_CERT_INVALID = 1<<1, - GNUTLS_CERT_REVOKED = 1<<5, - GNUTLS_CERT_SIGNER_NOT_FOUND = 1<<6, - GNUTLS_CERT_SIGNER_NOT_CA = 1<<7, - GNUTLS_CERT_INSECURE_ALGORITHM = 1<<8, - GNUTLS_CERT_NOT_ACTIVATED = 1<<9, - GNUTLS_CERT_EXPIRED = 1<<10, - GNUTLS_CERT_SIGNATURE_FAILURE = 1<<11, - GNUTLS_CERT_REVOCATION_DATA_SUPERSEDED = 1<<12, - GNUTLS_CERT_UNEXPECTED_OWNER = 1<<14, - GNUTLS_CERT_REVOCATION_DATA_ISSUED_IN_FUTURE = 1<<15, - GNUTLS_CERT_SIGNER_CONSTRAINTS_FAILURE = 1<<16, - GNUTLS_CERT_MISMATCH = 1<<17, -} gnutls_certificate_status_t; -typedef enum gnutls_connection_end { GNUTLS_SERVER=1, GNUTLS_CLIENT } gnutls_connection_end_t; -typedef enum gnutls_credentials_type { GNUTLS_CRD_CERTIFICATE=1, GNUTLS_CRD_ANON, GNUTLS_CRD_SRP } gnutls_credentials_type_t; -typedef enum gnutls_close_request { GNUTLS_SHUT_RDWR=0, GNUTLS_SHUT_WR=1 } gnutls_close_request_t; -typedef ssize_t (*gnutls_pull_func) (gnutls_transport_ptr_t, void *, size_t); -typedef ssize_t (*gnutls_push_func) (gnutls_transport_ptr_t, const void *, size_t); - -#define GNUTLS_E_AGAIN -28 -#define GNUTLS_E_CERTIFICATE_ERROR -43 -#define GNUTLS_E_INTERRUPTED -52 -#define GNUTLS_E_PREMATURE_TERMINATION -110 - -typedef enum -{ - GNUTLS_NAME_DNS = 1 -} gnutls_server_name_type_t; - -typedef int (VARGS gnutls_certificate_verify_function)(gnutls_session_t session); - -#else #include #if GNUTLS_VERSION_MAJOR >= 3 #include @@ -128,7 +46,6 @@ typedef int (VARGS gnutls_certificate_verify_function)(gnutls_session_t session) #ifndef GNUTLS_SOPREFIX #define GNUTLS_SOPREFIX #endif -#endif #if GNUTLS_VERSION_MAJOR >= 3 #if GNUTLS_VERSION_MAJOR >= 3 diff --git a/engine/common/plugin.c b/engine/common/plugin.c index 1bc61dbe..38b4e84f 100644 --- a/engine/common/plugin.c +++ b/engine/common/plugin.c @@ -9,6 +9,9 @@ #define FTEENGINE #include "../plugins/plugin.h" +struct q3gamecode_s *q3; +static struct plugin_s *q3plug; + #ifdef PLUGINS #ifdef MODELFMT_GLTF @@ -21,6 +24,7 @@ cvar_t plug_sbar = CVARD("plug_sbar", "3", "Controls whether plugins are allowed to draw the hud, rather than the engine (when allowed by csqc). This is typically used to permit the ezhud plugin without needing to bother unloading it.\n=0: never use hud plugins.\n&1: Use hud plugins in deathmatch.\n&2: Use hud plugins in singleplayer/coop.\n=3: Always use hud plugins (when loaded)."); cvar_t plug_loaddefault = CVARD("plug_loaddefault", "1", "0: Load plugins only via explicit plug_load commands\n1: Load built-in plugins and those selected via the package manager\n2: Scan for misc plugins, loading all that can be found, but not built-ins.\n3: Scan for plugins, and then load any built-ins"); +qboolean Plug_Q3_Init(void); static struct { const char *name; @@ -36,6 +40,10 @@ static struct #if defined(MODELFMT_GLTF) {"GLTF", Plug_GLTF_Init}, #endif + +#ifdef STATIC_Q3 + {"Q3", Plug_Q3_Init}, +#endif {NULL} }; //for internal plugins to link against @@ -87,7 +95,6 @@ typedef struct plugin_s { dllhandle_t *lib; void (QDECL *tick)(double realtime, double gametime); - qboolean (QDECL *executestring)(qboolean isinsecure); #ifndef SERVERONLY qboolean (QDECL *consolelink)(void); qboolean (QDECL *consolelinkmouseover)(float x, float y); @@ -116,6 +123,7 @@ plugin_t *currentplug; #ifndef SERVERONLY #include "cl_plugin.inc" +#include "cl_master.h" #else void Plug_Client_Init(void){} void Plug_Client_Close(plugin_t *plug) {} @@ -275,9 +283,22 @@ static plugin_t *Plug_Load(const char *file) return newplug; } -static void Plug_Load_Update(const char *name) +static void Plug_Load_Update(const char *name, qboolean blocked) { - Plug_Load(name); + if (blocked) + { //plugins can be blocked by gametypes (to prevents conflicts) + plugin_t *plug; + for (plug = plugs; plug; plug = plug->next) + { + if (!strcmp(plug->name, name)) + { + Plug_Close(plug); + return; + } + } + } + else + Plug_Load(name); } static int QDECL Plug_EnumeratedRoot (const char *name, qofs_t size, time_t mtime, void *param, searchpathfuncs_t *spath) @@ -311,10 +332,6 @@ static void QDECL Plug_Con_Print(const char *text) { Con_Printf("%s", text); } -static void QDECL Plug_Sys_Error(const char *text) -{ - Sys_Error("%s", text); -} static quintptr_t QDECL Plug_Sys_Milliseconds(void) { return Sys_DoubleTime()*1000u; @@ -322,10 +339,10 @@ static quintptr_t QDECL Plug_Sys_Milliseconds(void) qboolean VARGS PlugBI_ExportFunction(const char *name, funcptr_t function) { + if (!currentplug) + return false; if (!strcmp(name, "Tick")) //void(int realtime) currentplug->tick = function; - else if (!strcmp(name, "ExecuteCommand")) //bool(isinsecure) - currentplug->executestring = function; else if (!strcmp(name, "Shutdown")) //void() currentplug->shutdown = function; else if (!strcmp(name, "MayShutdown")||!strcmp(name, "MayUnload")) @@ -407,6 +424,20 @@ static qboolean QDECL PlugBI_ExportInterface(const char *name, void *interfacept #endif if (!strcmp(name, "Crypto")) return NET_RegisterCrypto(currentplug, interfaceptr); +#if defined(Q3SERVER)||defined(Q3CLIENT) + if (!strcmp(name, "Quake3Plugin") && sizeof(*q3) == structsize) + { + if (q3plug) + { + struct plugin_s *p = currentplug; + Plug_Close(q3plug); + currentplug = p; + } + q3 = interfaceptr; + q3plug = currentplug; + return true; + } +#endif #ifdef HAVE_CLIENT if (!strcmp(name, plugvrfuncs_name)) return R_RegisterVRDriver(currentplug, interfaceptr); @@ -429,65 +460,14 @@ static cvar_t *QDECL Plug_Cvar_GetNVFDG(const char *name, const char *defaultval return Cvar_Get2(name, defaultvalue, flags&1, description, groupname); } - -typedef struct { - //Make SURE that the engine has resolved all cvar pointers into globals before this happens. - plugin_t *plugin; - cvar_t *var; -} plugincvararray_t; -static int plugincvararraylen; -static plugincvararray_t *plugincvararray; -//qhandle_t Cvar_Register (char *name, char *defaultval, int flags, char *grouphint); -static qhandle_t QDECL Plug_Cvar_Register(const char *name, const char *defaultvalue, int flags, const char *groupname) -{ - cvar_t *var; - int i; - - var = Cvar_Get(name, defaultvalue, flags&1, groupname); - - for (i = 0; i < plugincvararraylen; i++) - { - if (!plugincvararray[i].var) - { //hmm... a gap... - plugincvararray[i].plugin = currentplug; - plugincvararray[i].var = var; - return i; - } - } - - i = plugincvararraylen; - plugincvararraylen++; - plugincvararray = BZ_Realloc(plugincvararray, (plugincvararraylen)*sizeof(plugincvararray_t)); - plugincvararray[i].plugin = currentplug; - plugincvararray[i].var = var; - return i; -} -//int Cvar_Update, (qhandle_t handle, int modificationcount, char *stringv, float *floatv)); //stringv is 256 chars long, don't expect this function to do anything if modification count is unchanged. -static qboolean QDECL Plug_Cvar_Update(qhandle_t handle, int *modificationcount, char *outstringv, size_t stringsize, float *outfloatv) -{ - cvar_t *var; - if (handle < 0 || handle >= plugincvararraylen) - return false; - if (plugincvararray[handle].plugin != currentplug) - return false; //I'm not letting you know what annother plugin has registered. - - var = plugincvararray[handle].var; - - //if (var->modified != *modificationcount) //for future optimisation - { - //*modificationcount = var->modified; - Q_strncpyz(outstringv, var->string, stringsize); - *outfloatv = var->value; - return true; - } - return false; -} - static void QDECL Plug_Cmd_TokenizeString(const char *text) { Cmd_TokenizeString(text, false, false); } - +static void QDECL Plug_Cmd_ShiftArgs(int args) +{ + Cmd_ShiftArgs(args, false); +} //void Cmd_Args(char *buffer, int buffersize) static void QDECL Plug_Cmd_Args(char *buffer, int maxsize) { @@ -502,7 +482,7 @@ static void QDECL Plug_Cmd_Args(char *buffer, int maxsize) strcpy(buffer, args); } //void Cmd_Argv(int num, char *buffer, int buffersize) -static void QDECL Plug_Cmd_Argv(int argn, char *outbuffer, size_t buffersize) +static char *QDECL Plug_Cmd_Argv(int argn, char *outbuffer, size_t buffersize) { char *args; args = Cmd_Argv(argn); @@ -514,6 +494,7 @@ static void QDECL Plug_Cmd_Argv(int argn, char *outbuffer, size_t buffersize) } else strcpy(outbuffer, args); + return args; } //int Cmd_Argc(void) static int QDECL Plug_Cmd_Argc(void) @@ -528,6 +509,13 @@ static void QDECL Plug_Cvar_SetString(const char *name, const char *value) if (var) Cvar_Set(var, value); } +//void Cvar_SetString (char *name, char *value); +static void QDECL Plug_Cvar_ForceSetString(const char *name, const char *value) +{ + cvar_t *var = Cvar_Get(name, value, 0, "Plugin vars"); + if (var) + Cvar_ForceSet(var, value); +} //void Cvar_SetFloat (char *name, float value); static void QDECL Plug_Cvar_SetFloat(const char *cvarname, float newvalue) @@ -573,6 +561,8 @@ static qboolean QDECL Plug_Cvar_GetString(const char *name, char *outbuffer, qui else { var = Cvar_Get(name, "", 0, "Plugin vars"); + if (!var) + return false; if (strlen(var->name)+1 > sizeofbuffer) return false; @@ -592,10 +582,16 @@ static void QDECL Plug_Cmd_AddText(const char *text, qboolean insert) Cbuf_AddText(text, level); } +static qboolean QDECL Plug_Cmd_IsInsecure(void) +{ + return Cmd_IsInsecure(); +} + static int plugincommandarraylen; typedef struct { plugin_t *plugin; char command[64]; + xcommand_t func; } plugincommand_t; static plugincommand_t *plugincommandarray; void Plug_Command_f(void) @@ -605,7 +601,7 @@ void Plug_Command_f(void) plugin_t *oldplug = currentplug; for (i = 0; i < plugincommandarraylen; i++) { - if (!plugincommandarray[i].plugin) + if (!plugincommandarray[i].func) continue; //don't check commands who's owners died. if (Q_strcasecmp(plugincommandarray[i].command, cmd)) //not the right command @@ -613,17 +609,46 @@ void Plug_Command_f(void) currentplug = plugincommandarray[i].plugin; - if (currentplug->executestring) - currentplug->executestring(Cmd_IsInsecure()); + plugincommandarray[i].func(); break; } currentplug = oldplug; } -static qboolean QDECL Plug_Cmd_AddCommand(const char *name) +static qboolean QDECL Plug_Cmd_AddCommand(const char *name, xcommand_t func, const char *desc) { int i; + if (!currentplug) + return false; + for (i = 0; i < plugincommandarraylen; i++) + { + if (!plugincommandarray[i].plugin) + break; + if (plugincommandarray[i].plugin == currentplug) + { + if (!strcmp(name, plugincommandarray[i].command)) + return true; //already registered + } + } + if (i == plugincommandarraylen) + { + plugincommandarraylen++; + plugincommandarray = BZ_Realloc(plugincommandarray, plugincommandarraylen*sizeof(plugincommand_t)); + } + + Q_strncpyz(plugincommandarray[i].command, name, sizeof(plugincommandarray[i].command)); + if (!Cmd_AddCommandD(plugincommandarray[i].command, Plug_Command_f, desc)) + return false; + plugincommandarray[i].plugin = currentplug; //worked + plugincommandarray[i].func = func; //worked + return true; +} +static qboolean QDECL Plug_Cmd_AddCommandOld(const char *name) +{ + int i; + if (!currentplug) + return false; for (i = 0; i < plugincommandarraylen; i++) { if (!plugincommandarray[i].plugin) @@ -644,6 +669,7 @@ static qboolean QDECL Plug_Cmd_AddCommand(const char *name) if (!Cmd_AddCommand(plugincommandarray[i].command, Plug_Command_f)) return false; plugincommandarray[i].plugin = currentplug; //worked + plugincommandarray[i].func = NULL; //worked return true; } static void Plug_FreeConCommands(plugin_t *plug) @@ -654,7 +680,9 @@ static void Plug_FreeConCommands(plugin_t *plug) if (plugincommandarray[i].plugin == plug) { plugincommandarray[i].plugin = NULL; + plugincommandarray[i].func = NULL; Cmd_RemoveCommand(plugincommandarray[i].command); + *plugincommandarray[i].command = 0; } } } @@ -1198,11 +1226,11 @@ void Plug_Initialise(qboolean fromgamedir) if (plug_loaddefault.ival & 1) { unsigned int u; - PM_EnumeratePlugins(Plug_Load_Update); for (u = 0; staticplugins[u].name; u++) { Plug_Load(staticplugins[u].name); } + PM_EnumeratePlugins(Plug_Load_Update); } } @@ -1240,27 +1268,6 @@ void Plug_ResChanged(void) } #endif -qboolean Plugin_ExecuteString(void) -{ - plugin_t *oldplug = currentplug; - if (Cmd_Argc()>0) - { - for (currentplug = plugs; currentplug; currentplug = currentplug->next) - { - if (currentplug->executestring) - { - if (currentplug->executestring(0)) - { - currentplug = oldplug; - return true; - } - } - } - } - currentplug = oldplug; - return false; -} - #ifndef SERVERONLY qboolean Plug_ConsoleLinkMouseOver(float x, float y, char *text, char *info) { @@ -1552,6 +1559,12 @@ void Plug_Close(plugin_t *plug) FS_UnRegisterFileSystemModule(plug); Mod_UnRegisterAllModelFormats(plug); + if (q3plug == plug) + { + q3 = NULL; + q3plug = NULL; + } + //tell the plugin that everything is closed and that it should free up any lingering memory/stuff //it is still allowed to create/have open files. if (plug->shutdown) @@ -1766,17 +1779,9 @@ void Plug_Shutdown(qboolean preliminary) pluginstreamarray = NULL; pluginstreamarraylen = 0; - plugincvararraylen = 0; - BZ_Free(plugincvararray); - plugincvararray = NULL; - plugincommandarraylen = 0; BZ_Free(plugincommandarray); plugincommandarray = NULL; - -#ifndef SERVERONLY - Plug_Client_Shutdown(); -#endif } } @@ -1789,8 +1794,10 @@ plugcorefuncs_t plugcorefuncs = PlugBI_ExportInterface, PlugBI_GetPluginName, Plug_Con_Print, - Plug_Sys_Error, + Sys_Error, + Host_EndGame, Plug_Sys_Milliseconds, + Sys_DoubleTime, Sys_LoadLibrary, Sys_GetAddressForName, Sys_CloseLibrary, @@ -1799,6 +1806,7 @@ plugcorefuncs_t plugcorefuncs = BZ_Realloc, Z_Free, ZG_Malloc, + ZG_Free, ZG_FreeGroup, }; @@ -1817,9 +1825,11 @@ static void *QDECL PlugBI_GetEngineInterface(const char *interfacename, size_t s COM_ParseType, COM_ParseTokenOut, Plug_Cmd_TokenizeString, + Plug_Cmd_ShiftArgs, Plug_Cmd_Args, Plug_Cmd_Argv, Plug_Cmd_Argc, + Plug_Cmd_IsInsecure, Plug_Cmd_AddCommand, Plug_Cmd_AddText, }; @@ -1829,12 +1839,12 @@ static void *QDECL PlugBI_GetEngineInterface(const char *interfacename, size_t s qboolean (QDECL*AddCommand) (const char *cmdname); void (QDECL*TokenizeString) (const char *msg); void (QDECL*Args) (char *buffer, int bufsize); - void (QDECL*Argv) (int argnum, char *buffer, size_t bufsize); + char * (QDECL*Argv) (int argnum, char *buffer, size_t bufsize); int (QDECL*Argc) (void); void (QDECL*AddText) (const char *text, qboolean insert); } oldfuncs = { - Plug_Cmd_AddCommand, + Plug_Cmd_AddCommandOld, Plug_Cmd_TokenizeString, Plug_Cmd_Args, Plug_Cmd_Argv, @@ -1854,9 +1864,8 @@ static void *QDECL PlugBI_GetEngineInterface(const char *interfacename, size_t s Plug_Cvar_SetFloat, Plug_Cvar_GetString, Plug_Cvar_GetFloat, - Plug_Cvar_Register, - Plug_Cvar_Update, Plug_Cvar_GetNVFDG, + Plug_Cvar_ForceSetString, }; if (structsize == sizeof(funcs)) return &funcs; @@ -1872,8 +1881,12 @@ static void *QDECL PlugBI_GetEngineInterface(const char *interfacename, size_t s Plug_FS_Seek, Plug_FS_GetLength, + FS_FLocateFile, FS_OpenVFS, FS_NativePath, + + FS_Rename, + FS_Remove, COM_EnumerateFiles, wildcmp, @@ -1882,6 +1895,50 @@ static void *QDECL PlugBI_GetEngineInterface(const char *interfacename, size_t s COM_CleanUpPath, Com_BlockChecksum, FS_LoadMallocFile, + + FS_GetPackHashes, + FS_GetPackNames, + FS_GenCachedPakName, +#ifdef HAVE_CLIENT + FS_PureMode, +#endif +#ifdef Q3CLIENT + FSQ3_GenerateClientPacksList, +#endif + }; + if (structsize == sizeof(funcs)) + return &funcs; + } + if (!strcmp(interfacename, plugmsgfuncs_name)) + { + static plugmsgfuncs_t funcs = + { + MSG_BeginReading, + MSG_GetReadCount, + MSG_ReadBits, + MSG_ReadByte, + MSG_ReadShort, + MSG_ReadLong, + MSG_ReadData, + MSG_ReadString, + + MSG_BeginWriting, + MSG_WriteBits, + MSG_WriteByte, + MSG_WriteShort, + MSG_WriteLong, + SZ_Write, + MSG_WriteString, + + NET_CompareAdr, + NET_CompareBaseAdr, + NET_AdrToString, + NET_StringToAdr2, + NET_SendPacket, + + Huff_CompressionCRC, + Huff_EncryptPacket, + Huff_DecryptPacket, }; if (structsize == sizeof(funcs)) return &funcs; @@ -1915,16 +1972,44 @@ static void *QDECL PlugBI_GetEngineInterface(const char *interfacename, size_t s if (structsize == sizeof(funcs)) return &funcs; } + if (!strcmp(interfacename, plugworldfuncs_name)) + { + static plugworldfuncs_t funcs = + { + Mod_ForName, + Mod_FixName, + Mod_GetEntitiesString, + + World_TransformedTrace, + CM_TempBoxModel, + + InfoBuf_ToString, + InfoBuf_FromString, + InfoBuf_SetKey, + InfoBuf_ValueForKey, + Info_ValueForKey, + Info_SetValueForKey, + + SV_DropClient, + SV_ExtractFromUserinfo, + SV_ChallengePasses, + }; + if (structsize == sizeof(funcs)) + return &funcs; + } #ifdef HAVE_CLIENT if (!strcmp(interfacename, plug2dfuncs_name)) { static plug2dfuncs_t funcs = { + Plug_Draw_GetScreenSize, Plug_Draw_LoadImageData, Plug_Draw_LoadImageShader, Plug_Draw_LoadImagePic, - Plug_Draw_UnloadImage, + Plug_Draw_ShaderFromId, + NULL,//Plug_Draw_UnloadImage, Plug_Draw_Image, + Plug_Draw_Image2dQuad, Plug_Draw_ImageSize, Plug_Draw_Fill, Plug_Draw_Line, @@ -1936,11 +2021,41 @@ static void *QDECL PlugBI_GetEngineInterface(const char *interfacename, size_t s Plug_Draw_ColourP, Plug_Draw_Colour4f, + Plug_Draw_RedrawScreen, + Plug_LocalSound, }; if (structsize == sizeof(funcs)) return &funcs; } + if (!strcmp(interfacename, plug3dfuncs_name)) + { + static plug3dfuncs_t funcs = + { + Mod_ForName, + Plug_Scene_ModelToId, + Plug_Scene_ModelFromId, + R_RemapShader, + Plug_Scene_ShaderForSkin, + Mod_RegisterSkinFile, + Mod_LookupSkin, + Mod_TagNumForName, + Mod_GetTag, + Mod_ClipDecal, + + Surf_NewMap, + Plug_Scene_Clear, + V_AddAxisEntity, + Plug_Scene_AddPolydata, + + CL_NewDlight, + CL_AllocDlightOrg, + R_CalcModelLighting, + Plug_Scene_RenderScene, + }; + if (structsize == sizeof(funcs)) + return &funcs; + } if (!strcmp(interfacename, plugclientfuncs_name)) { static plugclientfuncs_t funcs = @@ -1969,6 +2084,9 @@ static void *QDECL PlugBI_GetEngineInterface(const char *interfacename, size_t s NULL, NULL, #endif + + Plug_CL_ClearState, + Plug_CL_UpdateGameTime, }; if (structsize == sizeof(funcs)) return &funcs; @@ -1980,6 +2098,9 @@ static void *QDECL PlugBI_GetEngineInterface(const char *interfacename, size_t s Plug_SetMenuFocus, Plug_HasMenuFocus, + Menu_Push, + Menu_Unlink, + //for menu input Plug_Key_GetKeyCode, Plug_Key_GetKeyName, @@ -1987,12 +2108,18 @@ static void *QDECL PlugBI_GetEngineInterface(const char *interfacename, size_t s Plug_Key_GetKeyBind, Plug_Key_SetKeyBind, + Plug_Input_IsKeyDown, + Plug_Input_ClearKeyStates, + Plug_Input_GetMoveCount, + Plug_Input_GetMoveEntry, + IN_GetKeyDest, IN_KeyEvent, IN_MouseMove, IN_JoystickAxisEvent, IN_Accelerometer, IN_Gyroscope, + IN_SetHandPosition, }; if (structsize == sizeof(funcs)) @@ -2023,6 +2150,35 @@ static void *QDECL PlugBI_GetEngineInterface(const char *interfacename, size_t s { Plug_LocalSound, Plug_S_RawAudio, + + S_Spacialize, + S_UpdateReverb, + Plug_S_PrecacheSound, + S_StartSound, + S_GetChannelLevel, + S_Voip_ClientLoudness, + Media_NamedTrack + }; + if (structsize == sizeof(funcs)) + return &funcs; + } + + if (!strcmp(interfacename, plugmasterfuncs_name)) + { + static plugmasterfuncs_t funcs = + { + NET_StringToAdr2, + NET_AdrToString, + Master_InfoForServer, + CL_QueryServers, + Master_QueryServer, + Master_CheckPollSockets, + Master_TotalCount, + Master_InfoForNum, + Master_ReadKeyString, + Master_ReadKeyFloat, + MasterInfo_WriteServers, + Master_ServerToString, }; if (structsize == sizeof(funcs)) return &funcs; @@ -2082,6 +2238,21 @@ static void *QDECL PlugBI_GetEngineInterface(const char *interfacename, size_t s return &funcs; } #endif +#ifdef VM_ANY + if (!strcmp(interfacename, plugq3vmfuncs_name)) + { + static plugq3vmfuncs_t funcs = + { + VM_Create, + VM_NonNative, + VM_MemoryBase, + VM_Call, + VM_Destroy, + }; + if (structsize == sizeof(funcs)) + return &funcs; + } +#endif #ifdef SKELETALMODELS if (!strcmp(interfacename, plugmodfuncs_name)) { diff --git a/engine/common/pr_bgcmd.c b/engine/common/pr_bgcmd.c index a3b8e6c7..99ee971d 100644 --- a/engine/common/pr_bgcmd.c +++ b/engine/common/pr_bgcmd.c @@ -1434,7 +1434,7 @@ void QCBUILTIN PF_setattachment(pubprogfuncs_t *prinst, struct globalvars_s *pr_ { if (model && model->loadstate == MLS_LOADING) COM_WorkerPartialSync(model, &model->loadstate, MLS_LOADING); - tagidx = Mod_TagNumForName(model, tagname); + tagidx = Mod_TagNumForName(model, tagname, 0); if (tagidx == 0) Con_DPrintf("setattachment(edict %i, edict %i, string \"%s\"): tried to find tag named \"%s\" on entity %i (model \"%s\") but could not find it\n", NUM_FOR_EDICT(prinst, e), NUM_FOR_EDICT(prinst, tagentity), tagname, tagname, NUM_FOR_EDICT(prinst, tagentity), model->name); } diff --git a/engine/common/protocol.h b/engine/common/protocol.h index aa91b359..e4f7bbb1 100644 --- a/engine/common/protocol.h +++ b/engine/common/protocol.h @@ -1457,7 +1457,8 @@ typedef struct q1usercmd_s #define RDF_RENDERSCALE (1u<<21) #define RDF_SCENEGAMMA (1u<<22) #define RDF_DISABLEPARTICLES (1u<<23) //mostly for skyrooms -#define RDF_SKIPSKY (1u<<24) //we have a skyroom, skip drawing sky chains for this scene. +#define RDF_SKIPSKY (1u<<24) //we drew a skyroom, skip drawing sky chains for this scene. +#define RDF_SKYROOMENABLED (1u<<25) //skyroom position is known, be prepared to draw the skyroom if its visible. #define RDF_ALLPOSTPROC (RDF_BLOOM|RDF_FISHEYE|RDF_WATERWARP|RDF_CUSTOMPOSTPROC|RDF_ANTIALIAS|RDF_SCENEGAMMA) //these flags require rendering to an fbo for the various different post-processing shaders. @@ -1766,6 +1767,8 @@ typedef struct q1usercmd_s #define MLS_POWERMODE 2 #define MLS_TORCH 3 #define MLS_TOTALDARK 4 +#define MLS_UNUSED 4 +#define MLS_ADDLIGHT 6 #define MLS_ABSLIGHT (MLS_MASK) #define SCALE_TYPE_MASK (SCALE_TYPE_UNIFORM|SCALE_TYPE_XYONLY|SCALE_TYPE_ZONLY) #define SCALE_TYPE_UNIFORM 0 // Scale X, Y, and Z diff --git a/engine/common/q3api.h b/engine/common/q3api.h new file mode 100644 index 00000000..35406df1 --- /dev/null +++ b/engine/common/q3api.h @@ -0,0 +1,57 @@ + +#if defined(Q3CLIENT) || defined(Q3SERVER) +struct sfx_s; +struct server_static_s; +struct server_s; +struct usercmd_s; +struct q3gamecode_s +{ + struct + { + void (*SendAuthPacket)(struct ftenet_connections_s *socket, netadr_t *gameserver); + void (*SendConnectPacket)(struct ftenet_connections_s *socket, netadr_t *to, int challenge, int qport, infobuf_t *userinfo); + void (*Established)(void); + void (*VARGS SendClientCommand)(const char *fmt, ...) LIKEPRINTF(1); + void (*SendCmd)(struct ftenet_connections_s *socket, struct usercmd_s *cmd, unsigned int movesequence, double gametime); + int (*ParseServerMessage) (sizebuf_t *msg); + void (*Disconnect) (struct ftenet_connections_s *socket); //disconnects from the server, killing all connection+cgame state. + } cl; + + struct + { + void (*VideoRestarted) (void); + int (*Redraw) (double time); + qboolean (*ConsoleCommand) (void); + qboolean (*KeyPressed) (int key, int unicode, int down); + unsigned int (*GatherLoopingSounds) (vec3_t *positions, unsigned int *entnums, struct sfx_s **sounds, unsigned int max); + } cg; + + struct + { + qboolean (*IsRunning)(void); + qboolean (*ConsoleCommand)(void); + void (*Start) (void); + qboolean (*OpenMenu)(void); + void (*Reset)(void); + } ui; + +//server stuff + struct + { + void (*ShutdownGame) (qboolean restart); + qboolean (*InitGame) (struct server_static_s *server_state_static, struct server_s *server_state, qboolean restart); + qboolean (*ConsoleCommand) (void); + qboolean (*PrefixedConsoleCommand) (void); + qboolean (*HandleClient) (netadr_t *from, sizebuf_t *msg); + void (*DirectConnect) (netadr_t *from, sizebuf_t *msg); + void (*NewMapConnects) (void); + void (*DropClient) (struct client_s *cl); + void (*RunFrame) (void); + void (*SendMessage) (struct client_s *client); + qboolean (*RestartGamecode) (void); + void (*ServerinfoChanged) (const char *key); + } sv; +}; + +extern struct q3gamecode_s *q3; +#endif diff --git a/engine/common/q3common.c b/engine/common/q3common.c index 2e1c8dd3..2d6d3708 100644 --- a/engine/common/q3common.c +++ b/engine/common/q3common.c @@ -1,18 +1,26 @@ -#include "quakedef.h" +#include "q3common.h" +plug2dfuncs_t *drawfuncs; +plug3dfuncs_t *scenefuncs; +plugaudiofuncs_t *audiofuncs; +plugq3vmfuncs_t *vmfuncs; +plugfsfuncs_t *fsfuncs; +pluginputfuncs_t *inputfuncs; +plugclientfuncs_t *clientfuncs; +plugmsgfuncs_t *msgfuncs; +plugworldfuncs_t *worldfuncs; +plugmasterfuncs_t *masterfuncs; + +double realtime; +struct netprim_s msg_nullnetprim; + +//mostly for access to sv.state or svs.sockets +q3serverstate_t sv3; //this file contains q3 netcode related things. //field info, netchan, and the WriteBits stuff (which should probably be moved to common.c with the others) //also contains vm filesystem -#if defined(HAVE_CLIENT) && defined(HAVE_SERVER) -#define NET_SendPacket(c,s,d,t) NET_SendPacket(((c)!=NS_CLIENT)?svs.sockets:cls.sockets,s,d,t) -#elif defined(HAVE_SERVER) -#define NET_SendPacket(c,s,d,t) NET_SendPacket(svs.sockets,s,d,t) -#else -#define NET_SendPacket(c,s,d,t) NET_SendPacket(cls.sockets,s,d,t) -#endif - -#define MAX_VM_FILES 8 +#define MAX_VM_FILES 64 typedef struct { char name[256]; @@ -27,7 +35,7 @@ qofs_t VM_fopen (const char *name, int *handle, int fmode, int owner) int i; if (!handle) - return !!FS_FLocateFile(name, FSLF_IFFOUND, NULL); + return !!fsfuncs->LocateFile(name, FSLF_IFFOUND, NULL); *handle = 0; @@ -50,14 +58,14 @@ qofs_t VM_fopen (const char *name, int *handle, int fmode, int owner) switch (fmode) { case VM_FS_READ: - vm_fopen_files[i].file = FS_OpenVFS(name, "rb", FS_GAME); + vm_fopen_files[i].file = fsfuncs->OpenVFS(name, "rb", FS_GAME); break; case VM_FS_APPEND: case VM_FS_APPEND_SYNC: - vm_fopen_files[i].file = FS_OpenVFS(name, "ab", FS_GAMEONLY); + vm_fopen_files[i].file = fsfuncs->OpenVFS(name, "ab", FS_GAMEONLY); break; case VM_FS_WRITE: - vm_fopen_files[i].file = FS_OpenVFS(name, "wb", FS_GAMEONLY); + vm_fopen_files[i].file = fsfuncs->OpenVFS(name, "wb", FS_GAMEONLY); break; default: //bad return -1; @@ -215,7 +223,7 @@ static int QDECL VMEnum(const char *match, qofs_t size, time_t mtime, void *args check = ((vmsearch_t *)args)->initialbuffer; while(check < ((vmsearch_t *)args)->buffer) { - if (!stricmp(check, match)) + if (!Q_strcasecmp(check, match)) return true; //we found this one already check += strlen(check)+1; } @@ -251,7 +259,7 @@ static int QDECL VMEnumMods(const char *match, qofs_t size, time_t modtime, void if (match[newlen-2] != '/') return true; - if (!stricmp(match, "baseq3/")) + if (!Q_strcasecmp(match, "baseq3/")) return true; //we don't want baseq3. FIXME: should be any basedir, rather than hardcoded. foundone = false; @@ -260,11 +268,19 @@ static int QDECL VMEnumMods(const char *match, qofs_t size, time_t modtime, void return true; //we only count directories with a pk3 file Q_strncpyz(desc, match, sizeof(desc)); - f = FS_OpenVFS(va("%sdescription.txt", match), "rb", FS_ROOT); + f = fsfuncs->OpenVFS(va("%sdescription.txt", match), "rb", FS_ROOT); if (f) { - VFS_GETS(f, desc, sizeof(desc)); + char *e; + VFS_READ(f, desc, sizeof(desc)-1); VFS_CLOSE(f); + desc[sizeof(desc)-1] = 0; + for (e = desc; *e; e++) + if (*e == '\n' || *e == '\r') + { + *e = 0; + break; + } } desclen = strlen(desc)+1; @@ -275,7 +291,7 @@ static int QDECL VMEnumMods(const char *match, qofs_t size, time_t modtime, void check = ((vmsearch_t *)args)->initialbuffer; while(check < ((vmsearch_t *)args)->buffer) { - if (!stricmp(check, match)) + if (!Q_strcasecmp(check, match)) return true; //we found this one already check += strlen(check)+1; check += strlen(check)+1; @@ -304,15 +320,18 @@ int VM_GetFileList(const char *path, const char *ext, char *output, int buffersi vms.found=0; if (!strcmp(path, "$modlist")) { + cvar_t *fs_basedir = cvarfuncs->GetNVFDG("fs_basedir", NULL, 0, NULL, NULL); + cvar_t *fs_homedir = cvarfuncs->GetNVFDG("fs_homedir", NULL, 0, NULL, NULL); vms.skip=0; - Sys_EnumerateFiles((vms.dir=com_gamepath), "*", VMEnumMods, &vms, NULL); - if (*com_homepath) - Sys_EnumerateFiles((vms.dir=com_homepath), "*", VMEnumMods, &vms, NULL); + if (fs_basedir && *fs_basedir->string) + Sys_EnumerateFiles((vms.dir=fs_basedir->string), "*", VMEnumMods, &vms, NULL); + if (fs_homedir && *fs_homedir->string) + Sys_EnumerateFiles((vms.dir=fs_homedir->string), "*", VMEnumMods, &vms, NULL); } else if (*(char *)ext == '.' || *(char *)ext == '/') - COM_EnumerateFiles(va("%s/*%s", path, ext), VMEnum, &vms); + fsfuncs->EnumerateFiles(va("%s/*%s", path, ext), VMEnum, &vms); else - COM_EnumerateFiles(va("%s/*.%s", path, ext), VMEnum, &vms); + fsfuncs->EnumerateFiles(va("%s/*.%s", path, ext), VMEnum, &vms); return vms.found; } @@ -339,23 +358,9 @@ int VMQ3_Cvar_Register(q3vmcvar_t *v, char *name, char *defval, int flags) fteflags = flags & (CVAR_ARCHIVE | CVAR_USERINFO | CVAR_SERVERINFO); - c = Cvar_Get(name, defval, fteflags, "Q3VM cvars"); + c = cvarfuncs->GetNVFDG(name, defval, fteflags, NULL, "Q3VM cvars"); if (!c) //command name, etc return 0; -#ifndef SERVERONLY - if ((flags & CVAR_USERINFO) && !(c->flags & CVAR_USERINFO)) - { - c->flags |= CVAR_USERINFO; - InfoBuf_SetKey(&cls.userinfo[0], c->name, c->string); - } -#endif -#ifndef CLIENTONLY - if ((flags & CVAR_SERVERINFO) && !(c->flags & CVAR_SERVERINFO)) - { - c->flags |= CVAR_SERVERINFO; - InfoBuf_SetKey (&svs.info, c->name, c->string); - } -#endif for (i = 0; i < MAX_VMQ3_CVARS; i++) { if (!q3cvlist[i]) @@ -380,178 +385,27 @@ int VMQ3_Cvar_Update(q3vmcvar_t *v) { cvar_t *c; int i; - i = v->handle; - if (!i) - return 0; //not initialised - i--; + if (!v) + return 0; //ERROR! + i = v->handle-1; if ((unsigned)i >= MAX_VMQ3_CVARS) return 0; //a hack attempt c = q3cvlist[i]; if (!c) return 0; //that slot isn't active yet +// if (v->modificationCount == c->modifiedcount) +// return 1; //no changes, don't waste time on an strcpy v->integer = c->ival; v->value = c->value; - v->modificationCount = c->modified; + v->modificationCount = c->modifiedcount; Q_strncpyz(v->string, c->string, sizeof(v->string)); return 1; } -/* -============ -MSG_WriteRawBytes -============ -*/ -static void MSG_WriteRawBytes( sizebuf_t *msg, int value, int bits ) -{ - qbyte *buf; - - if( bits <= 8 ) - { - buf = SZ_GetSpace( msg, 1 ); - buf[0] = value; - } - else if( bits <= 16 ) - { - buf = SZ_GetSpace( msg, 2 ); - buf[0] = value & 0xFF; - buf[1] = value >> 8; - } - else if( bits <= 32 ) - { - buf = SZ_GetSpace( msg, 4 ); - buf[0] = value & 0xFF; - buf[1] = (value >> 8) & 0xFF; - buf[2] = (value >> 16) & 0xFF; - buf[3] = value >> 24; - } -} - -/* -============ -MSG_WriteRawBits -============ -*/ -static void MSG_WriteRawBits( sizebuf_t *msg, int value, int bits ) -{ - // TODO -} - -/* -============ -MSG_WriteHuffBits -============ -*/ -#ifdef HUFFNETWORK -static void MSG_WriteHuffBits( sizebuf_t *msg, int value, int bits ) -{ - int remaining; - int i; - - value &= 0xFFFFFFFFU >> (32 - bits); - remaining = bits & 7; - - for( i=0; icurrentbit & 7) ) - { - msg->data[msg->currentbit >> 3] = 0; - } - msg->data[msg->currentbit >> 3] |= (value & 1) << (msg->currentbit & 7); - msg->currentbit++; - value >>= 1; - } - bits -= remaining; - - if( bits > 0 ) - { - for( i=0 ; i<(bits+7)>>3 ; i++ ) - { - Huff_EmitByte( value & 255, msg->data, &msg->currentbit ); - value >>= 8; - } - } - - msg->cursize = (msg->currentbit >> 3) + 1; -} -#endif - -/* -============ -MSG_WriteBits -============ -*/ -void MSG_WriteBits(sizebuf_t *msg, int value, int bits) -{ -#ifdef MSG_PROFILING - int maxval; -#endif // MSG_PROFILING - - if( msg->maxsize - msg->cursize < 4 ) - { - msg->overflowed = true; - return; - } - - if( !bits || bits < -31 || bits > 32 ) - { - Sys_Error("MSG_WriteBits: bad bits %i", bits); - } - -#ifdef MSG_PROFILING - msg_bitsWritten += bits; - - if( bits != 32 ) - { - if( bits > 0 ) - { - maxval = (1 << bits) - 1; - if( value > maxval || maxval < 0 ) - { - msg_overflows++; - } - } - else - { - maxval = (1 << (bits - 1)) - 1; - if( value > maxval || value < -maxval - 1 ) - { - msg_overflows++; - } - } - } -#endif // MSG_PROFILING - - if( bits < 0 ) - { - bits = -bits; - } - - switch( msg->packing ) - { - default: - case SZ_BAD: - Sys_Error("MSG_WriteBits: bad msg->packing %i", msg->packing ); - break; - case SZ_RAWBYTES: - MSG_WriteRawBytes( msg, value, bits ); - break; - case SZ_RAWBITS: - MSG_WriteRawBits( msg, value, bits ); - break; -#ifdef HUFFNETWORK - case SZ_HUFFMAN: - MSG_WriteHuffBits( msg, value, bits ); - break; -#endif - } - -} - - //////////////////////////////////////////////////////////////////////////////// //q3 netchan @@ -567,7 +421,24 @@ void MSG_WriteBits(sizebuf_t *msg, int value, int bits) #define STUNDEMULTIPLEX_MASK 0x40000000 //stun requires that we set this bit to avoid surprises, and ignore packets without it. #define FRAGMENT_MASK 0x80000000 #define FRAGMENTATION_TRESHOLD (MAX_PACKETLEN-100) -qboolean Netchan_ProcessQ3 (netchan_t *chan) +void Netchan_SetupQ3(netsrc_t sock, netchan_t *chan, netadr_t *adr, int qport) +{ + memset (chan, 0, sizeof(*chan)); + + chan->sock = sock; + chan->remote_address = *adr; + chan->last_received = realtime; + chan->incoming_unreliable = -1; + + chan->message.data = chan->message_buf; + chan->message.allowoverflow = true; + chan->message.maxsize = MAX_QWMSGLEN; + + chan->qport = qport; + + chan->qportsize = 2; +} +qboolean Netchan_ProcessQ3 (netchan_t *chan, sizebuf_t *msg) { //incoming_reliable_sequence is perhaps wrongly used... int sequence; @@ -577,12 +448,12 @@ qboolean Netchan_ProcessQ3 (netchan_t *chan) char adr[MAX_ADR_SIZE]; // Get sequence number - MSG_BeginReading(msg_nullnetprim); - sequence = MSG_ReadBits(32); + msgfuncs->BeginReading(msg, msg_nullnetprim); + sequence = msgfuncs->ReadBits(32); if (chan->pext_stunaware) { - sequence = BigLong(sequence); + sequence = ((sequence&0xff000000)>>24)|((sequence&0x00ff0000)>>8)|((sequence&0x0000ff00)<<8)|((sequence&0x000000ff)<<24); //reinterpret it as big-endian if (sequence & STUNDEMULTIPLEX_MASK) sequence-= STUNDEMULTIPLEX_MASK; else @@ -592,7 +463,7 @@ qboolean Netchan_ProcessQ3 (netchan_t *chan) // Read the qport if we are a server if (chan->sock == NS_SERVER) { - MSG_ReadBits(16); + msgfuncs->ReadBits(16); } // Check if packet is a message fragment @@ -601,8 +472,8 @@ qboolean Netchan_ProcessQ3 (netchan_t *chan) sequence &= ~FRAGMENT_MASK; fragment = true; - fragmentStart = MSG_ReadBits(16); - fragmentLength = MSG_ReadBits(16); + fragmentStart = msgfuncs->ReadBits(16); + fragmentLength = msgfuncs->ReadBits(16); } else { @@ -638,7 +509,7 @@ qboolean Netchan_ProcessQ3 (netchan_t *chan) if (chan->drop_count > 0)// && (net_showdrop->integer || net_showpackets->integer)) { - Con_DPrintf("%s:Dropped %i packets at %i\n", NET_AdrToString(adr, sizeof(adr), &chan->remote_address), chan->drop_count, sequence); + Con_DPrintf("%s:Dropped %i packets at %i\n", masterfuncs->AdrToString(adr, sizeof(adr), &chan->remote_address), chan->drop_count, sequence); } if (!fragment) @@ -660,13 +531,13 @@ qboolean Netchan_ProcessQ3 (netchan_t *chan) { // if(net_showdrop->integer || net_showpackets->integer) { - Con_Printf("%s:Dropped a message fragment\n", NET_AdrToString(adr, sizeof(adr), &chan->remote_address)); + Con_Printf("%s:Dropped a message fragment\n", masterfuncs->AdrToString(adr, sizeof(adr), &chan->remote_address)); } return false; } // Check if fragmentLength is valid - if (fragmentLength < 0 || fragmentLength > FRAGMENTATION_TRESHOLD || msg_readcount + fragmentLength > net_message.cursize || chan->in_fragment_length + fragmentLength > sizeof(chan->in_fragment_buf)) + if (fragmentLength < 0 || fragmentLength > FRAGMENTATION_TRESHOLD || msgfuncs->ReadCount() + fragmentLength > msg->cursize || chan->in_fragment_length + fragmentLength > sizeof(chan->in_fragment_buf)) { /* if (net_showdrop->integer || net_showpackets->integer) { @@ -676,7 +547,7 @@ qboolean Netchan_ProcessQ3 (netchan_t *chan) } // Append to the incoming fragment buffer - memcpy( chan->in_fragment_buf + chan->in_fragment_length, net_message.data + msg_readcount, fragmentLength); + memcpy(chan->in_fragment_buf + chan->in_fragment_length, msg->data + msgfuncs->ReadCount(), fragmentLength); chan->in_fragment_length += fragmentLength; if (fragmentLength == FRAGMENTATION_TRESHOLD) @@ -685,21 +556,21 @@ qboolean Netchan_ProcessQ3 (netchan_t *chan) } // Check if assembled message fits in buffer - if (chan->in_fragment_length > net_message.maxsize) + if (chan->in_fragment_length > msg->maxsize) { - Con_Printf("%s:fragmentLength %i > net_message.maxsize\n", NET_AdrToString(adr, sizeof(adr), &chan->remote_address), chan->in_fragment_length); + Con_Printf("%s:fragmentLength %i > net_message.maxsize\n", masterfuncs->AdrToString(adr, sizeof(adr), &chan->remote_address), chan->in_fragment_length); return false; } // // Reconstruct message properly // - SZ_Clear(&net_message); - MSG_WriteLong(&net_message, sequence); - SZ_Write(&net_message, chan->in_fragment_buf, chan->in_fragment_length); + msgfuncs->BeginWriting(msg, msg_nullnetprim, NULL, 0); + msgfuncs->WriteLong(msg, sequence); + msgfuncs->WriteData(msg, chan->in_fragment_buf, chan->in_fragment_length); - MSG_BeginReading(msg_nullnetprim); - MSG_ReadLong(); + msgfuncs->BeginReading(msg, msg_nullnetprim); + msgfuncs->ReadLong(); // No more fragments chan->in_fragment_length = 0; @@ -716,7 +587,7 @@ qboolean Netchan_ProcessQ3 (netchan_t *chan) Netchan_TransmitNextFragment ================= */ -void Netchan_TransmitNextFragment( netchan_t *chan ) +void Netchan_TransmitNextFragment(struct ftenet_connections_s *socket, netchan_t *chan ) { //'reliable' is badly named. it should be 'fragment' instead. //but in the interests of a smaller netchan_t... @@ -729,7 +600,7 @@ void Netchan_TransmitNextFragment( netchan_t *chan ) if (chan->pext_stunaware) { sequence+= STUNDEMULTIPLEX_MASK; - sequence = BigLong(sequence); + sequence = ((sequence&0xff000000)>>24)|((sequence&0x00ff0000)>>8)|((sequence&0x0000ff00)<<8)|((sequence&0x000000ff)<<24); //reinterpret it as big-endian } // Write the packet header @@ -737,12 +608,12 @@ void Netchan_TransmitNextFragment( netchan_t *chan ) send.packing = SZ_RAWBYTES; send.maxsize = sizeof(send_buf); send.data = send_buf; - MSG_WriteLong( &send, sequence ); + msgfuncs->WriteLong( &send, sequence ); #ifndef SERVERONLY // Send the qport if we are a client if( chan->sock == NS_CLIENT ) { - MSG_WriteShort( &send, chan->qport); + msgfuncs->WriteShort( &send, chan->qport); } #endif fragmentLength = chan->reliable_length - chan->reliable_start; @@ -752,14 +623,14 @@ void Netchan_TransmitNextFragment( netchan_t *chan ) } // Write the fragment header - MSG_WriteShort( &send, chan->reliable_start ); - MSG_WriteShort( &send, fragmentLength ); + msgfuncs->WriteShort( &send, chan->reliable_start ); + msgfuncs->WriteShort( &send, fragmentLength ); // Copy message fragment to the packet - SZ_Write( &send, chan->reliable_buf + chan->reliable_start, fragmentLength ); + msgfuncs->WriteData(&send, chan->reliable_buf + chan->reliable_start, fragmentLength); // Send the datagram - NET_SendPacket( chan->sock, send.cursize, send.data, &chan->remote_address ); + msgfuncs->SendPacket(socket, send.cursize, send.data, &chan->remote_address); // if( net_showpackets->integer ) // { @@ -788,7 +659,7 @@ void Netchan_TransmitNextFragment( netchan_t *chan ) Netchan_Transmit ================= */ -void Netchan_TransmitQ3( netchan_t *chan, int length, const qbyte *data ) +void Netchan_TransmitQ3(struct ftenet_connections_s *socket, netchan_t *chan, int length, const qbyte *data ) { int i; sizebuf_t send; @@ -799,22 +670,22 @@ void Netchan_TransmitQ3( netchan_t *chan, int length, const qbyte *data ) // Check for message overflow if( length > MAX_OVERALLMSGLEN ) { - Con_Printf( "%s: outgoing message overflow\n", NET_AdrToString( adr, sizeof(adr), &chan->remote_address ) ); + Con_Printf( "%s: outgoing message overflow\n", masterfuncs->AdrToString( adr, sizeof(adr), &chan->remote_address ) ); return; } if( length < 0 ) { - Sys_Error("Netchan_Transmit: length = %i", length); + plugfuncs->Error("Netchan_Transmit: length = %i", length); } // Don't send if there are still unsent fragments if( chan->reliable_length ) { - Netchan_TransmitNextFragment( chan ); + Netchan_TransmitNextFragment(socket, chan); if( chan->reliable_length ) { - Con_DPrintf( "%s: unsent fragments\n", NET_AdrToString( adr, sizeof(adr), &chan->remote_address ) ); + Con_DPrintf( "%s: unsent fragments\n", masterfuncs->AdrToString( adr, sizeof(adr), &chan->remote_address ) ); return; } /*drop the outgoing packet if we fragmented*/ @@ -828,7 +699,7 @@ void Netchan_TransmitQ3( netchan_t *chan, int length, const qbyte *data ) chan->reliable_length = length; chan->reliable_start = 0; memcpy( chan->reliable_buf, data, length ); - Netchan_TransmitNextFragment( chan ); + Netchan_TransmitNextFragment(socket, chan); return; } @@ -836,27 +707,24 @@ void Netchan_TransmitQ3( netchan_t *chan, int length, const qbyte *data ) if (chan->pext_stunaware) { sequence+= STUNDEMULTIPLEX_MASK; - sequence = BigLong(sequence); + sequence = ((sequence&0xff000000)>>24)|((sequence&0x00ff0000)>>8)|((sequence&0x0000ff00)<<8)|((sequence&0x000000ff)<<24); //reinterpret it as big-endian } // Write the packet header - memset(&send, 0, sizeof(send)); - send.packing = SZ_RAWBYTES; - send.maxsize = sizeof(send_buf); - send.data = send_buf; - MSG_WriteLong( &send, chan->outgoing_sequence ); + msgfuncs->BeginWriting(&send, msg_nullnetprim, send_buf, sizeof(send_buf)); + msgfuncs->WriteLong(&send, chan->outgoing_sequence); #ifndef SERVERONLY // Send the qport if we are a client if( chan->sock == NS_CLIENT ) { - MSG_WriteShort( &send, chan->qport); + msgfuncs->WriteShort(&send, chan->qport); } #endif // Copy the message to the packet - SZ_Write( &send, data, length ); + msgfuncs->WriteData(&send, data, length); // Send the datagram - NET_SendPacket( chan->sock, send.cursize, send.data, &chan->remote_address ); + msgfuncs->SendPacket( socket, send.cursize, send.data, &chan->remote_address ); /* if( net_showpackets->integer ) { @@ -958,15 +826,15 @@ static const q3field_t esFieldTable[] = { ES_FIELD( origin[1], 0 ), ES_FIELD( origin[2], 0 ), ES_FIELD( solid, 24 ), - ES_FIELD( powerups, 16 ), - ES_FIELD( modelindex, 8 ), + ES_FIELD( powerups, MAX_Q3_POWERUPS ), + ES_FIELD( modelindex, MODELINDEX_BITS ), ES_FIELD( otherEntityNum2, 10 ), ES_FIELD( loopSound, 8 ), ES_FIELD( generic1, 8 ), ES_FIELD( origin2[2], 0 ), ES_FIELD( origin2[0], 0 ), ES_FIELD( origin2[1], 0 ), - ES_FIELD( modelindex2, 8 ), + ES_FIELD( modelindex2, MODELINDEX_BITS ), ES_FIELD( angles[0], 0 ), ES_FIELD( time, 32 ), ES_FIELD( apos.trTime, 32 ), @@ -1012,7 +880,7 @@ qboolean MSG_Q3_ReadDeltaEntity( const q3entityState_t *from, q3entityState_t *t if( number < 0 || number >= MAX_GENTITIES ) { - Host_EndGame("MSG_ReadDeltaEntity: Bad delta entity number: %i\n", number); + plugfuncs->EndGame("MSG_ReadDeltaEntity: Bad delta entity number: %i\n", number); } if( !to ) @@ -1029,7 +897,7 @@ qboolean MSG_Q3_ReadDeltaEntity( const q3entityState_t *from, q3entityState_t *t } #endif - if (MSG_ReadBits(1)) + if (msgfuncs->ReadBits(1)) { memset( to, 0, sizeof( *to ) ); to->number = ENTITYNUM_NONE; @@ -1053,7 +921,7 @@ qboolean MSG_Q3_ReadDeltaEntity( const q3entityState_t *from, q3entityState_t *t } to->number = number; - if( !MSG_ReadBits( 1 ) ) + if( !msgfuncs->ReadBits( 1 ) ) { return true; // unchanged } @@ -1065,7 +933,7 @@ qboolean MSG_Q3_ReadDeltaEntity( const q3entityState_t *from, q3entityState_t *t } #endif - maxFieldNum = MSG_ReadByte(); + maxFieldNum = msgfuncs->ReadByte(); #ifdef MSG_SHOWNET if( dump ) @@ -1076,15 +944,15 @@ qboolean MSG_Q3_ReadDeltaEntity( const q3entityState_t *from, q3entityState_t *t if( maxFieldNum > esTableSize ) { - Host_EndGame("MSG_ReadDeltaEntity: maxFieldNum > esTableSize"); + plugfuncs->EndGame("MSG_ReadDeltaEntity: maxFieldNum > esTableSize"); } for( i=0, field=esFieldTable ; iReadBits( 1 ) ) continue; // field unchanged - if( !MSG_ReadBits( 1 ) ) + if( !msgfuncs->ReadBits( 1 ) ) { FIELD_INTEGER( to ) = 0; #ifdef MSG_SHOWNET @@ -1098,7 +966,7 @@ qboolean MSG_Q3_ReadDeltaEntity( const q3entityState_t *from, q3entityState_t *t if( field->bits ) { - to_integer = MSG_ReadBits( field->bits ); + to_integer = msgfuncs->ReadBits( field->bits ); FIELD_INTEGER( to ) = to_integer; #ifdef MSG_SHOWNET if( dump ) @@ -1110,9 +978,9 @@ qboolean MSG_Q3_ReadDeltaEntity( const q3entityState_t *from, q3entityState_t *t } - if( !MSG_ReadBits( 1 ) ) + if( !msgfuncs->ReadBits( 1 ) ) { - to_integer = MSG_ReadBits( 13 ) - 0x1000; + to_integer = msgfuncs->ReadBits( 13 ) - 0x1000; FIELD_FLOAT( to ) = (float)to_integer; #ifdef MSG_SHOWNET if( dump ) @@ -1123,7 +991,7 @@ qboolean MSG_Q3_ReadDeltaEntity( const q3entityState_t *from, q3entityState_t *t } else { - FIELD_INTEGER( to ) = MSG_ReadLong(); + FIELD_INTEGER( to ) = msgfuncs->ReadLong(); #ifdef MSG_SHOWNET if( dump ) { @@ -1169,14 +1037,14 @@ void MSGQ3_WriteDeltaEntity(sizebuf_t *msg, const q3entityState_t *from, const q { if(from) { - MSG_WriteBits(msg, from->number, GENTITYNUM_BITS); - MSG_WriteBits(msg, 1, 1); + msgfuncs->WriteBits(msg, from->number, GENTITYNUM_BITS); + msgfuncs->WriteBits(msg, 1, 1); } return; // removed } if(to->number < 0 || to->number > MAX_GENTITIES) - SV_Error("MSG_WriteDeltaEntity: Bad entity number: %i", to->number); + plugfuncs->EndGame("MSG_WriteDeltaEntity: Bad entity number: %i", to->number); if(!from) from = &nullEntityState; // nodelta update @@ -1196,16 +1064,16 @@ void MSGQ3_WriteDeltaEntity(sizebuf_t *msg, const q3entityState_t *from, const q if(!force) return; // don't emit any bits at all - MSG_WriteBits(msg, to->number, GENTITYNUM_BITS); - MSG_WriteBits(msg, 0, 1); - MSG_WriteBits(msg, 0, 1); + msgfuncs->WriteBits(msg, to->number, GENTITYNUM_BITS); + msgfuncs->WriteBits(msg, 0, 1); + msgfuncs->WriteBits(msg, 0, 1); return; // unchanged } - MSG_WriteBits(msg, to->number, GENTITYNUM_BITS); - MSG_WriteBits(msg, 0, 1); - MSG_WriteBits(msg, 1, 1); - MSG_WriteBits(msg, maxFieldNum, 8); + msgfuncs->WriteBits(msg, to->number, GENTITYNUM_BITS); + msgfuncs->WriteBits(msg, 0, 1); + msgfuncs->WriteBits(msg, 1, 1); + msgfuncs->WriteBits(msg, maxFieldNum, 8); // // write all modified fields @@ -1216,21 +1084,21 @@ void MSGQ3_WriteDeltaEntity(sizebuf_t *msg, const q3entityState_t *from, const q if(FIELD_INTEGER(from) == to_value) { - MSG_WriteBits( msg, 0, 1 ); + msgfuncs->WriteBits( msg, 0, 1 ); continue; // field unchanged } - MSG_WriteBits(msg, 1, 1); + msgfuncs->WriteBits(msg, 1, 1); if(!to_value) { - MSG_WriteBits(msg, 0, 1); + msgfuncs->WriteBits(msg, 0, 1); continue; // field set to zero } - MSG_WriteBits(msg, 1, 1); + msgfuncs->WriteBits(msg, 1, 1); if(field->bits) { - MSG_WriteBits(msg, to_value, field->bits); + msgfuncs->WriteBits(msg, to_value, field->bits); continue; // integer value } @@ -1248,16 +1116,16 @@ void MSGQ3_WriteDeltaEntity(sizebuf_t *msg, const q3entityState_t *from, const q && to_integer + MAX_SNAPPED/2 >= 0 && to_integer + MAX_SNAPPED/2 < MAX_SNAPPED) { - MSG_WriteBits(msg, 0, 1 ); // pack in 13 bits - MSG_WriteBits(msg, to_integer + MAX_SNAPPED/2, SNAPPED_BITS); + msgfuncs->WriteBits(msg, 0, 1 ); // pack in 13 bits + msgfuncs->WriteBits(msg, to_integer + MAX_SNAPPED/2, SNAPPED_BITS); #ifdef MSG_PROFILING msg_vectorsCompressed++; #endif // MSG_PROFILING } else { - MSG_WriteBits(msg, 1, 1 ); // pack in 32 bits - MSG_WriteBits(msg, to_value, 32); + msgfuncs->WriteBits(msg, 1, 1 ); // pack in 32 bits + msgfuncs->WriteBits(msg, to_value, 32); } } } @@ -1343,11 +1211,11 @@ void MSGQ3_WriteDeltaPlayerstate(sizebuf_t *msg, const q3playerState_t *from, co float to_float; int to_integer; int maxFieldNum; - int statsMask; - int persistantMask; - int ammoMask; - int powerupsMask; - int i; + unsigned int statsMask; + unsigned int persistantMask; + unsigned int ammoMask; + unsigned int powerupsMask; + int i, j; if(!to) { @@ -1371,7 +1239,7 @@ void MSGQ3_WriteDeltaPlayerstate(sizebuf_t *msg, const q3playerState_t *from, co } } - MSG_WriteBits(msg, maxFieldNum, 8); + msgfuncs->WriteBits(msg, maxFieldNum, 8); // // write all modified fields @@ -1382,14 +1250,14 @@ void MSGQ3_WriteDeltaPlayerstate(sizebuf_t *msg, const q3playerState_t *from, co if( FIELD_INTEGER( from ) == to_value ) { - MSG_WriteBits( msg, 0, 1 ); + msgfuncs->WriteBits( msg, 0, 1 ); continue; // field unchanged } - MSG_WriteBits( msg, 1, 1 ); + msgfuncs->WriteBits( msg, 1, 1 ); if( field->bits ) { - MSG_WriteBits( msg, to_value, field->bits ); + msgfuncs->WriteBits( msg, to_value, field->bits ); continue; // integer value } @@ -1407,16 +1275,16 @@ void MSGQ3_WriteDeltaPlayerstate(sizebuf_t *msg, const q3playerState_t *from, co && to_integer + MAX_SNAPPED/2 >= 0 && to_integer + MAX_SNAPPED/2 < MAX_SNAPPED ) { - MSG_WriteBits( msg, 0, 1 ); // pack in 13 bits - MSG_WriteBits( msg, to_integer + MAX_SNAPPED/2, SNAPPED_BITS ); + msgfuncs->WriteBits( msg, 0, 1 ); // pack in 13 bits + msgfuncs->WriteBits( msg, to_integer + MAX_SNAPPED/2, SNAPPED_BITS ); #ifdef MSG_PROFILING msg_vectorsCompressed++; #endif // MSG_PROFILING } else { - MSG_WriteBits(msg, 1, 1); // pack in 32 bits - MSG_WriteBits(msg, to_value, 32); + msgfuncs->WriteBits(msg, 1, 1); // pack in 32 bits + msgfuncs->WriteBits(msg, to_value, 32); } } @@ -1427,91 +1295,95 @@ void MSGQ3_WriteDeltaPlayerstate(sizebuf_t *msg, const q3playerState_t *from, co for(i=0; istats[i] != to->stats[i]) - statsMask |= (1 << i); + statsMask |= (1u << i); } persistantMask = 0; for(i=0 ; ipersistant[i] != to->persistant[i]) - persistantMask |= (1 << i); + persistantMask |= (1u << i); } ammoMask = 0; for(i=0 ; iammo[i] != to->ammo[i]) - ammoMask |= (1 << i); + ammoMask |= (1u << i); } powerupsMask = 0; for( i=0 ; ipowerups[i] != to->powerups[i]) - powerupsMask |= (1 << i); + powerupsMask |= (1u << i); } - if(!statsMask && !persistantMask && !ammoMask && !powerupsMask) + if(statsMask || persistantMask + || ammoMask + || powerupsMask) { - MSG_WriteBits(msg, 0, 1); - return; // no arrays modified - } + // + // write all modified arrays + // + msgfuncs->WriteBits(msg, 1, 1); - // - // write all modified arrays - // - MSG_WriteBits(msg, 1, 1); - - // PS_STATS - if(statsMask) - { - MSG_WriteBits(msg, 1, 1); - MSG_WriteBits(msg, statsMask, 16); - for(i=0; istats[i], -16); - } - else - MSG_WriteBits(msg, 0, 1); // unchanged - - // PS_PERSISTANT - if(persistantMask) - { - MSG_WriteBits(msg, 1, 1); - MSG_WriteBits(msg, persistantMask, 16); - for(i=0; ipersistant[i], -16); - } - else - MSG_WriteBits(msg, 0, 1); // unchanged - - - // PS_AMMO - if( ammoMask ) - { - MSG_WriteBits(msg, 1, 1); - MSG_WriteBits(msg, ammoMask, 16); - for(i=0; iammo[i], 16); - } - else - MSG_WriteBits(msg, 0, 1); // unchanged - - // PS_POWERUPS - if(powerupsMask) - { - MSG_WriteBits(msg, 1, 1); - MSG_WriteBits(msg, powerupsMask, 16); - for(i=0; ipowerups[i], 32); // WARNING: powerups use 32 bits, not 16 + msgfuncs->WriteBits(msg, 1, 1); + msgfuncs->WriteBits(msg, statsMask, 16); + for(i=0; iWriteBits(msg, to->stats[i], -16); } + else + msgfuncs->WriteBits(msg, 0, 1); // unchanged + + // PS_PERSISTANT + if (persistantMask) + { + msgfuncs->WriteBits(msg, 1, 1); + msgfuncs->WriteBits(msg, persistantMask, 16); + for(i=0; iWriteBits(msg, to->persistant[i], -16); + } + else + msgfuncs->WriteBits(msg, 0, 1); // unchanged + + for (j = 0; j < MAX_Q3_WEAPONS/16; j++) + { + // PS_AMMO + if (ammoMask & (0xffffu<WriteBits(msg, 1, 1); + msgfuncs->WriteBits(msg, ammoMask>>(j*16), 16); + for(i=0; i<16; i++) + if(ammoMask & ((quint64_t)1u << (j*16+i))) + msgfuncs->WriteBits(msg, to->ammo[j*16+i], 16); + } + else + msgfuncs->WriteBits(msg, 0, 1); // unchanged + } + + // PS_POWERUPS + if(powerupsMask) + { + msgfuncs->WriteBits(msg, 1, 1); + msgfuncs->WriteBits(msg, powerupsMask, 16); + for(i=0; iWriteBits(msg, to->powerups[i], 32); // WARNING: powerups use 32 bits, not 16 + } + } + else + msgfuncs->WriteBits(msg, 0, 1); // unchanged } else - MSG_WriteBits( msg, 0, 1 ); // unchanged + msgfuncs->WriteBits(msg, 0, 1); + } #endif @@ -1520,13 +1392,13 @@ void MSG_Q3_ReadDeltaPlayerstate( const q3playerState_t *from, q3playerState_t * const q3field_t *field; int to_integer; int maxFieldNum; - int bitmask; + unsigned int bitmask; #ifdef MSG_SHOWNET int startbits; qboolean dump; qboolean moredump; #endif - int i; + int i, j; if( !to ) { @@ -1554,23 +1426,23 @@ void MSG_Q3_ReadDeltaPlayerstate( const q3playerState_t *from, q3playerState_t * memcpy( to, from, sizeof( *to ) ); } - maxFieldNum = MSG_ReadByte(); + maxFieldNum = msgfuncs->ReadByte(); if( maxFieldNum > psTableSize ) { - Host_EndGame( "MSG_ReadDeltaPlayerstate: maxFieldNum > psTableSize" ); + plugfuncs->EndGame( "MSG_ReadDeltaPlayerstate: maxFieldNum > psTableSize" ); } for( i=0, field=psFieldTable ; iReadBits(1)) { continue; // field unchanged } if( field->bits ) { - to_integer = MSG_ReadBits(field->bits); + to_integer = msgfuncs->ReadBits(field->bits); FIELD_INTEGER( to ) = to_integer; #ifdef MSG_SHOWNET if( dump ) @@ -1582,9 +1454,9 @@ void MSG_Q3_ReadDeltaPlayerstate( const q3playerState_t *from, q3playerState_t * } - if(!MSG_ReadBits(1)) + if(!msgfuncs->ReadBits(1)) { - to_integer = MSG_ReadBits(13) - 0x1000; + to_integer = msgfuncs->ReadBits(13) - 0x1000; FIELD_FLOAT( to ) = (float)to_integer; #ifdef MSG_SHOWNET if( dump ) @@ -1595,7 +1467,7 @@ void MSG_Q3_ReadDeltaPlayerstate( const q3playerState_t *from, q3playerState_t * } else { - FIELD_INTEGER( to ) = MSG_ReadLong(); + FIELD_INTEGER( to ) = msgfuncs->ReadLong(); #ifdef MSG_SHOWNET if( dump ) { @@ -1605,10 +1477,10 @@ void MSG_Q3_ReadDeltaPlayerstate( const q3playerState_t *from, q3playerState_t * } } - if( MSG_ReadBits(1) ) + if( msgfuncs->ReadBits(1) ) { // PS_STATS - if( MSG_ReadBits(1) ) + if( msgfuncs->ReadBits(1) ) { #ifdef MSG_SHOWNET if( moredump ) @@ -1616,18 +1488,18 @@ void MSG_Q3_ReadDeltaPlayerstate( const q3playerState_t *from, q3playerState_t * Com_Printf( "PS_STATS " ); } #endif - bitmask = MSG_ReadBits(16); + bitmask = msgfuncs->ReadBits(16); for( i=0 ; istats[i] = (signed short)MSG_ReadBits(-16); + to->stats[i] = (signed short)msgfuncs->ReadBits(-16); } } } // PS_PERSISTANT - if( MSG_ReadBits(1 ) ) + if( msgfuncs->ReadBits(1 ) ) { #ifdef MSG_SHOWNET if( moredump ) @@ -1636,38 +1508,39 @@ void MSG_Q3_ReadDeltaPlayerstate( const q3playerState_t *from, q3playerState_t * } #endif - bitmask = MSG_ReadBits(16); + bitmask = msgfuncs->ReadBits(16); for( i=0 ; ipersistant[i] = (signed short)MSG_ReadBits(-16); + to->persistant[i] = (signed short)msgfuncs->ReadBits(-16); } } } // PS_AMMO - if( MSG_ReadBits(1) ) + for (j=0; j < MAX_Q3_WEAPONS/16; j++) { + if( msgfuncs->ReadBits(1) ) + { #ifdef MSG_SHOWNET - if( moredump ) - { - Com_Printf( "PS_AMMO " ); - } -#endif - - bitmask = MSG_ReadBits(16); - for( i=0 ; iammo[i] = (signed short)MSG_ReadBits(16); + Com_Printf( "PS_AMMO " ); + } +#endif + bitmask = msgfuncs->ReadBits(16); + for( i=0 ; i<16 ; i++ ) + { + if( bitmask & (1u << i) ) + { + to->ammo[j*16+i] = (signed short)msgfuncs->ReadBits(16); + } } } } - // PS_POWERUPS - if( MSG_ReadBits(1) ) + if( msgfuncs->ReadBits(1) ) { #ifdef MSG_SHOWNET if( moredump ) { @@ -1675,17 +1548,19 @@ void MSG_Q3_ReadDeltaPlayerstate( const q3playerState_t *from, q3playerState_t * } #endif - bitmask = MSG_ReadBits(16); + bitmask = msgfuncs->ReadBits(16); for( i=0 ; ipowerups[i] = MSG_ReadLong(); + to->powerups[i] = msgfuncs->ReadLong(); } } } } + + #ifdef MSG_SHOWNET if( dump ) { @@ -1712,20 +1587,20 @@ int kbitmask[] = { static int MSG_ReadDeltaKey(int key, int from, int bits) { - if (MSG_ReadBits(1)) - return MSG_ReadBits(bits) ^ (key & kbitmask[bits]); + if (msgfuncs->ReadBits(1)) + return msgfuncs->ReadBits(bits) ^ (key & kbitmask[bits]); else return from; } void MSG_Q3_ReadDeltaUsercmd(int key, const usercmd_t *from, usercmd_t *to) { - if (MSG_ReadBits(1)) - to->servertime = MSG_ReadBits(8) + from->servertime; + if (msgfuncs->ReadBits(1)) + to->servertime = msgfuncs->ReadBits(8) + from->servertime; else - to->servertime = MSG_ReadBits(32); + to->servertime = msgfuncs->ReadBits(32); to->msec = 0; //first of a packet should always be an absolute value, which makes the old value awkward. - if (!MSG_ReadBits(1)) + if (!msgfuncs->ReadBits(1)) { to->angles[0] = from->angles[0]; to->angles[1] = from->angles[1]; @@ -1748,11 +1623,12 @@ void MSG_Q3_ReadDeltaUsercmd(int key, const usercmd_t *from, usercmd_t *to) to->upmove = (signed char)(unsigned char)MSG_ReadDeltaKey(key, (unsigned char)(signed char)from->upmove, 8); to->buttons = MSG_ReadDeltaKey(key, from->buttons, 16); to->weapon = MSG_ReadDeltaKey(key, from->weapon, 8); + } } qint64_t Q3VM_GetRealtime(q3time_t *qtime) -{ //this is useful mostly for saved games, or other weird stuff. +{ //this is useful mostly for saved games, or other weird stuff. time_t t = time(NULL); if (qtime) { @@ -1773,4 +1649,103 @@ qint64_t Q3VM_GetRealtime(q3time_t *qtime) } return t; } + + + + + +static struct q3gamecode_s q3funcs = +{ + { + CLQ3_SendAuthPacket, + CLQ3_SendConnectPacket, + CLQ3_Established, + CLQ3_SendClientCommand, + CLQ3_SendCmd, + CLQ3_ParseServerMessage, + CLQ3_Disconnect, + }, + + { + CG_Restart, + CG_Refresh, + CG_ConsoleCommand, + CG_KeyPressed, + CG_GatherLoopingSounds, + }, + + { + UI_IsRunning, + UI_ConsoleCommand, + UI_Start, + UI_OpenMenu, + UI_Reset, + }, + + { + SVQ3_ShutdownGame, + SVQ3_InitGame, + SVQ3_ConsoleCommand, + SVQ3_PrefixedConsoleCommand, + SVQ3_HandleClient, + SVQ3_DirectConnect, + SVQ3_NewMapConnects, + SVQ3_DropClient, + SVQ3_RunFrame, + SVQ3_SendMessage, + SVQ3_RestartGamecode, + SVQ3_ServerinfoChanged, + }, +}; + +void Q3_Frame(double enginetime, double gametime) +{ + realtime = enginetime; +} + +void Q3_Shutdown(void) +{ + SVQ3_ShutdownGame(false); + CG_Stop(); + UI_Stop(); + + VMQ3_FlushStringHandles(); +} + +#ifdef STATIC_Q3 +#define Plug_Init Plug_Q3_Init +#endif + +qboolean Plug_Init(void) +{ + vmfuncs = plugfuncs->GetEngineInterface(plugq3vmfuncs_name, sizeof(*vmfuncs)); + fsfuncs = plugfuncs->GetEngineInterface(plugfsfuncs_name, sizeof(*fsfuncs)); + msgfuncs = plugfuncs->GetEngineInterface(plugmsgfuncs_name, sizeof(*msgfuncs)); + worldfuncs = plugfuncs->GetEngineInterface(plugworldfuncs_name, sizeof(*worldfuncs)); + + if (!vmfuncs || !fsfuncs || !msgfuncs || !worldfuncs) + { + Con_Printf("Engine functionality missing, cannot enable q3 gamecode support.\n"); + return false; + } + + if (!plugfuncs->ExportFunction("Shutdown", Q3_Shutdown) || + !plugfuncs->ExportInterface("Quake3Plugin", &q3funcs, sizeof(q3funcs))) + { + Con_Printf("Engine is already using a q3-derived gamecode plugin.\n"); + return false; + } + plugfuncs->ExportFunction("Tick", Q3_Frame); + + drawfuncs = plugfuncs->GetEngineInterface(plug2dfuncs_name, sizeof(*drawfuncs)); + scenefuncs = plugfuncs->GetEngineInterface(plug3dfuncs_name, sizeof(*scenefuncs)); + inputfuncs = plugfuncs->GetEngineInterface(pluginputfuncs_name, sizeof(*inputfuncs)); + clientfuncs = plugfuncs->GetEngineInterface(plugclientfuncs_name, sizeof(*clientfuncs)); + audiofuncs = plugfuncs->GetEngineInterface(plugaudiofuncs_name, sizeof(*audiofuncs)); + masterfuncs = plugfuncs->GetEngineInterface(plugmasterfuncs_name, sizeof(*masterfuncs)); + if (drawfuncs && scenefuncs && inputfuncs && audiofuncs && masterfuncs && clientfuncs) + UI_Init(); + return true; +} + #endif diff --git a/engine/common/q3common.h b/engine/common/q3common.h new file mode 100644 index 00000000..a265d925 --- /dev/null +++ b/engine/common/q3common.h @@ -0,0 +1,67 @@ +#include "../plugins/plugin.h" +#include "clq3defs.h" + +//#define Q3_NOENCRYPT //a debugging property, makes it incompatible with q3 + +extern plug2dfuncs_t *drawfuncs; +extern plug3dfuncs_t *scenefuncs; +extern pluginputfuncs_t *inputfuncs; +extern plugaudiofuncs_t *audiofuncs; +extern plugmasterfuncs_t*masterfuncs; +extern plugclientfuncs_t*clientfuncs; + +extern plugq3vmfuncs_t *vmfuncs; +extern plugfsfuncs_t *fsfuncs; +extern plugmsgfuncs_t *msgfuncs; +extern plugworldfuncs_t *worldfuncs; + +extern cvar_t *sv_maxclients; +extern cvar_t *cl_shownet_ptr, *cl_c2sdupe_ptr, *cl_nodelta_ptr; + +#define Q_snprintfz Q_snprintf +#define Sys_Error plugfuncs->Error + +#define Z_Malloc plugfuncs->Malloc +#define Z_Free plugfuncs->Free + +typedef struct //merge? +{ + int flags; + int areabytes; + qbyte areabits[MAX_Q2MAP_AREAS/8]; // portalarea visibility bits + q3playerState_t ps; + int num_entities; + int first_entity; // into the circular sv_packet_entities[] + int senttime; // for ping calculations + + + int serverMessageNum; + int serverCommandNum; + int serverTime; // server time the message is valid for (in msec) + int localTime; + int deltaFrame; +} q3client_frame_t; + + + + +typedef struct +{ + world_t *world; + model_t *models[1u<refcount > 0) return; //still in use. + registeredskins[id] = NULL; for (i = 0; i < sk->nummappings; i++) { @@ -95,8 +96,7 @@ void Mod_WipeSkin(skinid_t id, qboolean force) } R_UnloadShader(sk->mappings[i].shader); } - Z_Free(registeredskins[id]); - registeredskins[id] = NULL; + Z_Free(sk); } static void Mod_WipeAllSkins(qboolean final) { @@ -275,6 +275,7 @@ skinid_t Mod_ReadSkinFile(const char *skinname, const char *skintext) skin->q1upper = Q1UNSPECIFIED; #endif + while(skintext) { if (skin->nummappings == skin->maxmappings) @@ -414,6 +415,7 @@ skinid_t Mod_ReadSkinFile(const char *skinname, const char *skintext) if (!*skintext) break; } + registeredskins[id] = skin; #ifdef QWSKINS @@ -1383,7 +1385,7 @@ qboolean R_CalcModelLighting(entity_t *e, model_t *clmodel) return e->light_known-1; } - if (!(r_refdef.flags & RDF_NOWORLDMODEL)) + if (!(r_refdef.flags & RDF_NOWORLDMODEL) && cl.worldmodel) { if (e->flags & RF_WEAPONMODEL) { @@ -1479,6 +1481,17 @@ qboolean R_CalcModelLighting(entity_t *e, model_t *clmodel) } else { +#ifdef HEXEN2 + if ((e->drawflags & MLS_MASK) == MLS_ADDLIGHT) + { + ambientlight[0] += e->abslight; + ambientlight[1] += e->abslight; + ambientlight[2] += e->abslight; + shadelight[0] += e->abslight; + shadelight[1] += e->abslight; + shadelight[2] += e->abslight; + } +#endif if (!r_vertexdlights.ival && r_dynamic.ival > 0) { float *org = e->origin; diff --git a/engine/gl/gl_backend.c b/engine/gl/gl_backend.c index 2bb8a8fe..3e0d35b3 100644 --- a/engine/gl/gl_backend.c +++ b/engine/gl/gl_backend.c @@ -1548,18 +1548,18 @@ void GLBE_Init(void) shaderstate.curentity = &r_worldentity; be_maxpasses = gl_config_nofixedfunc?1:gl_mtexarbable; be_maxpasses = min(SHADER_TMU_MAX, min(be_maxpasses, 32-VATTR_LEG_TMU0)); - gl_stencilbits = 0; + sh_config.stencilbits = 0; #ifndef GLESONLY if (!gl_config_gles && gl_config.glversion >= 3.0 && gl_config_nofixedfunc) { //docs say this line should be okay in gl3+. nvidia do not seem to agree. GL_STENCIL_BITS is depricated however. so for now, just assume. - qglGetFramebufferAttachmentParameteriv(GL_FRAMEBUFFER_EXT, GL_STENCIL, GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE, &gl_stencilbits); + qglGetFramebufferAttachmentParameteriv(GL_FRAMEBUFFER_EXT, GL_STENCIL, GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE, &sh_config.stencilbits); if (qglGetError()) - gl_stencilbits = 8; + sh_config.stencilbits = 8; } else #endif - qglGetIntegerv(GL_STENCIL_BITS, &gl_stencilbits); + qglGetIntegerv(GL_STENCIL_BITS, &sh_config.stencilbits); for (i = 0; i < FTABLE_SIZE; i++) { t = (double)i / (double)FTABLE_SIZE; diff --git a/engine/gl/gl_model.c b/engine/gl/gl_model.c index fb6539a8..f7fe6516 100644 --- a/engine/gl/gl_model.c +++ b/engine/gl/gl_model.c @@ -1056,6 +1056,7 @@ void Mod_ModelLoaded(void *ctx, void *data, size_t a, size_t b) Con_Printf(CON_ERROR "Unable to load %s\n", mod->name); break; case MLV_SILENT: + case MLV_SILENTSYNC: break; } } @@ -1369,18 +1370,16 @@ model_t *Mod_LoadModel (model_t *mod, enum mlverbosity_e verbose) COM_InsertWork(WG_LOADER, Mod_LoadModelWorker, mod, NULL, verbose, 0); else COM_AddWork(WG_LOADER, Mod_LoadModelWorker, mod, NULL, verbose, 0); - - //block until its loaded, if we care. - if (verbose == MLV_ERROR || verbose == MLV_WARNSYNC) - COM_WorkerPartialSync(mod, &mod->loadstate, MLS_LOADING); } + //block until its loaded, if we care. + if (mod->loadstate == MLS_LOADING && (verbose == MLV_ERROR || verbose == MLV_WARNSYNC || verbose == MLV_SILENTSYNC)) + COM_WorkerPartialSync(mod, &mod->loadstate, MLS_LOADING); + if (verbose == MLV_ERROR) { //someone already tried to load it without caring if it failed or not. make sure its loaded. //fixme: this is a spinloop. - if (mod->loadstate == MLS_LOADING) - COM_WorkerPartialSync(mod, &mod->loadstate, MLS_LOADING); if (mod->loadstate != MLS_LOADED) Host_EndGame ("Mod_NumForName: %s not found or couldn't load", mod->name); diff --git a/engine/gl/gl_rlight.c b/engine/gl/gl_rlight.c index 1eb3cdf4..8716c8b4 100644 --- a/engine/gl/gl_rlight.c +++ b/engine/gl/gl_rlight.c @@ -448,10 +448,6 @@ void R_RenderDlights (void) switch(method) { - case 2: - if (TraceLineR(r_refdef.vieworg, l->origin, waste1, waste2)) - continue; - break; case 0: break; case 3: @@ -534,8 +530,9 @@ void R_RenderDlights (void) #endif //other renderers fall through default: - case 1: - if (CL_TraceLine(r_refdef.vieworg, l->origin, waste1, NULL, NULL) < 1) + case 1: //bsp-only + case 2: //non-bsp too + if (TraceLineR(r_refdef.vieworg, l->origin, waste1, waste2, method!=2)) continue; break; } diff --git a/engine/gl/gl_rmain.c b/engine/gl/gl_rmain.c index 87f1858c..edc24a30 100644 --- a/engine/gl/gl_rmain.c +++ b/engine/gl/gl_rmain.c @@ -608,7 +608,7 @@ static void R_SetupGL (vec3_t eyeangorg[2], vec4_t fovoverrides, float projmatri if (r_refdef.useperspective) { float maxdist = r_refdef.maxdist; - if (gl_stencilbits && Sh_StencilShadowsActive()) + if (sh_config.stencilbits && Sh_StencilShadowsActive()) maxdist = 0; //if we're using stencil shadows then force the maxdist to infinite to ensure the shadow volume is sealed. Matrix4x4_CM_Projection_Offset(r_refdef.m_projection_std, fov_l, fov_r, fov_d, fov_u, r_refdef.mindist, maxdist, false); Matrix4x4_CM_Projection_Offset(r_refdef.m_projection_view, -fovv_x/2, fovv_x/2, -fovv_y/2, fovv_y/2, r_refdef.mindist, maxdist, false); diff --git a/engine/gl/gl_screen.c b/engine/gl/gl_screen.c index 8021778c..0e2261af 100644 --- a/engine/gl/gl_screen.c +++ b/engine/gl/gl_screen.c @@ -175,7 +175,7 @@ qboolean GLSCR_UpdateScreen (void) if (topmenu && topmenu->isopaque) nohud = true; #ifdef VM_CG - else if (CG_Refresh()) + else if (q3 && q3->cg.Redraw(cl.time)) nohud = true; #endif #ifdef CSQC_DAT diff --git a/engine/gl/gl_shader.c b/engine/gl/gl_shader.c index 6dd44b8a..69df6828 100644 --- a/engine/gl/gl_shader.c +++ b/engine/gl/gl_shader.c @@ -700,8 +700,8 @@ qboolean Shader_ParseSkySides (char *shadername, char *texturename, texid_t *ima } if (!images[i]->width) { - Con_Printf("Sky \"%s\" missing texture: %s\n", shadername, path); - images[i] = missing_texture; + Con_DPrintf("Sky \"%s\" missing texture: %s\n", shadername, path); + images[i] = r_blackimage; allokay = false; } } diff --git a/engine/gl/gl_shadow.c b/engine/gl/gl_shadow.c index 3377c45c..8aa5c0bd 100644 --- a/engine/gl/gl_shadow.c +++ b/engine/gl/gl_shadow.c @@ -3424,7 +3424,7 @@ static qboolean Sh_DrawStencilLight(dlight_t *dl, vec3_t colour, vec3_t axis[3], sfrontfail = GL_DECR_WRAP_EXT; } #else - sref = (1<= countof(mode)) return -1; - case FS_READ_BIN: - case FS_READ_TXT: - mode = VM_FS_READ; - break; - case FS_WRITE_BIN: - case FS_WRITE_TXT: - mode = VM_FS_WRITE; - break; - case FS_APPEND_BIN: - case FS_APPEND_TXT: - mode = VM_FS_APPEND; - break; - } - return VM_fopen(VM_POINTER(arg[0]), VM_POINTER(arg[1]), mode, VMFSID_Q1QVM); + for (fnum = 0; fnum < countof(vm_fopen_files); fnum++) + if (!vm_fopen_files[fnum].file) + break; + if (fnum == countof(vm_fopen_files)) //too many already open + return -1; + + vm_fopen_files[fnum].file = FS_OpenVFS(name, mode[fmode].mode, mode[fmode].root); + if (!vm_fopen_files[fnum].file) + return -1; + *handle = fnum+1; + return VFS_GETLEN(vm_fopen_files[fnum].file); } static qintptr_t QVM_FS_CloseFile (void *offset, quintptr_t mask, const qintptr_t *arg) { - VM_fclose(arg[0], VMFSID_Q1QVM); - return 0; + int fnum = VM_LONG(arg[0])-1; + if (fnum >= 0 && fnum < countof(vm_fopen_files) && vm_fopen_files[fnum].file) + { + VFS_CLOSE(vm_fopen_files[fnum].file); + vm_fopen_files[fnum].file = NULL; + return 0; + } + return -1; +} +static void QVM_FS_CloseFileAll (void) +{ + size_t fnum; + for (fnum = 0; fnum < countof(vm_fopen_files); fnum++) + if (vm_fopen_files[fnum].file) + { + VFS_CLOSE(vm_fopen_files[fnum].file); + vm_fopen_files[fnum].file = NULL; + } } static qintptr_t QVM_FS_ReadFile (void *offset, quintptr_t mask, const qintptr_t *arg) { - if (VM_OOB(arg[0], arg[1])) + void *dest = VM_POINTER(arg[0]); + int size = VM_LONG(arg[1]); + int fnum = VM_LONG(arg[2])-1; + if (VM_OOB(arg[0], size)) return 0; - return VM_FRead(VM_POINTER(arg[0]), VM_LONG(arg[1]), VM_LONG(arg[2]), VMFSID_Q1QVM); + if (fnum >= 0 && fnum < countof(vm_fopen_files) && vm_fopen_files[fnum].file && vm_fopen_files[fnum].file->ReadBytes) + return VFS_READ(vm_fopen_files[fnum].file, dest, size); + return 0; } static qintptr_t QVM_FS_WriteFile (void *offset, quintptr_t mask, const qintptr_t *arg) { - if (VM_OOB(arg[0], arg[1])) + void *dest = VM_POINTER(arg[0]); + int size = VM_LONG(arg[1]); + int fnum = VM_LONG(arg[2])-1; + if (VM_OOB(arg[0], size)) return 0; - return VM_FWrite(VM_POINTER(arg[0]), VM_LONG(arg[1]), VM_LONG(arg[2]), VMFSID_Q1QVM); + if (fnum >= 0 && fnum < countof(vm_fopen_files) && vm_fopen_files[fnum].file && vm_fopen_files[fnum].file->ReadBytes) + return VFS_WRITE(vm_fopen_files[fnum].file, dest, size); + return 0; } static qintptr_t QVM_FS_SeekFile (void *offset, quintptr_t mask, const qintptr_t *arg) { - //fixme: what should the return value be? - VM_FSeek(VM_LONG(arg[0]), VM_LONG(arg[1]), VM_LONG(arg[2]), VMFSID_Q1QVM); + int fnum = VM_LONG(arg[0])-1; + quintptr_t foffset = arg[1]; + int seektype = VM_LONG(arg[2]); + if (fnum >= 0 && fnum < countof(vm_fopen_files) && vm_fopen_files[fnum].file && vm_fopen_files[fnum].file->seekstyle != SS_UNSEEKABLE) + { + if (seektype == 0) //cur + foffset += VFS_TELL(vm_fopen_files[fnum].file); + else if (seektype == 2) //end + foffset = VFS_GETLEN(vm_fopen_files[fnum].file) + (qintptr_t)foffset; + return VFS_SEEK(vm_fopen_files[fnum].file, foffset); + } return 0; } static qintptr_t QVM_FS_TellFile (void *offset, quintptr_t mask, const qintptr_t *arg) { - return VM_FTell(VM_LONG(arg[0]), VMFSID_Q1QVM); + int fnum = VM_LONG(arg[0])-1; + if (fnum >= 0 && fnum < countof(vm_fopen_files) && vm_fopen_files[fnum].file) + { + return VFS_TELL(vm_fopen_files[fnum].file); + } + return -1; +} + + + + +//filesystem searches result in a tightly-packed blob of null-terminated filenames (along with a count for how many entries) +typedef struct { + char *initialbuffer; + char *buffer; + int found; + int bufferleft; + int skip; +} vmsearch_t; +static int QDECL VMEnum(const char *match, qofs_t size, time_t mtime, void *args, searchpathfuncs_t *spath) +{ + char *check; + int newlen; + match += ((vmsearch_t *)args)->skip; + newlen = strlen(match)+1; + if (newlen > ((vmsearch_t *)args)->bufferleft) + return false; //too many files for the buffer + + check = ((vmsearch_t *)args)->initialbuffer; + while(check < ((vmsearch_t *)args)->buffer) + { + if (!Q_strcasecmp(check, match)) + return true; //we found this one already + check += strlen(check)+1; + } + + memcpy(((vmsearch_t *)args)->buffer, match, newlen); + ((vmsearch_t *)args)->buffer+=newlen; + ((vmsearch_t *)args)->bufferleft-=newlen; + ((vmsearch_t *)args)->found++; + return true; } static qintptr_t QVM_FS_GetFileList (void *offset, quintptr_t mask, const qintptr_t *arg) { - if (VM_OOB(arg[2], arg[3])) + vmsearch_t vms; + const char *path = VM_POINTER(arg[0]); + const char *ext = VM_POINTER(arg[1]); + char *output = VM_POINTER(arg[2]); + size_t buffersize = VM_LONG(arg[3]); + if (VM_OOB(arg[2], buffersize)) return 0; - return VM_GetFileList(VM_POINTER(arg[0]), VM_POINTER(arg[1]), VM_POINTER(arg[2]), VM_LONG(arg[3])); + + vms.initialbuffer = vms.buffer = output; + vms.skip = strlen(path)+1; + vms.bufferleft = buffersize; + vms.found=0; + if (*(const char *)ext == '.' || *(const char *)ext == '/') + COM_EnumerateFiles(va("%s/*%s", path, ext), VMEnum, &vms); + else + COM_EnumerateFiles(va("%s/*.%s", path, ext), VMEnum, &vms); + return vms.found; } static qintptr_t QVM_CVar_Set_Float (void *offset, quintptr_t mask, const qintptr_t *arg) { @@ -2189,7 +2289,7 @@ void Q1QVM_Shutdown(qboolean notifygame) VM_Call(q1qvm, GAME_SHUTDOWN, 0, 0, 0); VM_Destroy(q1qvm); q1qvm = NULL; - VM_fcloseall(VMFSID_Q1QVM); + QVM_FS_CloseFileAll(); if (svprogfuncs == &q1qvmprogfuncs) sv.world.progs = svprogfuncs = NULL; Z_FreeTags(VMFSID_Q1QVM); @@ -2269,12 +2369,12 @@ qboolean PR_LoadQ1QVM(void) Q1QVM_Shutdown(true); - q1qvm = VM_Create(fname, com_nogamedirnativecode.ival?NULL:syscallnative, fname, syscallqvm); + q1qvm = VM_Create(fname, com_gamedirnativecode.ival?syscallnative:NULL, fname, syscallqvm); if (!q1qvm) q1qvm = VM_Create(fname, syscallnative, fname, NULL); if (!q1qvm) { - if (com_nogamedirnativecode.ival && COM_FCheckExists(va("%s"ARCH_DL_POSTFIX, fname))) + if (!com_gamedirnativecode.ival && COM_FCheckExists(va("%s"ARCH_DL_POSTFIX, fname))) Con_Printf(CON_WARNING"%s"ARCH_DL_POSTFIX" exists, but is blocked from loading due to known bugs in other engines. If this is from a safe source then either ^aset com_nogamedirnativecode 0^a or rename to eg %s%s_%s"ARCH_DL_POSTFIX"\n", fname, ((host_parms.binarydir && *host_parms.binarydir)?host_parms.binarydir:host_parms.basedir), fname, FS_GetGamedir(false)); if (svprogfuncs == &q1qvmprogfuncs) sv.world.progs = svprogfuncs = NULL; diff --git a/engine/server/q3g_public.h b/engine/server/q3g_public.h index 49149dd4..12b63fde 100644 --- a/engine/server/q3g_public.h +++ b/engine/server/q3g_public.h @@ -96,8 +96,6 @@ typedef struct { q3entityShared_t r; // shared by both the server system and game - I *really* don't understand this, it looks like a bug. } q3sharedEntity_t; - - //=============================================================== // @@ -112,6 +110,7 @@ typedef enum { G_ERROR, // ( const char *string ); // abort the game + G_MILLISECONDS, // ( void ); // get current time for profiling reasons // this should NOT be used for any game related tasks, @@ -283,6 +282,7 @@ typedef enum { BOTLIB_AAS_SWIMMING, BOTLIB_AAS_PREDICT_CLIENT_MOVEMENT, + BOTLIB_EA_SAY = 400, BOTLIB_EA_SAY_TEAM, BOTLIB_EA_COMMAND, @@ -373,7 +373,6 @@ typedef enum { BOTLIB_AI_ALLOC_MOVE_STATE, BOTLIB_AI_FREE_MOVE_STATE, BOTLIB_AI_INIT_MOVE_STATE, - BOTLIB_AI_CHOOSE_BEST_FIGHT_WEAPON, BOTLIB_AI_GET_WEAPON_INFO, BOTLIB_AI_LOAD_WEAPON_WEIGHTS, @@ -402,8 +401,8 @@ typedef enum { BOTLIB_PC_READ_TOKEN, BOTLIB_PC_SOURCE_FILE_AND_LINE, - G_DEFAULTCASEWARNINGDISABLE //note: not an allowed index, just exists to prevent clang from warning about the default case. + G_DEFAULTCASEWARNINGDISABLE //note: not an allowed index, just exists to prevent clang from warning about the default case. } q3ggameImport_t; diff --git a/engine/server/savegame.c b/engine/server/savegame.c index 9b5c390b..85ab02a0 100644 --- a/engine/server/savegame.c +++ b/engine/server/savegame.c @@ -2114,7 +2114,7 @@ qboolean SV_Loadgame (const char *unsafe_savename) best = p; } } - + Q_snprintfz (filename, sizeof(filename), savefiles[best].pattern, savename); f = FS_OpenReadLocation(filename, &savefiles[best].loc); if (!f) diff --git a/engine/server/server.h b/engine/server/server.h index 2cdec089..cf5380ab 100644 --- a/engine/server/server.h +++ b/engine/server/server.h @@ -104,7 +104,7 @@ extern int sv_max_staticentities; extern staticsound_state_t *sv_staticsounds; extern int sv_max_staticsounds; -typedef struct +typedef struct server_s { qboolean active; // false when server is going down server_state_t state; // precache commands are only valid during load @@ -112,15 +112,14 @@ typedef struct float gamespeed; //time progression multiplier, fixed per-level. unsigned int csqcchecksum; qboolean mapchangelocked; - qboolean restarting; #ifdef SAVEDGAMES char loadgame_on_restart[MAX_QPATH]; //saved game to load on map_restart double autosave_time; #endif - double time; //current map time - double restartedtime; //sv.time from last map restart - double starttime; //system time we changed map. + double time; //time passed since map (re)start + double starttime; //Sys_DoubleTime at the start of the map + double restarttime; //for delayed map restarts - map will restart once sv.time reaches this stamp int framenum; int logindatabase; @@ -391,26 +390,6 @@ typedef struct //merge? float ping_time; } q2client_frame_t; #endif -#ifdef Q3SERVER -#include "../client/clq3defs.h" -typedef struct //merge? -{ - int flags; - int areabytes; - qbyte areabits[MAX_Q2MAP_AREAS/8]; // portalarea visibility bits - q3playerState_t ps; - int num_entities; - int first_entity; // into the circular sv_packet_entities[] - int senttime; // for ping calculations - - - int serverMessageNum; - int serverCommandNum; - int serverTime; // server time the message is valid for (in msec) - int localTime; - int deltaFrame; -} q3client_frame_t; -#endif #define MAX_BACK_BUFFERS 16 @@ -584,7 +563,7 @@ typedef struct client_s q2client_frame_t *q2frames; #endif #ifdef Q3SERVER - q3client_frame_t *q3frames; + void *q3frames; #endif } frameunion; packet_entities_t sentents; @@ -624,7 +603,7 @@ typedef struct client_s //quake3 does reliables only via this mechanism. basically just like q1's stuffcmds. int server_command_ack; //number known to have been received. int server_command_sequence; //number available. - char server_commands[64][1024]; //the commands, to deal with resends + char server_commands[256][1024]; //the commands, to deal with resends #endif //true/false/persist @@ -940,7 +919,7 @@ typedef struct svtcpstream_s { } svtcpstream_t; #endif -typedef struct +typedef struct server_static_s { gametype_e gametype; int spawncount; // number of servers spawned since start, @@ -1293,24 +1272,6 @@ void MSGQ2_WriteDeltaEntity (q2entity_state_t *from, q2entity_state_t *to, sizeb void SVQ2_BuildBaselines(void); #endif -//q3 stuff -#ifdef Q3SERVER -void SVQ3_ShutdownGame(qboolean restarting); -qboolean SVQ3_InitGame(qboolean restarting); -void SVQ3_ServerinfoChanged(const char *key); -qboolean SVQ3_RestartGamecode(void); -qboolean SVQ3_ConsoleCommand(void); -qboolean SVQ3_HandleClient(void); -void SVQ3_DirectConnect(void); -void SVQ3_NewMapConnects(void); -void SVQ3_DropClient(client_t *cl); -int SVQ3_AddBot(void); -void SVQ3_RunFrame(void); -void SVQ3_SendMessage(client_t *client); -qboolean SVQ3_Command(void); -#endif - - // // sv_send.c // diff --git a/engine/server/sv_ccmds.c b/engine/server/sv_ccmds.c index 1adbeeaf..3333f914 100644 --- a/engine/server/sv_ccmds.c +++ b/engine/server/sv_ccmds.c @@ -466,7 +466,7 @@ static int QDECL CompleteMapList (const char *name, qofs_t flags, time_t mtime, char stripped[64]; if (name[5] == 'b' && name[6] == '_') //skip box models return true; - + COM_StripExtension(name+5, stripped, sizeof(stripped)); ctx->cb(stripped, NULL, NULL, ctx); return true; @@ -530,6 +530,8 @@ variations: 'changelevel' will not flush the level cache, for h2 compat (won't save current level state in such a situation, as nq would prefer not) 'gamemap' will save the game to 'save0' after loading, for q2 compat 'spmap' is for q3 and sets 'gametype' to '2', otherwise identical to 'map'. all other map commands will reset it to '0' if its '2' at the time. +'spdevmap' forces sv_cheats 1, otherwise spmap +'devmap' forces sv_cheats 1, otherwise map 'map_restart' restarts the current map. Name is needed for q3 compat. 'restart' is an alias for 'map_restart'. Exists for NQ compat, but as an alias for QW mods that tried to use it for mod-specific things. @@ -572,16 +574,16 @@ void SV_Map_f (void) #ifdef Q3SERVER qboolean q3singleplayer = false; //forces g_gametype to 2 (otherwise clears if it was 2). #endif - qboolean waschangelevel = false; qboolean mapeditor = false; int i; char *startspot; + const char *cmd = Cmd_Argv(0); #ifndef SERVERONLY if (!Renderer_Started() && !isDedicated) { - Cbuf_AddText(va("wait;%s %s\n", Cmd_Argv(0), Cmd_Args()), Cmd_ExecLevel); + Cbuf_AddText(va("wait;%s %s\n", cmd, Cmd_Args()), Cmd_ExecLevel); return; } #endif @@ -592,14 +594,18 @@ void SV_Map_f (void) return; #endif - if (!Q_strcasecmp(Cmd_Argv(0), "map_restart")) + if (!Q_strcasecmp(cmd, "map_restart")) { const char *arg = Cmd_Argv(1); #ifdef Q3SERVER - if (sv.state==ss_active && svs.gametype==GT_QUAKE3) - if (SVQ3_RestartGamecode()) - return; + Cvar_ApplyLatches(CVAR_MAPLATCH, false); + if (sv.state==ss_active && svs.gametype==GT_QUAKE3 && q3->sv.RestartGamecode()) + { + sv.time = sv.world.physicstime; + sv.starttime = Sys_DoubleTime() - sv.time; + return; + } #endif #ifdef SAVEDGAMES @@ -615,7 +621,8 @@ void SV_Map_f (void) Con_DPrintf ("map_restart delay not implemented yet\n"); } Q_strncpyz (level, ".", sizeof(level)); - startspot = NULL; //FIXME: startspot forgotten on restart + startspot = NULL; + isrestart = true; //FIXME: if precaches+statics don't change, don't do the whole networking thing. } @@ -655,15 +662,15 @@ void SV_Map_f (void) } #ifdef Q3SERVER - q3singleplayer = !strcmp(Cmd_Argv(0), "spmap"); + q3singleplayer = !strncmp(cmd, "sp", 2); #endif if ((svs.gametype == GT_PROGS || svs.gametype == GT_Q1QVM) && progstype == PROG_QW) - flushparms = !strcmp(Cmd_Argv(0), "spmap"); //quakeworld's map command preserves spawnparms. + flushparms = !strncmp(cmd, "sp", 2); //quakeworld's map command preserves spawnparms. q3 doesn't do parms, so we might as well reuse sp[dev]map to flush in qw else - flushparms = !strcmp(Cmd_Argv(0), "map") || !strcmp(Cmd_Argv(0), "spmap"); //[sp]map flushes in nq+h2+q2+etc + flushparms = !strcmp(cmd, "map") || !strncmp(cmd, "sp", 2); //[sp]map flushes in nq+h2+q2+etc #ifdef SAVEDGAMES newunit = flushparms || (!strcmp(Cmd_Argv(0), "changelevel") && !startspot); - q2savetos0 = !strcmp(Cmd_Argv(0), "gamemap") && !isDedicated; //q2 + q2savetos0 = !strcmp(cmd, "gamemap") && !isDedicated; //q2 #endif mapeditor = !strcmp(Cmd_Argv(0), "mapedit"); @@ -876,12 +883,15 @@ void SV_Map_f (void) #ifdef Q3SERVER { - cvar_t *gametype; + cvar_t *var, *gametype; Cvar_ApplyLatches(CVAR_MAPLATCH, false); host_mapname.flags |= CVAR_SERVERINFO; + var = Cvar_Get("nextmap", "", 0, "Q3 compatibility"); + Cvar_ForceSet(var, "map_restart 0"); //on every map change matches q3. + gametype = Cvar_Get("g_gametype", "", CVAR_MAPLATCH|CVAR_SERVERINFO, "Q3 compatability"); // gametype->callback = gtcallback; @@ -1504,7 +1514,7 @@ static void SV_FilterIP_f (void) if (i == countof(banflags)) Con_Printf("Unknown ban/penalty flag: %s. ignoring.\n", com_token); } - //if no flags were specified, + //if no flags were specified, if (!proto.banflags) { if (!strcmp(Cmd_Argv(0), "ban")) @@ -2241,18 +2251,22 @@ static void SV_Status_f (void) #define C_USERID COLUMN(1, "userid", Con_Printf("%6i ", (int)cl->userid)) #define C_ADDRESS COLUMN(2, "address ", Con_Printf("%-16.16s", s)) #define C_NAME COLUMN(3, "name ", Con_Printf("%-16.16s", cl->name)) -#define C_RATE COLUMN(4, "rate", Con_Printf("%4i ", cl->frameunion.frames?(int)(1/cl->netchan.frame_rate):0)) +#define C_RATE COLUMN(4, "rate", Con_Printf("%4i ", (cl->frameunion.frames&&cl->netchan.frame_rate>0)?(int)(1/cl->netchan.frame_rate):0)) #define C_PING COLUMN(5, "ping", Con_Printf("%4i ", (int)SV_CalcPing (cl, false))) #define C_DROP COLUMN(6, "drop", Con_Printf("%4.1f ", 100.0*cl->netchan.drop_count / cl->netchan.incoming_sequence)) -#define C_DLP COLUMN(7, "dl ", if (!cl->download)Con_Printf(" ");else Con_Printf("%3.0f ", (cl->downloadcount*100.0)/cl->downloadsize)) +#define C_DLP COLUMN(7, "dl ", if (!cl->download||!cl->downloadsize)Con_Printf(" ");else Con_Printf("%3.0f ", (cl->downloadcount*100.0)/cl->downloadsize)) #define C_DLS COLUMN(8, "dls", if (!cl->download)Con_Printf(" ");else Con_Printf("%3u ", (unsigned int)(cl->downloadsize/1024))) -#define C_PROT COLUMN(9, "prot ", Con_Printf("%-6.6s", p)) +#define C_PROT COLUMN(9, "prot ", Con_Printf("%-6.5s", p)) +#define C_MODELSKIN COLUMN(11, "model/skin ", Con_Printf("%s", s)) #define C_ADDRESS2 COLUMN(10, "address ", Con_Printf("%s", s)) - int columns = (1<<6)-1; + int columns = (1<<4)-1; for (i=0,cl=svs.clients ; istate) + continue; + if (cl->netchan.drop_count) columns |= 1<<6; if (cl->download) @@ -2260,11 +2274,17 @@ static void SV_Status_f (void) columns |= 1<<7; columns |= 1<<8; } - if (cl->protocol != SCP_QUAKEWORLD || cl->spectator || !(cl->fteprotocolextensions2 & PEXT2_REPLACEMENTDELTAS)) + if (cl->frameunion.frames&&cl->netchan.frame_rate>0) + columns |= 1<<4; + if (cl->netchan.remote_address.type > NA_LOOPBACK) + columns |= 1<<5; + if (cl->protocol != SCP_BAD && (cl->protocol >= SCP_NETQUAKE || cl->spectator || (cl->protocol == SCP_QUAKEWORLD && !(cl->fteprotocolextensions2 & PEXT2_REPLACEMENTDELTAS)))) columns |= 1<<9; - if (cl->netchan.remote_address.type == NA_IPV6) - columns = (columns & ~(1<<2)) | (1<<10); + if (cl->netchan.remote_address.type == NA_IPV6||cl->reversedns) + columns |= (1<<10); } + if (columns&(1<<10)) //if address2, remove the limited length addresses. + columns &= ~(1<<2); #define COLUMN(f,t,v) if (columns&(1<netchan.remote_address); - switch(cl->protocol) + safeswitch(cl->protocol) { - default: - case SCP_BAD: - p = ""; - break; + case SCP_BAD: p = "none"; break; case SCP_QUAKEWORLD: p = (cl->fteprotocolextensions2 & PEXT2_REPLACEMENTDELTAS)?"fteqw":"qw"; break; case SCP_QUAKE2: p = "q2"; break; case SCP_QUAKE3: p = "q3"; break; @@ -2313,6 +2330,9 @@ static void SV_Status_f (void) case SCP_FITZ666: p = (cl->fteprotocolextensions2 & PEXT2_REPLACEMENTDELTAS)?"ftenq":(cl->qex?"qe666":"fitz"); break; case SCP_DARKPLACES6: p = "dpp6"; break; case SCP_DARKPLACES7: p = "dpp7"; break; + safedefault: + p = ""; + break; } if (cl->state == cs_connected && cl->protocol>=SCP_NETQUAKE) p = "nq"; //not actually known yet. @@ -2593,7 +2613,7 @@ void SV_User_f (void) char buf[256]; extern cvar_t sv_userinfo_bytelimit, sv_userinfo_keylimit; static const char *pext1names[32] = { "setview", "scale", "lightstylecol", "trans", "view2", "builletens", "accuratetimings", "sounddbl", - "fatness", "hlbsp", "bullet", "hullsize", "modeldbl", "entitydbl", "entitydbl2", "floatcoords", + "fatness", "hlbsp", "bullet", "hullsize", "modeldbl", "entitydbl", "entitydbl2", "floatcoords", "OLD vweap", "q2bsp", "q3bsp", "colormod", "splitscreen", "hexen2", "spawnstatic2", "customtempeffects", "packents", "UNKNOWN", "showpic", "setattachment","UNKNOWN", "chunkeddls", "csqc", "dpflags"}; static const char *pext2names[32] = { "prydoncursor", "voip", "setangledelta", "rplcdeltas", "maxplayers", "predinfo", "sizeenc", "infoblobs", @@ -2607,16 +2627,16 @@ void SV_User_f (void) return; } - Con_Printf("Userinfo:\n"); while((cl = SV_GetClientForString(Cmd_Argv(1), &clnum))) { + Con_Printf("Userinfo (%i):\n", cl->userid); InfoBuf_Print (&cl->userinfo, " "); Con_Printf("[%u/%i, %u/%i]\n", (unsigned)cl->userinfo.totalsize, sv_userinfo_bytelimit.ival, (unsigned)cl->userinfo.numkeys, sv_userinfo_keylimit.ival); switch(cl->protocol) { case SCP_BAD: Con_Printf("protocol: bot/invalid\n"); - break; + continue; case SCP_QUAKEWORLD: //branding is everything... if (cl->fteprotocolextensions2 & PEXT2_REPLACEMENTDELTAS) Con_Printf("protocol: fteqw-nack\n"); @@ -2846,10 +2866,7 @@ static void SV_Gamedir_f (void) Con_TPrintf ("%s should be a single filename, not a path\n", Cmd_Argv(0)); } else - { COM_Gamedir (dir, NULL); - InfoBuf_SetValueForStarKey (&svs.info, "*gamedir", dir); - } Z_Free(dir); } @@ -3024,7 +3041,7 @@ static void SV_SetTimer_f(void) static void SV_SendGameCommand_f(void) { #ifdef Q3SERVER - if (SVQ3_ConsoleCommand()) + if (q3->sv.PrefixedConsoleCommand()) return; #endif @@ -3175,7 +3192,7 @@ void SV_MemInfo_f(void) fr += sizeof(*cl->sentents.entities) * cl->sentents.max_entities; csfr = sizeof(*cl->pendingcsqcbits) * cl->max_net_ents; - + Con_Printf("%"PRIuSIZE" minping=%i frame=%i, csqc=%i\n", sizeof(svs.clients[i]), sz, fr, csfr); } } diff --git a/engine/server/sv_cluster.c b/engine/server/sv_cluster.c index a671cdcb..995376b2 100644 --- a/engine/server/sv_cluster.c +++ b/engine/server/sv_cluster.c @@ -130,7 +130,7 @@ static int MSV_SubServerRead(pubsubserver_t *ps) net_message.cursize = len-2; memmove(ps->inbuffer, ps->inbuffer+len, ps->inbuffersize - len); ps->inbuffersize -= len; - MSG_BeginReading (msg_nullnetprim); + MSG_BeginReading (&net_message, msg_nullnetprim); return len; } @@ -1233,7 +1233,7 @@ void MSV_PollSlaves(void) memmove(inbuffer, inbuffer+size, inbuffersize-size); inbuffersize -= size; - MSG_BeginReading (msg_nullnetprim); + MSG_BeginReading (&net_message, msg_nullnetprim); SSV_ReadFromControlServer(); } else @@ -1259,7 +1259,7 @@ void MSV_PollSlaves(void) { VFS_READ(msv_loop_to_ss, net_message.data, size); net_message.cursize = size-2; - MSG_BeginReading (msg_nullnetprim); + MSG_BeginReading (&net_message, msg_nullnetprim); SSV_ReadFromControlServer(); } } diff --git a/engine/server/sv_init.c b/engine/server/sv_init.c index 89e6ab65..3e6d3950 100644 --- a/engine/server/sv_init.c +++ b/engine/server/sv_init.c @@ -628,7 +628,8 @@ void SV_UnspawnServer (void) //terminate the running server. } PR_Deinit(); #ifdef Q3SERVER - SVQ3_ShutdownGame(false); + if (q3) + q3->sv.ShutdownGame(false); #endif #ifdef Q2SERVER SVQ2_ShutdownGameProgs(); @@ -927,14 +928,11 @@ void SV_SpawnServer (const char *server, const char *startspot, qboolean noents, // if (0) // cls.state = ca_connected; Surf_PreNewMap(); -#ifdef VM_CG - CG_Stop(); -#endif #endif #ifdef Q3SERVER if (svs.gametype == GT_QUAKE3) - SVQ3_ShutdownGame(false); //botlib kinda mandates this. :( + q3->sv.ShutdownGame(false); //botlib kinda mandates this. :( #endif Mod_ClearAll (); @@ -994,7 +992,6 @@ void SV_SpawnServer (const char *server, const char *startspot, qboolean noents, CL_CheckServerInfo(); #endif - sv.restarting = false; sv.state = ss_loading; #if defined(Q2BSPS) if (usecinematic) @@ -1162,7 +1159,7 @@ MSV_OpenUserDatabase(); newgametype = GT_HALFLIFE; #endif #ifdef Q3SERVER - else if (SVQ3_InitGame(false)) + else if (q3 && q3->sv.InitGame(&svs, &sv, false)) newgametype = GT_QUAKE3; #endif #ifdef Q2SERVER @@ -1193,7 +1190,7 @@ MSV_OpenUserDatabase(); #endif #ifdef Q3SERVER if (newgametype != GT_QUAKE3) - SVQ3_ShutdownGame(false); + q3->sv.ShutdownGame(false); #endif #ifdef Q2SERVER if (newgametype != GT_QUAKE2) //we don't want the q2 stuff anymore. @@ -1403,6 +1400,7 @@ MSV_OpenUserDatabase(); #endif #ifdef Q3SERVER case GT_QUAKE3: + Cvar_LockFromServer(&maxclients, maxclients.string); SV_UpdateMaxPlayers(playerslots?playerslots:max(8,maxclients.ival)); break; #endif @@ -1764,7 +1762,7 @@ MSV_OpenUserDatabase(); #ifdef Q3SERVER if (svs.gametype == GT_QUAKE3) { - SVQ3_NewMapConnects(); + q3->sv.NewMapConnects(); } #endif @@ -1784,6 +1782,11 @@ MSV_OpenUserDatabase(); sv.autosave_time = sv.time + sv_autosave.value*60; #endif +#ifdef HAVE_CLIENT + //there's a whole load of ugly debug crap there. make sure it stays hidden. + Con_ClearNotify(); +#endif + #ifdef __GLIBC__ if (isDedicated) malloc_trim(0); diff --git a/engine/server/sv_main.c b/engine/server/sv_main.c index 3fa80ac2..06547228 100644 --- a/engine/server/sv_main.c +++ b/engine/server/sv_main.c @@ -606,7 +606,7 @@ void SV_DropClient (client_t *drop) break; case GT_QUAKE3: #ifdef Q3SERVER - SVQ3_DropClient(drop); + q3->sv.DropClient(drop); #endif break; case GT_HALFLIFE: @@ -657,9 +657,10 @@ void SV_DropClient (client_t *drop) } else #endif - if (drop->state == cs_spawned || drop->istobeloaded) + if (drop->protocol == SCP_BAD) + drop->state = cs_free; //skip zombie state for bots. + else if (drop->state == cs_spawned || drop->istobeloaded) { - drop->istobeloaded = false; drop->state = cs_zombie; // become free in a few seconds drop->connection_started = realtime; // for zombie timeout } @@ -2170,7 +2171,7 @@ void SV_ClientProtocolExtensionsChanged(client_t *client) case SCP_QUAKE3: if (client->frameunion.q3frames) Z_Free(client->frameunion.q3frames); - client->frameunion.q3frames = Z_Malloc(Q3UPDATE_BACKUP*sizeof(*client->frameunion.q3frames)); + client->frameunion.q3frames = NULL;//Z_Malloc(Q3UPDATE_BACKUP*sizeof(*client->frameunion.q3frames)); break; #endif @@ -4040,7 +4041,7 @@ qboolean SV_ConnectionlessPacket (void) char *c; char adr[MAX_ADR_SIZE]; - MSG_BeginReading (svs.netprim); + MSG_BeginReading (&net_message, svs.netprim); if (net_message.cursize >= MAX_QWMSGLEN) //add a null term in message space { @@ -4096,7 +4097,7 @@ qboolean SV_ConnectionlessPacket (void) #ifdef Q3SERVER if (svs.gametype == GT_QUAKE3) { - SVQ3_DirectConnect(); + q3->sv.DirectConnect(&net_from, &net_message); return true; } @@ -4251,7 +4252,7 @@ qboolean SVNQ_ConnectionlessPacket(void) if (!sv_listen_nq.value || SSV_IsSubServer()) return false; - MSG_BeginReading(svs.netprim); + MSG_BeginReading(&net_message, svs.netprim); header = LongSwap(MSG_ReadLong()); if (!(header & NETFLAG_CTL)) { @@ -4664,7 +4665,7 @@ void SV_ReadPacket(void) #ifdef Q3SERVER if (svs.gametype == GT_QUAKE3) { - if (SVQ3_HandleClient()) + if (q3->sv.HandleClient(&net_from, &net_message)) inboundsequence++; else if (NET_WasSpecialPacket(svs.sockets)) return; @@ -4674,7 +4675,7 @@ void SV_ReadPacket(void) // read the qport out of the message so we can fix up // stupid address translating routers - MSG_BeginReading (svs.netprim); + MSG_BeginReading (&net_message, svs.netprim); MSG_ReadLong (); // sequence number MSG_ReadLong (); // sequence number qport = MSG_ReadShort () & 0xffff; @@ -4789,7 +4790,7 @@ dominping: return; #ifdef QWOVERQ3 - if (sv_listen_q3.ival && SVQ3_HandleClient()) + if (sv_listen_q3.ival && q3->sv.HandleClient()) { received++; continue; @@ -4906,7 +4907,6 @@ qboolean SV_ReadPackets (float *delay) NET_DTLS_Timeouts(svs.sockets); #endif - if (inboundsequence == oldinboundsequence) return false; //nothing new. oldinboundsequence = inboundsequence; @@ -5527,7 +5527,8 @@ static void SV_InfoChanged(void *context, const char *key) size_t i; #ifdef Q3SERVER - SVQ3_ServerinfoChanged(key); + if (q3) + q3->sv.ServerinfoChanged(key); #endif if (context != &svs.info && *key == '_') diff --git a/engine/server/sv_master.c b/engine/server/sv_master.c index 10571c0b..95fd92dc 100644 --- a/engine/server/sv_master.c +++ b/engine/server/sv_master.c @@ -1120,10 +1120,10 @@ static void SVM_ProcessUDPPacket(void) svm.time = Sys_DoubleTime(); - MSG_BeginReading(msg_nullnetprim); + MSG_BeginReading(&net_message, msg_nullnetprim); if (MSG_ReadLong() != -1 || msg_badread) { //go back to start... - MSG_BeginReading(msg_nullnetprim); + MSG_BeginReading(&net_message, msg_nullnetprim); } line = MSG_ReadStringLine(); s = COM_Parse(line); diff --git a/engine/server/sv_phys.c b/engine/server/sv_phys.c index cd6e62da..47acefe2 100644 --- a/engine/server/sv_phys.c +++ b/engine/server/sv_phys.c @@ -2519,7 +2519,7 @@ qboolean SV_Physics (void) { int i; qboolean moved = false; - int maxtics; + int maxtics = sv_limittics.ival; double trueframetime = host_frametime; double maxtic = sv_maxtic.value; double mintic = sv_mintic.value; @@ -2530,6 +2530,9 @@ qboolean SV_Physics (void) if (maxtic < mintic) maxtic = mintic; + if (maxtics>1&&sv.spawned_observer_slots==0&&sv.spawned_client_slots==0) + maxtics = 1; //no players on the server. let timings slide + //keep gravity tracking the cvar properly movevars.gravity = sv_gravity.value; @@ -2540,43 +2543,52 @@ qboolean SV_Physics (void) ) //make tics multiples of sv_maxtic (defaults to 0.1) { if (svs.gametype == GT_QUAKE2) - maxtic = 0.1; //fucking fuckity fuck. we should warn about this. + mintic = maxtic = 0.1; //fucking fuckity fuck. we should warn about this. + mintic = max(mintic, 1/1000.0); - host_frametime = sv.time - sv.world.physicstime; - if (host_frametime<0) + for(;;) { - if (host_frametime < -1) + host_frametime = sv.time - sv.world.physicstime; + if (host_frametime<0) + { + if (host_frametime < -1) + sv.world.physicstime = sv.time; + host_frametime = 0; + } + if (!maxtics--) + { //don't loop infinitely if we froze (eg debugger or suspend/hibernate) sv.world.physicstime = sv.time; - host_frametime = 0; - } - if (svs.gametype != GT_QUAKE3) - if (host_frametime < maxtic && realtime) - { -// sv.time+=host_frametime; - host_frametime = trueframetime; - return false; //don't bother with the whole server thing for a bit longer - } - if (host_frametime > maxtic) - host_frametime = maxtic; - sv.world.physicstime = sv.time; + break; + } + if (!host_frametime || (host_frametime < mintic && realtime)) + { + // sv.time+=host_frametime; + host_frametime = trueframetime; + return false; //don't bother with the whole server thing for a bit longer + } + if (host_frametime > maxtic) + host_frametime = maxtic; + sv.world.physicstime += host_frametime; + moved = true; - switch(svs.gametype) - { + switch(svs.gametype) + { #ifdef Q2SERVER - case GT_QUAKE2: - ge->RunFrame(); - break; + case GT_QUAKE2: + ge->RunFrame(); + break; #endif #ifdef Q3SERVER - case GT_QUAKE3: - SVQ3_RunFrame(); - break; + case GT_QUAKE3: + q3->sv.RunFrame(); + break; #endif - default: - break; + default: + break; + } } host_frametime = trueframetime; - return true; + return moved; } if (svs.gametype != GT_HALFLIFE && /*sv.botsonthemap &&*/ progstype == PROG_QW) @@ -2644,10 +2656,6 @@ qboolean SV_Physics (void) } } - maxtics = sv_limittics.ival; - if (sv.spawned_observer_slots==0&&sv.spawned_client_slots==0) - maxtics = 1; //no players on the server. let timings slide - // don't bother running a frame if sys_ticrate seconds haven't passed while (1) { diff --git a/engine/server/sv_send.c b/engine/server/sv_send.c index 81f85108..4e5a3bb7 100644 --- a/engine/server/sv_send.c +++ b/engine/server/sv_send.c @@ -3384,7 +3384,11 @@ void SV_SendClientMessages (void) continue; } - SVQ3_SendMessage(c); + if (c->lastoutgoingphysicstime == pt) + continue; + c->lastoutgoingphysicstime = pt; + + q3->sv.SendMessage(c); } return; } @@ -3461,7 +3465,7 @@ void SV_SendClientMessages (void) #ifdef Q3SERVER if (ISQ3CLIENT(c)) { //q3 protocols bypass backbuffering and pretty much everything else - SVQ3_SendMessage(c); + q3->sv.SendMessage(c); continue; } #endif diff --git a/engine/server/svq2_game.c b/engine/server/svq2_game.c index 0b50c12b..25abb338 100644 --- a/engine/server/svq2_game.c +++ b/engine/server/svq2_game.c @@ -92,13 +92,13 @@ void *SVQ2_GetGameAPI (void *parms) } else if (*gamename[o] == '/') { //system path. o.O - if (com_nogamedirnativecode.ival) //just in case they match. + if (!com_gamedirnativecode.ival) //just in case they match. continue; Q_snprintfz(name, sizeof(name), gamename[o], gamepath); } else { //gamedir paths as specified above. - if (com_nogamedirnativecode.ival) + if (!com_gamedirnativecode.ival) continue; Q_snprintfz(name, sizeof(name), "%s%s", syspath, gamename[o]); } diff --git a/engine/server/svq3_game.c b/engine/server/svq3_game.c index 5c5dfd8c..adc1f7ef 100644 --- a/engine/server/svq3_game.c +++ b/engine/server/svq3_game.c @@ -1,10 +1,10 @@ -#include "quakedef.h" +#include "q3common.h" +#define net_message asrgsaerge //An implementation of a Q3 server... //requires qvm implementation and existing q3 client stuff (or at least the overlapping stuff in q3common.c). #ifdef Q3SERVER - #define USEBOTLIB #ifdef USEBOTLIB @@ -16,6 +16,8 @@ #include "botlib.h" #define Z_TAG_BOTLIB 221726 +static zonegroup_t botlibmem; +static zonegroup_t botlibhunkmem; static botlib_export_t *FTE_GetBotLibAPI(int apiVersion, botlib_import_t *import) { //a stub that will prevent botlib from loading. @@ -49,13 +51,19 @@ botlib_export_t *botlib; #include "clq3defs.h" #include "q3g_public.h" -static vm_t *q3gamevm; +#define svs (*sv3.server_state_static) +#define sv (*sv3.server_state) + +vm_t *q3gamevm; +#ifdef VM_CG +extern vm_t *cgvm; +#endif #define fs_key 0 -#define MAX_CONFIGSTRINGS 1024 -static char *svq3_configstrings[MAX_CONFIGSTRINGS]; +static qboolean q3_serverinfo_dirty; //signals that the serverinfo has changed. this involves networking so we use a flag to gather changes to splurge at once instead of many minor changes that each send out new config string updates +static char *svq3_configstrings[MAX_Q3_CONFIGSTRINGS]; static qboolean q3_serverinfo_dirty; static q3sharedEntity_t *q3_entarray; @@ -68,7 +76,7 @@ static int q3_num_snapshot_entities; static int q3_next_snapshot_entities; static q3entityState_t *q3_snapshot_entities; static q3entityState_t *q3_baselines; -extern cvar_t sv_pure; +cvar_t *sv_maxclients; #define NUM_FOR_GENTITY(ge) (((char*)ge - (char*)q3_entarray) / sizeofq3gentity) #define NUM_FOR_SENTITY(se) (se - q3_sentities) @@ -79,13 +87,14 @@ extern cvar_t sv_pure; static qboolean BoundsIntersect (vec3_t mins1, vec3_t maxs1, vec3_t mins2, vec3_t maxs2); +static int SVQ3_AddBot(void); void SVQ3_CreateBaseline(void); void SVQ3_ClientThink(client_t *cl); #ifdef QWOVERQ3 static void SVQ3Q1_ConvertEntStateQ1ToQ3(entity_state_t *q1, q3entityState_t *q3); #endif -const char *mapentspointer; +static const char *mapentspointer; #define Q3SOLID_BMODEL 0xffffff @@ -124,20 +133,38 @@ const char *mapentspointer; //these entities are private to the engine. gamecode shall not see this. typedef struct { -#ifdef USEAREAGRID areagridlink_t areas[16]; size_t areagridsequence; -#else - link_t area; -#endif + qboolean linked; pvscache_t pvscache; } q3serverEntity_t; -q3serverEntity_t *q3_sentities; +static q3serverEntity_t *q3_sentities; + +// ClearLink is used for new headnodes +static void W_ClearLink (link_t *l) +{ + l->prev = l->next = l; +} + +static void W_RemoveLink (link_t *l) +{ + l->next->prev = l->prev; + l->prev->next = l->next; +} + +static void W_InsertLinkBefore (link_t *l, link_t *before) +{ + l->next = before; + l->prev = before->prev; + l->prev->next = l; + l->next->prev = l; +} static void Q3G_UnlinkEntity(q3sharedEntity_t *ent) { + int i; q3serverEntity_t *sent; ent->r.linked = false; @@ -149,26 +176,25 @@ static void Q3G_UnlinkEntity(q3sharedEntity_t *ent) return; // not linked in anywhere } -#ifdef USEAREAGRID - {int i; - for (i = 0; i < countof(sent->areas); i++) - { - if (!sent->areas[i].ed) - break; - RemoveLink(&sent->areas[i].l); - sent->areas[i].ed = NULL; - } + for (i = 0; i < countof(sent->areas); i++) + { + if (!sent->areas[i].ed) + break; + W_RemoveLink(&sent->areas[i].l); + sent->areas[i].ed = NULL; } -#else - if (sent->area.prev == NULL || sent->area.next == NULL) - SV_Error("Null entity links in linked entity\n"); - - RemoveLink(&sent->area); - sent->area.prev = sent->area.next = NULL; -#endif sent->linked = false; } +#define CALCAREAGRIDBOUNDS(min,max) \ + ming[0] = floor(((min)[0]+sv3.gridbias[0]) / sv3.gridscale[0]); \ + ming[1] = floor(((min)[1]+sv3.gridbias[1]) / sv3.gridscale[1]); \ + maxg[0] = floor(((max)[0]+sv3.gridbias[0]) / sv3.gridscale[0]); \ + maxg[1] = floor(((max)[1]+sv3.gridbias[1]) / sv3.gridscale[1]); \ + ming[0] = bound(0, ming[0], sv3.gridsize[0]-1); \ + ming[1] = bound(0, ming[1], sv3.gridsize[1]-1); \ + maxg[0] = bound(ming[0], maxg[0], sv3.gridsize[0]-1)+1; \ + maxg[1] = bound(ming[1], maxg[1], sv3.gridsize[1]-1)+1; #define MAX_TOTAL_ENT_LEAFS 256 @@ -178,20 +204,18 @@ static model_t *Q3G_GetCModel(unsigned int modelindex) //1 == *1 //this is not how quake's precaches normally work. modelindex++; - if ((unsigned int)modelindex < MAX_PRECACHE_MODELS) + if ((unsigned int)modelindex < countof(sv3.models)) { - if (!sv.models[modelindex]) + if (!sv3.models[modelindex]) { if (modelindex == 1) - sv.models[modelindex] = sv.world.worldmodel; + sv3.models[modelindex] = sv3.world->worldmodel; else - sv.models[modelindex] = Mod_ForName(Mod_FixName(va("*%i", modelindex-1), sv.modelname), MLV_WARN); + sv3.models[modelindex] = worldfuncs->LoadModel(worldfuncs->FixName(va("*%i", modelindex-1), sv.modelname), MLV_WARNSYNC); } - if (sv.models[modelindex]->loadstate == MLS_LOADING) - COM_WorkerPartialSync(sv.models[modelindex], &sv.models[modelindex]->loadstate, MLS_LOADING); - if (sv.models[modelindex]->loadstate == MLS_LOADED) - return sv.models[modelindex]; + if (sv3.models[modelindex]->loadstate == MLS_LOADED) + return sv3.models[modelindex]; } return NULL; } @@ -279,7 +303,7 @@ static void Q3G_LinkEntity(q3sharedEntity_t *ent) ent->r.absmax[2] += 1; // link to PVS leafs - sv.world.worldmodel->funcs.FindTouchedLeafs(sv.world.worldmodel, &sent->pvscache, ent->r.absmin, ent->r.absmax); + sv3.world->worldmodel->funcs.FindTouchedLeafs(sv3.world->worldmodel, &sent->pvscache, ent->r.absmin, ent->r.absmax); //FIXME: return if no leafs ent->r.linkcount++; @@ -287,12 +311,11 @@ static void Q3G_LinkEntity(q3sharedEntity_t *ent) sent->linked = true; // find the first node that the ent's box crosses -#ifdef USEAREAGRID - CALCAREAGRIDBOUNDS(&sv.world, ent->r.absmin, ent->r.absmax); + CALCAREAGRIDBOUNDS(ent->r.absmin, ent->r.absmax); if ((maxg[0]-ming[0])*(maxg[1]-ming[1]) > countof(sent->areas)) { //entity is too large to fit in our grid. shove it in the overflow sent->areas[0].ed = sent; - InsertLinkBefore (&sent->areas[0].l, &sv.world.jumboarea.l); + W_InsertLinkBefore (&sent->areas[0].l, &sv3.jumboarea.l); } else { @@ -300,29 +323,53 @@ static void Q3G_LinkEntity(q3sharedEntity_t *ent) for ( g[1] = ming[1]; g[1] < maxg[1]; g[1]++, ga++) { sent->areas[ga].ed = sent; - InsertLinkBefore (&sent->areas[ga].l, &sv.world.gridareas[g[0] + g[1]*sv.world.gridsize[0]].l); + W_InsertLinkBefore (&sent->areas[ga].l, &sv3.gridareas[g[0] + g[1]*sv3.gridsize[0]].l); } } -#else - node = sv.world.areanodes; - while(1) - { - if(node->axis == -1) - break; - - if(ent->r.absmin[node->axis] > node->dist) - node = node->children[0]; - else if(ent->r.absmax[node->axis] < node->dist) - node = node->children[1]; - else - break; // crosses the node - } - // link it in - InsertLinkBefore((link_t *)&sent->area, &node->edicts); -#endif } -#ifdef USEAREAGRID +static void SVQ3_ClearWorld(void) +{ + int numareas = 1; + int i; + vec3_t mins, maxs, size; + if (sv3.world->worldmodel) + { + VectorCopy(sv3.world->worldmodel->mins, mins); + VectorCopy(sv3.world->worldmodel->maxs, maxs); + } + else + { + VectorSet(mins, -4096, -4096, -4096); + VectorSet(maxs, 4096, 4096, 4096); + } + Vector2Set(sv3.gridsize, 128, 128); + for (i = 0; i < 2; i++) + { + size[i] = maxs[i] - mins[i]; + size[i] /= sv3.gridsize[i]; + //enforce a minimum grid size, so things don't end up getting added to every single node + if (size[i] < 128) + { + mins[i] -= (128-size[i])/2 * sv3.gridsize[i]; + size[i] = 128; + } + sv3.gridscale[i] = size[i]; + sv3.gridbias[i] = -mins[i]; + + numareas *= sv3.gridsize[i]; + } + + if (sv3.gridareas) + memset (sv3.gridareas, 0, sizeof(*sv3.gridareas)*numareas); + else + sv3.gridareas = Z_Malloc(sizeof(*sv3.gridareas)*numareas); + + for (i = 0; i < numareas; i++) + W_ClearLink (&sv3.gridareas[i].l); + W_ClearLink (&sv3.jumboarea.l); +} + static int SVQ3_EntitiesInBoxNode(areagridlink_t *node, vec3_t mins, vec3_t maxs, int *list, int maxcount) { link_t *l, *next; @@ -339,9 +386,9 @@ static int SVQ3_EntitiesInBoxNode(areagridlink_t *node, vec3_t mins, vec3_t maxs next = l->next; sent = ((areagridlink_t*)l)->ed; - if (sent->areagridsequence != areagridsequence) + if (sent->areagridsequence != sv3.areagridsequence) { - sent->areagridsequence = areagridsequence; + sent->areagridsequence = sv3.areagridsequence; gent = GENTITY_FOR_SENTITY(sent); if (!BoundsIntersect(mins, maxs, gent->r.absmin, gent->r.absmax)) @@ -357,58 +404,14 @@ static int SVQ3_EntitiesInBox(vec3_t mins, vec3_t maxs, int *list, int maxcount) { int ming[2], maxg[2], g[2], ga; int linkcount = 0; - areagridsequence++; - linkcount += SVQ3_EntitiesInBoxNode(&sv.world.jumboarea, mins, maxs, list+linkcount, maxcount-linkcount); - CALCAREAGRIDBOUNDS(&sv.world, mins, maxs); + sv3.areagridsequence++; + linkcount += SVQ3_EntitiesInBoxNode(&sv3.jumboarea, mins, maxs, list+linkcount, maxcount-linkcount); + CALCAREAGRIDBOUNDS(mins, maxs); for (ga = 0, g[0] = ming[0]; g[0] < maxg[0]; g[0]++) for ( g[1] = ming[1]; g[1] < maxg[1]; g[1]++, ga++) - linkcount += SVQ3_EntitiesInBoxNode(&sv.world.gridareas[g[0] + g[1]*sv.world.gridsize[0]], mins, maxs, list+linkcount, maxcount-linkcount); + linkcount += SVQ3_EntitiesInBoxNode(&sv3.gridareas[g[0] + g[1]*sv3.gridsize[0]], mins, maxs, list+linkcount, maxcount-linkcount); return linkcount; } -#else -static int SVQ3_EntitiesInBoxNode(areanode_t *node, vec3_t mins, vec3_t maxs, int *list, int maxcount) -{ - link_t *l, *next; - q3serverEntity_t *sent; - q3sharedEntity_t *gent; - - int linkcount = 0; - - //work out who they are first. - for (l = node->edicts.next ; l != &node->edicts ; l = next) - { - if (maxcount == linkcount) - return linkcount; - - next = l->next; - sent = Q3EDICT_FROM_AREA(l); - gent = GENTITY_FOR_SENTITY(sent); - - if (!BoundsIntersect(mins, maxs, gent->r.absmin, gent->r.absmax)) - continue; - - list[linkcount++] = NUM_FOR_GENTITY(gent); - } - - if (node->axis >= 0) - { - - if ( maxs[node->axis] > node->dist ) - linkcount += SVQ3_EntitiesInBoxNode(node->children[0], mins, maxs, list+linkcount, maxcount-linkcount); - if ( mins[node->axis] < node->dist ) - linkcount += SVQ3_EntitiesInBoxNode(node->children[1], mins, maxs, list+linkcount, maxcount-linkcount); - } - - return linkcount; -} - -static int SVQ3_EntitiesInBox(vec3_t mins, vec3_t maxs, int *list, int maxcount) -{ - if (maxcount < 0) - return 0; - return SVQ3_EntitiesInBoxNode(sv.world.areanodes, mins, maxs, list, maxcount); -} -#endif #define ENTITYNUM_NONE (MAX_GENTITIES-1) #define ENTITYNUM_WORLD (MAX_GENTITIES-2) @@ -427,7 +430,7 @@ static void SVQ3_Trace(q3trace_t *result, vec3_t start, vec3_t mins, vec3_t maxs if (!maxs) maxs = vec3_origin; - sv.world.worldmodel->funcs.NativeTrace(sv.world.worldmodel, 0, NULLFRAMESTATE, NULL, start, end, mins, maxs, capsule, contentmask, &tr); + sv3.world->worldmodel->funcs.NativeTrace(sv3.world->worldmodel, 0, NULLFRAMESTATE, NULL, start, end, mins, maxs, capsule, contentmask, &tr); result->allsolid = tr.allsolid; result->contents = tr.contents; VectorCopy(tr.endpos, result->endpos); @@ -440,6 +443,9 @@ static void SVQ3_Trace(q3trace_t *result, vec3_t start, vec3_t mins, vec3_t maxs else result->surfaceFlags = 0; + if (result->allsolid) + return; + for (i = 0; i < 3; i++) { if (start[i] < end[i]) @@ -465,7 +471,6 @@ static void SVQ3_Trace(q3trace_t *result, vec3_t start, vec3_t mins, vec3_t maxs else ourowner = -1; - for (i = SVQ3_EntitiesInBox(mmins, mmaxs, contactlist, sizeof(contactlist)/sizeof(contactlist[0]))-1; i >= 0; i--) { if (contactlist[i] == entnum) @@ -490,19 +495,22 @@ static void SVQ3_Trace(q3trace_t *result, vec3_t start, vec3_t mins, vec3_t maxs mod = Q3G_GetCModel(es->s.modelindex); if (!mod) continue; - World_TransformedTrace(mod, 0, 0, start, end, mins, maxs, capsule, &tr, es->r.currentOrigin, es->r.currentAngles, contentmask); + worldfuncs->TransformedTrace(mod, 0, 0, start, end, mins, maxs, capsule, &tr, es->r.currentOrigin, es->r.currentAngles, contentmask); } else { if (es->r.svFlags & SVF_CAPSULE) - mod = CM_TempBoxModel(es->r.mins, es->r.maxs); + mod = worldfuncs->TempBoxModel(es->r.mins, es->r.maxs); else - mod = CM_TempBoxModel(es->r.mins, es->r.maxs); - World_TransformedTrace(mod, 0, 0, start, end, mins, maxs, capsule, &tr, es->r.currentOrigin, vec3_origin, contentmask); + mod = worldfuncs->TempBoxModel(es->r.mins, es->r.maxs); + worldfuncs->TransformedTrace(mod, 0, 0, start, end, mins, maxs, capsule, &tr, es->r.currentOrigin, vec3_origin, contentmask); } - if (tr.fraction < result->fraction) + if (tr.allsolid) + tr.fraction = 0; + +/* if (tr.fraction < result->fraction) { - result->allsolid = tr.allsolid; + result->allsolid |= tr.allsolid; result->contents = tr.contents; VectorCopy(tr.endpos, result->endpos); result->entityNum = contactlist[i]; @@ -514,6 +522,34 @@ static void SVQ3_Trace(q3trace_t *result, vec3_t start, vec3_t mins, vec3_t maxs // else result->surfaceFlags = 0; } + else if (tr.startsolid) + { + result->entityNum = contactlist[i]; + result->startsolid = true; + if (tr.allsolid) + result->allsolid = true; + } +*/ + + if ( tr.allsolid || tr.fraction < result->fraction ) { + result->allsolid |= tr.allsolid; + result->contents = tr.contents; + VectorCopy(tr.endpos, result->endpos); + result->entityNum = contactlist[i]; + result->fraction = tr.fraction; + result->plane = tr.plane; + result->startsolid |= tr.startsolid; +// if (tr.surface) +// result->surfaceFlags = tr.surface->flags; +// else + result->surfaceFlags = 0; + + } else if ( tr.startsolid ) { + result->startsolid = qtrue; + } + if ( result->allsolid ) { + return; + } } } @@ -528,10 +564,7 @@ static int SVQ3_PointContents(vec3_t pos, int entnum) int cont; - -// sv.worldmodel->funcs.Trace(sv.worldmodel, 0, 0, pos, pos, vec3_origin, vec3_origin, &tr); -// tr = CM_BoxTrace(sv.worldmodel, pos, pos, vec3_origin, vec3_origin, 0); - cont = sv.world.worldmodel->funcs.NativeContents (sv.world.worldmodel, 0, 0, NULL, pos, vec3_origin, vec3_origin); + cont = sv3.world->worldmodel->funcs.NativeContents (sv3.world->worldmodel, 0, 0, NULL, pos, vec3_origin, vec3_origin); if ((unsigned)entnum >= MAX_GENTITIES) ourowner = -1; @@ -566,12 +599,12 @@ static int SVQ3_PointContents(vec3_t pos, int entnum) mod = Q3G_GetCModel(es->s.modelindex); if (!mod) continue; - World_TransformedTrace(mod, 0, NULL, pos, pos, vec3_origin, vec3_origin, false, &tr, es->r.currentOrigin, es->r.currentAngles, 0xffffffff); + worldfuncs->TransformedTrace(mod, 0, NULL, pos, pos, vec3_origin, vec3_origin, false, &tr, es->r.currentOrigin, es->r.currentAngles, 0xffffffff); } else { - mod = CM_TempBoxModel(es->r.mins, es->r.maxs); - World_TransformedTrace(mod, 0, NULL, pos, pos, vec3_origin, vec3_origin, false, &tr, es->r.currentOrigin, vec3_origin, 0xffffffff); + mod = worldfuncs->TempBoxModel(es->r.mins, es->r.maxs); + worldfuncs->TransformedTrace(mod, 0, NULL, pos, pos, vec3_origin, vec3_origin, false, &tr, es->r.currentOrigin, vec3_origin, 0xffffffff); } cont |= tr.contents; @@ -593,13 +626,13 @@ static int SVQ3_Contact(vec3_t mins, vec3_t maxs, q3sharedEntity_t *ent, qboolea else { ang = vec3_origin; - mod = CM_TempBoxModel(ent->r.mins, ent->r.maxs); + mod = worldfuncs->TempBoxModel(ent->r.mins, ent->r.maxs); } if (!mod || !mod->funcs.NativeTrace) return false; - World_TransformedTrace(mod, 0, 0, vec3_origin, vec3_origin, mins, maxs, capsule, &tr, ent->r.currentOrigin, ang, 0xffffffff); + worldfuncs->TransformedTrace(mod, 0, 0, vec3_origin, vec3_origin, mins, maxs, capsule, &tr, ent->r.currentOrigin, ang, 0xffffffff); if (tr.startsolid) return true; @@ -611,7 +644,7 @@ static void SVQ3_SetBrushModel(q3sharedEntity_t *ent, char *modelname) int modelindex; model_t *mod; if (!modelname || *modelname != '*') - SV_Error("SVQ3_SetBrushModel: not an inline model"); + plugfuncs->EndGame("SVQ3_SetBrushModel: not an inline model"); modelindex = atoi(modelname+1); mod = Q3G_GetCModel(modelindex); if (mod) @@ -642,7 +675,7 @@ static qboolean SVQ3_GetUserCmd(int clientnumber, q3usercmd_t *ucmd) usercmd_t *cmd; if (clientnumber < 0 || clientnumber >= sv.allocated_client_slots) - SV_Error("SVQ3_GetUserCmd: Client out of range"); + plugfuncs->EndGame("SVQ3_GetUserCmd: Client out of range"); cmd = &svs.clients[clientnumber].lastcmd; ucmd->angles[0] = cmd->angles[0]; @@ -655,6 +688,7 @@ static qboolean SVQ3_GetUserCmd(int clientnumber, q3usercmd_t *ucmd) ucmd->buttons = cmd->buttons; ucmd->weapon = cmd->weapon; + return true; } @@ -674,6 +708,8 @@ void SVQ3_SendServerCommand(client_t *cl, char *str) } cl->server_command_sequence++; + if (cl->protocol!=SCP_BAD && cl->server_command_sequence-cl->server_command_ack >= countof(cl->server_commands)) + Con_Printf("%s: Reliable overflow %i-%i>%i\n", cl->name, cl->server_command_sequence,cl->server_command_ack, (int)countof(cl->server_commands)); Q_strncpyz(cl->server_commands[cl->server_command_sequence & Q3TEXTCMD_MASK], str, sizeof(cl->server_commands[0])); } @@ -726,7 +762,7 @@ void SVQ3_SetConfigString(int num, char *string) svq3_configstrings[num] = Z_Malloc(len+1); strcpy(svq3_configstrings[num], string); - if (sv.state == ss_loading && !sv.restarting) + if (sv.state == ss_loading && !sv3.restarting) return; //don't spam these, the svcq3_gamestate will have a copy anyway and the gamecode can get confused. SVQ3_SendConfigString(NULL, num, string); } @@ -771,12 +807,12 @@ static void SVQ3_Adjust_Area_Portal_State(q3sharedEntity_t *ge, qboolean open) q3serverEntity_t *se = SENTITY_FOR_GENTITY(ge); if (se->pvscache.areanum == -1 || se->pvscache.areanum2 == -1) //not linked properly. return; - sv.world.worldmodel->funcs.SetAreaPortalState(sv.world.worldmodel, -1, se->pvscache.areanum, se->pvscache.areanum2, open); + sv3.world->worldmodel->funcs.SetAreaPortalState(sv3.world->worldmodel, -1, se->pvscache.areanum, se->pvscache.areanum2, open); } static qboolean SV_InPVS(vec3_t p1, vec3_t p2) { - model_t *worldmodel = sv.world.worldmodel; + model_t *worldmodel = sv3.world->worldmodel; if (!worldmodel || worldmodel->loadstate != MLS_LOADED) return false; //still loading, don't give bad results. @@ -799,7 +835,7 @@ static qboolean SV_InPVS(vec3_t p1, vec3_t p2) } } -#define VALIDATEPOINTER(o,l) if ((int)o + l >= mask || VM_POINTER(o) < offset) SV_Error("Call to game trap %u passes invalid pointer\n", (unsigned int)fn); //out of bounds. +#define VALIDATEPOINTER(o,l) if ((int)o + l >= mask || VM_POINTER(o) < offset) plugfuncs->EndGame("Call to game trap %u passes invalid pointer\n", (unsigned int)fn); //out of bounds. static qintptr_t Q3G_SystemCalls(void *offset, quintptr_t mask, qintptr_t fn, const qintptr_t *arg) { int ret = 0; @@ -809,10 +845,10 @@ static qintptr_t Q3G_SystemCalls(void *offset, quintptr_t mask, qintptr_t fn, co Con_Printf("%s", (char*)VM_POINTER(arg[0])); break; case G_ERROR: // ( const char *string ); - SV_Error("Q3 Game error: %s", (char*)VM_POINTER(arg[0])); + plugfuncs->EndGame("Q3 Game error: %s", (char*)VM_POINTER(arg[0])); break; case G_MILLISECONDS: - return Sys_DoubleTime()*1000; + return plugfuncs->GetMilliseconds(); case G_CVAR_REGISTER:// ( vmCvar_t *vmCvar, const char *varName, const char *defaultValue, int flags ); if (arg[0]) @@ -823,27 +859,19 @@ static qintptr_t Q3G_SystemCalls(void *offset, quintptr_t mask, qintptr_t fn, co return VMQ3_Cvar_Update(VM_POINTER(arg[0])); case G_CVAR_SET:// ( const char *var_name, const char *value ); - { - cvar_t *var; - var = Cvar_FindVar(VM_POINTER(arg[0])); - if (var) - Cvar_Set(var, VM_POINTER(arg[1])); //set it - else - Cvar_Get(VM_POINTER(arg[0]), VM_POINTER(arg[1]), 0, "Q3-Game-Code created"); //create one - } + cvarfuncs->SetString(VM_POINTER(arg[0]), VM_POINTER(arg[1])); //set it break; case G_CVAR_VARIABLE_INTEGER_VALUE:// ( const char *var_name ); { cvar_t *var; - var = Cvar_Get(VM_POINTER(arg[0]), "0", 0, "Q3-Game-Code created"); + var = cvarfuncs->GetNVFDG(VM_POINTER(arg[0]), "0", 0, NULL, "Q3-Game-Code created"); if (var) - return var->value; + return var->ival; } break; case G_CVAR_VARIABLE_STRING_BUFFER:// ( const char *var_name, char *buffer, int bufsize ); { - cvar_t *var; - var = Cvar_FindVar(VM_POINTER(arg[0])); + cvar_t *var = cvarfuncs->GetNVFDG(VM_POINTER(arg[0]), NULL, 0, NULL, "Q3-Game-Code created"); if (!VM_LONG(arg[2])) return 0; else if (!var) @@ -863,21 +891,21 @@ static qintptr_t Q3G_SystemCalls(void *offset, quintptr_t mask, qintptr_t fn, co case G_BOT_FREE_CLIENT: case G_DROP_CLIENT: if ((unsigned)VM_LONG(arg[0]) < sv.allocated_client_slots) - SV_DropClient(&svs.clients[VM_LONG(arg[0])]); + worldfuncs->DropClient(&svs.clients[VM_LONG(arg[0])]); break; case G_BOT_ALLOCATE_CLIENT: return SVQ3_AddBot(); case G_ARGC: //8 - return Cmd_Argc(); + return cmdfuncs->Argc(); case G_ARGV: //9 VALIDATEPOINTER(arg[1], arg[2]); - Q_strncpyz(VM_POINTER(arg[1]), Cmd_Argv(VM_LONG(arg[0])), VM_LONG(arg[2])); + cmdfuncs->Argv(VM_LONG(arg[0]), VM_POINTER(arg[1]), VM_LONG(arg[2])); break; case G_SEND_CONSOLE_COMMAND: - Cbuf_AddText(VM_POINTER(arg[1]), RESTRICT_SERVER); + cmdfuncs->AddText(VM_POINTER(arg[1]), false); return 0; @@ -896,6 +924,8 @@ static qintptr_t Q3G_SystemCalls(void *offset, quintptr_t mask, qintptr_t fn, co case G_FS_WRITE: //fwrite ret = VM_FWrite(VM_POINTER(arg[0]), VM_LONG(arg[1]), VM_LONG(arg[2]), 0); break; + case G_FS_SEEK: + return VM_FSeek(arg[0], arg[1], arg[2], 0); case G_FS_FCLOSE_FILE: //fclose VM_fclose(VM_LONG(arg[0]), 0); break; @@ -907,9 +937,8 @@ static qintptr_t Q3G_SystemCalls(void *offset, quintptr_t mask, qintptr_t fn, co case G_LOCATE_GAME_DATA: // ( gentity_t *gEnts, int numGEntities, int sizeofGEntity_t, 15 // playerState_t *clients, int sizeofGameClient ); - if (VM_OOB(arg[0], arg[1]*arg[2]) || VM_OOB(arg[3], arg[4]*MAX_CLIENTS)) - SV_Error("Gamedata is out of bounds\n"); + plugfuncs->EndGame("Gamedata is out of bounds\n"); q3_entarray = VM_POINTER(arg[0]); numq3entities = VM_LONG(arg[1]); sizeofq3gentity = VM_LONG(arg[2]); @@ -917,11 +946,10 @@ static qintptr_t Q3G_SystemCalls(void *offset, quintptr_t mask, qintptr_t fn, co sizeofGameClient = VM_LONG(arg[4]); if (numq3entities > MAX_GENTITIES) - SV_Error("Gamecode specifies too many entities"); + plugfuncs->EndGame("Gamecode specifies too many entities"); break; case G_SEND_SERVER_COMMAND: // ( int clientNum, const char *fmt, ... ); 17 - Con_DPrintf("Game dispatching %s\n", (char*)VM_POINTER(arg[1])); if (VM_LONG(arg[0]) == -1) { //broadcast @@ -937,12 +965,10 @@ static qintptr_t Q3G_SystemCalls(void *offset, quintptr_t mask, qintptr_t fn, co break; case G_SET_CONFIGSTRING: // ( int num, const char *string ); 18 - if (arg[0] < 0 || arg[0] >= MAX_CONFIGSTRINGS) - return 0; SVQ3_SetConfigString(arg[0], VM_POINTER(arg[1])); break; case G_GET_CONFIGSTRING: // ( int num, char *buffer, int bufferSize ); 19 - if (arg[0] < 0 || arg[0] >= MAX_CONFIGSTRINGS || !arg[2]) + if (arg[0] < 0 || arg[0] >= MAX_Q3_CONFIGSTRINGS || !arg[2]) return 0; VALIDATEPOINTER(arg[1], arg[2]); if (svq3_configstrings[arg[0]]) @@ -957,7 +983,7 @@ static qintptr_t Q3G_SystemCalls(void *offset, quintptr_t mask, qintptr_t fn, co int length = VM_LONG(arg[1]); if (VM_OOB(arg[1], arg[2])) return 0; - InfoBuf_ToString(&svs.info, dest, length, NULL, NULL, NULL, NULL, NULL); + worldfuncs->IBufToInfo(&svs.info, dest, length, NULL, NULL, NULL, NULL, NULL); } return true; case G_GET_USERINFO://int num, char *buffer, int bufferSize 20 @@ -965,14 +991,14 @@ static qintptr_t Q3G_SystemCalls(void *offset, quintptr_t mask, qintptr_t fn, co return 0; if ((unsigned)VM_LONG(arg[0]) >= sv.allocated_client_slots) return 0; - InfoBuf_ToString(&svs.clients[VM_LONG(arg[0])].userinfo, VM_POINTER(arg[1]), VM_LONG(arg[2]), NULL, NULL, NULL, NULL, NULL); + worldfuncs->IBufToInfo(&svs.clients[VM_LONG(arg[0])].userinfo, VM_POINTER(arg[1]), VM_LONG(arg[2]), NULL, NULL, NULL, NULL, NULL); break; case G_SET_USERINFO://int num, char *buffer 20 if (VM_OOB(arg[1], 1)) return 0; - InfoBuf_FromString(&svs.clients[VM_LONG(arg[0])].userinfo, VM_POINTER(arg[1]), false); - SV_ExtractFromUserinfo(&svs.clients[VM_LONG(arg[0])], false); + worldfuncs->IBufFromInfo(&svs.clients[VM_LONG(arg[0])].userinfo, VM_POINTER(arg[1]), false); + worldfuncs->ExtractFromUserinfo(&svs.clients[VM_LONG(arg[0])], false); break; case G_LINKENTITY: // ( gentity_t *ent ); 30 @@ -1016,7 +1042,7 @@ static qintptr_t Q3G_SystemCalls(void *offset, quintptr_t mask, qintptr_t fn, co SVQ3_GetUserCmd(VM_LONG(arg[0]), VM_POINTER(arg[1])); break; case G_GET_ENTITY_TOKEN: // qboolean ( char *buffer, int bufferSize ) 37 - mapentspointer = COM_ParseOut(mapentspointer, VM_POINTER(arg[0]), arg[1]); + mapentspointer = cmdfuncs->ParseToken(mapentspointer, VM_POINTER(arg[0]), arg[1], NULL); return !!mapentspointer; case G_REAL_TIME: // 41 @@ -1122,7 +1148,6 @@ static qintptr_t Q3G_SystemCalls(void *offset, quintptr_t mask, qintptr_t fn, co } return 0; - case BOTLIB_AAS_ENABLE_ROUTING_AREA: return botlib->aas.AAS_EnableRoutingArea(VM_LONG(arg[0]), VM_LONG(arg[1])); case BOTLIB_AAS_BBOX_AREAS: @@ -1321,7 +1346,9 @@ static qintptr_t Q3G_SystemCalls(void *offset, quintptr_t mask, qintptr_t fn, co botlib->ai.BotSetChatGender(arg[0], arg[1]); return 0; case BOTLIB_AI_SET_CHAT_NAME: - botlib->ai.BotSetChatName(arg[0], VM_POINTER(arg[1]), arg[2]); + botlib->ai.BotSetChatName(arg[0], VM_POINTER(arg[1]), + arg[2] + ); return 0; @@ -1491,7 +1518,7 @@ static qintptr_t Q3G_SystemCalls(void *offset, quintptr_t mask, qintptr_t fn, co case BOTLIB_PC_LOAD_SOURCE: if (!botlib) { - SV_Error("Botlib is not installed (trap BOTLIB_PC_LOAD_SOURCE)\n"); + plugfuncs->EndGame("Botlib is not installed (trap BOTLIB_PC_LOAD_SOURCE)\n"); } return botlib->PC_LoadSourceHandle(VM_POINTER(arg[0])); case BOTLIB_PC_FREE_SOURCE: @@ -1505,6 +1532,7 @@ static qintptr_t Q3G_SystemCalls(void *offset, quintptr_t mask, qintptr_t fn, co #endif + case G_IN_PVS: return SV_InPVS(VM_POINTER(arg[0]), VM_POINTER(arg[1])); case G_AREAS_CONNECTED: Con_Printf("Q3Game: builtin %s is not implemented\n", "G_AREAS_CONNECTED"); return ret; @@ -1522,8 +1550,6 @@ static qintptr_t Q3G_SystemCalls(void *offset, quintptr_t mask, qintptr_t fn, co VALIDATEPOINTER(arg[1], sizeof(vec3_t)); PerpendicularVector(VM_POINTER(arg[0]), VM_POINTER(arg[1])); break; - case G_FS_SEEK: Con_Printf("Q3Game: builtin %s is not implemented\n", "G_FS_SEEK"); return ret; - return VM_FSeek(arg[0], arg[1], arg[2], 0); //case G_DEFAULTCASEWARNINGDISABLE: NOT A REAL VALUE // notimplemented: @@ -1581,6 +1607,7 @@ static qintptr_t EXPORT_FN Q3G_SystemCallsNative(qintptr_t arg, ...) void SVQ3_ShutdownGame(qboolean restarting) { int i; + CG_Stop(); if (!q3gamevm) return; @@ -1590,11 +1617,16 @@ void SVQ3_ShutdownGame(qboolean restarting) if (botlib) { //it crashes otherwise, probably due to our huck clearage botlib->BotLibShutdown(); - Z_FreeTags(Z_TAG_BOTLIB); } + plugfuncs->GFreeAll(&botlibmem); + plugfuncs->GFreeAll(&botlibhunkmem); + VM_fcloseall(Z_TAG_BOTLIB); #endif + } - for (i = 0; i < MAX_CONFIGSTRINGS; i++) + if (!restarting) + { + for (i = 0; i < countof(svq3_configstrings); i++) { if (svq3_configstrings[i]) { @@ -1602,17 +1634,19 @@ void SVQ3_ShutdownGame(qboolean restarting) svq3_configstrings[i] = NULL; } } - - Z_Free(q3_sentities); + + plugfuncs->Free(q3_sentities); q3_sentities = NULL; - BZ_Free(q3_snapshot_entities); + plugfuncs->Free(q3_snapshot_entities); q3_snapshot_entities = NULL; } - VM_Destroy(q3gamevm); + vmfuncs->Destroy(q3gamevm); q3gamevm = NULL; - Cvar_Set(Cvar_Get("sv_running", "0", 0, "Q3 compatability"), "0"); + VM_fcloseall(0); + + cvarfuncs->SetString("sv_running", "0"); } #ifdef USEBOTLIB @@ -1638,7 +1672,7 @@ static void *QDECL BL_Malloc(int size) int *mem; botlibmemoryavailable-=size; - mem = (int *)Z_TagMalloc(size+sizeof(int), Z_TAG_BOTLIB); + mem = plugfuncs->GMalloc(&botlibmem, sizeof(int)+size); mem[0] = size; return (void *)(mem + 1); @@ -1647,11 +1681,11 @@ static void QDECL BL_Free(void *mem) { int *memref = ((int *)mem) - 1; botlibmemoryavailable+=memref[0]; - Z_TagFree(memref); + plugfuncs->GFree(&botlibmem, memref); } static void *QDECL BL_HunkMalloc(int size) { - return BL_Malloc(size);//Hunk_AllocName(size, "botlib"); + return plugfuncs->GMalloc(&botlibhunkmem, sizeof(int)+size); } static int QDECL BL_FOpenFile(const char *name, fileHandle_t *handle, fsMode_t mode) @@ -1674,9 +1708,9 @@ 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 const char *QDECL BL_BSPEntityData(void) +static char *QDECL BL_BSPEntityData(void) { - return Mod_GetEntitiesString(sv.world.worldmodel); + return (char*)worldfuncs->GetEntitiesString(sv3.world->worldmodel); } static void QDECL BL_Trace(bsp_trace_t *trace, vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, int passent, int contentmask) { @@ -1745,7 +1779,10 @@ static void QDECL BL_BSPModelMinsMaxsOrigin(int modelnum, vec3_t angles, vec3_t if ((angles[0] || angles[1] || angles[2])) { // expand for rotation - max = RadiusFromBounds(mins, maxs); + vec3_t corner; + for (i=0 ; i<3 ; i++) + corner[i] = fabs(mins[i]) > fabs(maxs[i]) ? fabs(mins[i]) : fabs(maxs[i]); + max = sqrt(DotProduct(corner,corner)); for (i = 0; i < 3; i++) { mins[i] = -max; @@ -1761,8 +1798,8 @@ static void QDECL BL_BSPModelMinsMaxsOrigin(int modelnum, vec3_t angles, vec3_t } static void QDECL BL_BotClientCommand(int clientnum, char *command) { - Cmd_TokenizeString(command, false, false); - VM_Call(q3gamevm, GAME_CLIENT_COMMAND, clientnum); + cmdfuncs->TokenizeString(command); + vmfuncs->Call(q3gamevm, GAME_CLIENT_COMMAND, clientnum); } static int QDECL BL_DebugLineCreate(void) {return 0;} @@ -1773,18 +1810,21 @@ static void QDECL BL_DebugPolygonDelete(int id) {} void QDECL BL_Error(const char *msg) { - Sys_Error("%s", msg); + plugfuncs->Error("%s", msg); } #endif -static void SV_InitBotLib(void) +void SV_InitBotLib(void) { - cvar_t *bot_enable = Cvar_Get("bot_enable", "1", 0, "Q3 compatability"); + cvar_t *bot_enable = cvarfuncs->GetNVFDG("bot_enable", "1", 0, "Controls whether bots may be used by the gamecode or not.", "Q3 compatability"); #ifdef USEBOTLIB botlib_import_t import; + if (!bot_enable) + return; //o.O - Cvar_Set(Cvar_Get("sv_mapChecksum", "0", 0, "Q3 compatability"), va("%i", sv.world.worldmodel->checksum)); + if (sv3.world && sv3.world->worldmodel) + cvarfuncs->SetString("sv_mapChecksum", va("%i", sv3.world->worldmodel->checksum)); memset(&import, 0, sizeof(import)); import.Print = BL_Print; @@ -1813,7 +1853,6 @@ static void SV_InitBotLib(void) import.Error = BL_Error; -// Z_FreeTags(Z_TAG_BOTLIB); botlibmemoryavailable = 1024*1024*16; if (bot_enable->value) botlib = FTE_GetBotLibAPI(BOTLIB_API_VERSION, &import); @@ -1822,12 +1861,12 @@ static void SV_InitBotLib(void) if (!botlib) { bot_enable->flags |= CVAR_MAPLATCH; - Cvar_ForceSet(bot_enable, "0"); + cvarfuncs->ForceSetString(bot_enable->name, "0"); } #else //make sure it's switched off. - Cvar_ForceSet(bot_enable, "0"); + cvarfuncs->ForceSetString(bot_enable->name, "0"); bot_enable->flags |= CVAR_NOSET; #endif } @@ -1837,56 +1876,60 @@ void SVQ3_ServerinfoChanged(const char *key) q3_serverinfo_dirty = true; } static void SVQ3_UpdateServerinfo(void) -{ +{ /*qw serverinfo settings are not normally visible in the q3 serverinfo, so strip them from the configstring*/ char buffer[8192]; - /*update serverinfo - qw serverinfo settings are not normally visible in the q3 serverinfo, so strip them from the configstring*/ static const char *ignores[] = {"maxclients", "map", "sv_maxclients", "*z_ext", "*bspversion", "*gamedir", NULL}; - extern cvar_t maxclients; - InfoBuf_ToString(&svs.info, buffer, sizeof(buffer), NULL, ignores, NULL, NULL, NULL); + worldfuncs->IBufToInfo(&svs.info, buffer, sizeof(buffer), NULL, ignores, NULL, NULL, NULL); //add in maxclients.. the q3 version - Q_strncatz(buffer, va("\\sv_maxclients\\%s", maxclients.string), sizeof(buffer)); + Q_strncatz(buffer, va("\\sv_maxclients\\%s", sv_maxclients->string), sizeof(buffer)); SVQ3_SetConfigString(0, buffer); + q3_serverinfo_dirty = false; } -qboolean SVQ3_InitGame(qboolean restart) +qboolean SVQ3_InitGame(server_static_t *server_state_static, server_t *server_state, qboolean restart) { int i; + char ssqcprogs[MAX_QPATH]; - if (sv.world.worldmodel->type == mod_heightmap) + sv3.server_state_static = server_state_static; + sv3.server_state = server_state; + sv3.world = &server_state->world; + if (sv3.world->worldmodel->type == mod_heightmap) { } else { - if (sv.world.worldmodel->fromgame == fg_quake || sv.world.worldmodel->fromgame == fg_halflife || sv.world.worldmodel->fromgame == fg_quake2) + if (sv3.world->worldmodel->fromgame == fg_quake || sv3.world->worldmodel->fromgame == fg_halflife || sv3.world->worldmodel->fromgame == fg_quake2) return false; //always fail on q1bsp } - if (*pr_ssqc_progs.string) //don't load q3 gamecode if we're explicitally told to load a progs. + cvarfuncs->GetString("pr_ssqc_progs", ssqcprogs, sizeof(ssqcprogs)); + if (*ssqcprogs) //don't load q3 gamecode if we're explicitally told to load a progs. return false; + sv3.restarting = restart; SVQ3_ShutdownGame(restart); - q3gamevm = VM_Create("qagame", com_nogamedirnativecode.ival?NULL:Q3G_SystemCallsNative, "vm/qagame", Q3G_SystemCallsVM); + sv_maxclients = cvarfuncs->GetNVFDG("sv_maxclients", "", 0, NULL, "Q3 Compat"); + + q3gamevm = vmfuncs->Create("qagame", cvarfuncs->GetFloat("com_gamedirnativecode")?Q3G_SystemCallsNative:NULL, "vm/qagame", Q3G_SystemCallsVM); if (!q3gamevm) return false; //q3 needs mapname (while qw has map serverinfo) - { - cvar_t *mapname = Cvar_Get("mapname", "", CVAR_SERVERINFO, "Q3 compatability"); - Cvar_Set(mapname, svs.name); - } + cvarfuncs->SetString("mapname", svs.name); SV_InitBotLib(); - World_ClearWorld(&sv.world, false); + SVQ3_ClearWorld(); q3_sentities = Z_Malloc(sizeof(q3serverEntity_t)*MAX_GENTITIES); - Cvar_Set(Cvar_Get("sv_running", "0", 0, "Q3 compatability"), "1"); + cvarfuncs->SetString("sv_running", "1"); //so the ui knows if (!restart) { @@ -1894,28 +1937,29 @@ qboolean SVQ3_InitGame(qboolean restart) char sysinfo[8192]; /*update the system info*/ sysinfo[0] = '\0'; - Info_SetValueForKey(sysinfo, "sv_serverid", va("%i", svs.spawncount), MAX_SERVERINFO_STRING); + worldfuncs->SetInfoKey(sysinfo, "sv_serverid", va("%i", svs.spawncount), MAX_SERVERINFO_STRING); - Info_SetValueForKey(sysinfo, "sv_paks", FS_GetPackHashes(buffer, sizeof(buffer), false ), MAX_SERVERINFO_STRING); - Info_SetValueForKey(sysinfo, "sv_pakNames", FS_GetPackNames (buffer, sizeof(buffer), false, false), MAX_SERVERINFO_STRING); - Info_SetValueForKey(sysinfo, "sv_referencedPaks", FS_GetPackHashes(buffer, sizeof(buffer), true ), MAX_SERVERINFO_STRING); - Info_SetValueForKey(sysinfo, "sv_referencedPakNames", FS_GetPackNames (buffer, sizeof(buffer), true, false ), MAX_SERVERINFO_STRING); + worldfuncs->SetInfoKey(sysinfo, "sv_paks", fsfuncs->GetPackHashes(buffer, sizeof(buffer), false ), MAX_SERVERINFO_STRING); + worldfuncs->SetInfoKey(sysinfo, "sv_pakNames", fsfuncs->GetPackNames (buffer, sizeof(buffer), false, false), MAX_SERVERINFO_STRING); + worldfuncs->SetInfoKey(sysinfo, "sv_referencedPaks", fsfuncs->GetPackHashes(buffer, sizeof(buffer), true ), MAX_SERVERINFO_STRING); + worldfuncs->SetInfoKey(sysinfo, "sv_referencedPakNames", fsfuncs->GetPackNames (buffer, sizeof(buffer), true, false ), MAX_SERVERINFO_STRING); - Info_SetValueForKey(sysinfo, "sv_pure", sv_pure.string, MAX_SERVERINFO_STRING); + cvarfuncs->GetString("sv_pure", buffer, sizeof(buffer)); + worldfuncs->SetInfoKey(sysinfo, "sv_pure", buffer, MAX_SERVERINFO_STRING); SVQ3_SetConfigString(1, sysinfo); q3_serverinfo_dirty = true; } - mapentspointer = Mod_GetEntitiesString(sv.world.worldmodel); - VM_Call(q3gamevm, GAME_INIT, (intptr_t)(sv.time*1000), (int)rand(), restart); + mapentspointer = worldfuncs->GetEntitiesString(sv3.world->worldmodel); + vmfuncs->Call(q3gamevm, GAME_INIT, (intptr_t)(sv3.world->physicstime*1000), (int)rand(), restart); if (!restart) - { + { //restart means same initial gamestate, meaning don't mess with baselines. SVQ3_CreateBaseline(); q3_num_snapshot_entities = 32 * Q3UPDATE_BACKUP * 32; if (q3_snapshot_entities) - BZ_Free(q3_snapshot_entities); + plugfuncs->Free(q3_snapshot_entities); q3_next_snapshot_entities = 0; q3_snapshot_entities = Z_Malloc(sizeof( q3entityState_t ) * q3_num_snapshot_entities); } @@ -1924,14 +1968,9 @@ qboolean SVQ3_InitGame(qboolean restart) for (i = 0; i < 3; i++) { SVQ3_RunFrame(); - sv.time += 0.1; + sv3.world->physicstime += 0.1; } -#ifdef HAVE_CLIENT - //there's a whole load of ugly debug crap there. make sure it stays hidden. - Con_ClearNotify(); -#endif - return true; } @@ -1939,9 +1978,9 @@ void SVQ3_RunFrame(void) { #ifdef USEBOTLIB if (botlib) - VM_Call(q3gamevm, BOTAI_START_FRAME, (int)(sv.time*1000)); + vmfuncs->Call(q3gamevm, BOTAI_START_FRAME, (int)(sv3.world->physicstime*1000)); #endif - VM_Call(q3gamevm, GAME_RUN_FRAME, (int)(sv.time*1000)); + vmfuncs->Call(q3gamevm, GAME_RUN_FRAME, (int)(sv3.world->physicstime*1000)); if (q3_serverinfo_dirty) SVQ3_UpdateServerinfo(); @@ -1949,39 +1988,39 @@ void SVQ3_RunFrame(void) void SVQ3_ClientCommand(client_t *cl) { - VM_Call(q3gamevm, GAME_CLIENT_COMMAND, (int)(cl-svs.clients)); + vmfuncs->Call(q3gamevm, GAME_CLIENT_COMMAND, (int)(cl-svs.clients)); } void SVQ3_ClientBegin(client_t *cl) { - VM_Call(q3gamevm, GAME_CLIENT_BEGIN, (int)(cl-svs.clients)); + vmfuncs->Call(q3gamevm, GAME_CLIENT_BEGIN, (int)(cl-svs.clients)); sv.spawned_client_slots++; cl->spawned = true; } void SVQ3_ClientThink(client_t *cl) { - VM_Call(q3gamevm, GAME_CLIENT_THINK, (int)(cl-svs.clients)); -} - -qboolean SVQ3_Command(void) -{ - if (!q3gamevm) - return false; - - return VM_Call(q3gamevm, GAME_CONSOLE_COMMAND); + vmfuncs->Call(q3gamevm, GAME_CLIENT_THINK, (int)(cl-svs.clients)); } qboolean SVQ3_ConsoleCommand(void) { if (!q3gamevm) return false; - Cmd_ShiftArgs(1, false); - VM_Call(q3gamevm, GAME_CONSOLE_COMMAND); + + return vmfuncs->Call(q3gamevm, GAME_CONSOLE_COMMAND); +} + +qboolean SVQ3_PrefixedConsoleCommand(void) +{ + if (!q3gamevm) + return false; + cmdfuncs->ShiftArgs(1); + vmfuncs->Call(q3gamevm, GAME_CONSOLE_COMMAND); return true; } -void SVQ3_Netchan_Transmit( client_t *client, int length, qbyte *data ); +static void SVQ3_Netchan_Transmit( client_t *client, int length, qbyte *data ); void SVQ3_CreateBaseline(void) { @@ -2095,7 +2134,7 @@ void SVQ3_EmitPacketEntities(client_t *client, q3client_frame_t *from, q3client_ } } - MSG_WriteBits(msg, ENTITYNUM_NONE, GENTITYNUM_BITS); // end of packetentities + msgfuncs->WriteBits(msg, ENTITYNUM_NONE, GENTITYNUM_BITS); // end of packetentities } void SVQ3_WriteSnapshotToClient(client_t *client, sizebuf_t *msg) @@ -2106,7 +2145,8 @@ void SVQ3_WriteSnapshotToClient(client_t *client, sizebuf_t *msg) int i; // this is the frame we are transmitting - snap = &client->frameunion.q3frames[client->netchan.outgoing_sequence & Q3UPDATE_MASK]; + snap = client->frameunion.q3frames; + snap += client->netchan.outgoing_sequence & Q3UPDATE_MASK; if(client->state < cs_spawned) { @@ -2132,7 +2172,8 @@ void SVQ3_WriteSnapshotToClient(client_t *client, sizebuf_t *msg) { // we have a valid message to delta from delta = client->netchan.outgoing_sequence - client->delta_sequence; - oldsnap = &client->frameunion.q3frames[client->delta_sequence & Q3UPDATE_MASK]; + oldsnap = client->frameunion.q3frames; + oldsnap += client->delta_sequence & Q3UPDATE_MASK; if(oldsnap->first_entity <= q3_next_snapshot_entities - q3_num_snapshot_entities) { @@ -2149,17 +2190,17 @@ void SVQ3_WriteSnapshotToClient(client_t *client, sizebuf_t *msg) // } // write snapshot header - MSG_WriteBits(msg, svcq3_snapshot, 8); - MSG_WriteBits(msg, snap->serverTime, 32); - MSG_WriteBits(msg, delta, 8); // what we are delta'ing from + msgfuncs->WriteBits(msg, svcq3_snapshot, 8); + msgfuncs->WriteBits(msg, snap->serverTime, 32); + msgfuncs->WriteBits(msg, delta, 8); // what we are delta'ing from // write snapFlags - MSG_WriteBits(msg, snap->flags, 8); + msgfuncs->WriteBits(msg, snap->flags, 8); // send over the areabits - MSG_WriteBits(msg, snap->areabytes, 8); + msgfuncs->WriteBits(msg, snap->areabytes, 8); for (i = 0; i < snap->areabytes; i++) - MSG_WriteBits(msg, snap->areabits[i], 8); + msgfuncs->WriteBits(msg, snap->areabits[i], 8); // delta encode the playerstate MSGQ3_WriteDeltaPlayerstate(msg, oldsnap ? &oldsnap->ps : NULL, &snap->ps); @@ -2195,7 +2236,7 @@ static int VARGS SVQ3_QsortEntityStates( const void *arg1, const void *arg2 ) return -1; } - SV_Error("SV_QsortEntityStates: duplicated entity"); + plugfuncs->EndGame("SV_QsortEntityStates: duplicated entity"); return 0; @@ -2218,7 +2259,7 @@ static qboolean SVQ3_EntityIsVisible(q3client_frame_t *snap, q3sharedEntity_t *e { if (clientNum > 32) { - SV_Error("SVF_CLIENTMASK: clientNum > 32" ); + plugfuncs->EndGame("SVF_CLIENTMASK: clientNum > 32" ); } if (ent->r.singleClient & (1 << (clientNum & 7))) { @@ -2266,7 +2307,7 @@ static qboolean SVQ3_EntityIsVisible(q3client_frame_t *snap, q3sharedEntity_t *e } } - return sv.world.worldmodel->funcs.EdictInFatPVS(sv.world.worldmodel, &sent->pvscache, bitvector, NULL/*using the snapshots areabits rather than the bsp's*/); + return sv3.world->worldmodel->funcs.EdictInFatPVS(sv3.world->worldmodel, &sent->pvscache, bitvector, NULL/*using the snapshots areabits rather than the bsp's*/); } #ifdef Q3OVERQW @@ -2359,9 +2400,10 @@ void SVQ3_BuildClientSnapshot( client_t *client ) } // this is the frame we are creating - snap = &client->frameunion.q3frames[client->netchan.outgoing_sequence & Q3UPDATE_MASK]; + snap = client->frameunion.q3frames; + snap += client->netchan.outgoing_sequence & Q3UPDATE_MASK; - snap->serverTime = sv.restartedtime*1000 + sv.time*1000;//svs.levelTime; // save it for ping calc later + snap->serverTime = sv3.world->physicstime*1000; // save it for ping calc later snap->flags = 0; if( client->state < cs_spawned ) @@ -2380,17 +2422,10 @@ void SVQ3_BuildClientSnapshot( client_t *client ) VectorCopy( ps->origin, org ); org[2] += ps->viewheight; - bitvector = sv.world.worldmodel->funcs.ClusterPVS(sv.world.worldmodel, sv.world.worldmodel->funcs.ClusterForPoint(sv.world.worldmodel, org, &clientarea), &pvsbuffer, PVM_REPLACE); -/* - if (client->areanum != clientarea) - { - Com_Printf( "%s entered area %i\n", client->name, clientarea); - client->areanum = clientarea; - } -*/ + bitvector = sv3.world->worldmodel->funcs.ClusterPVS(sv3.world->worldmodel, sv.world.worldmodel->funcs.ClusterForPoint(sv.world.worldmodel, org, &clientarea), &pvsbuffer, PVM_REPLACE); // calculate the visible areas - snap->areabytes = sv.world.worldmodel->funcs.WriteAreaBits(sv.world.worldmodel, snap->areabits, sizeof(snap->areabits), clientarea, false); + snap->areabytes = sv3.world->worldmodel->funcs.WriteAreaBits(sv3.world->worldmodel, snap->areabits, sizeof(snap->areabits), clientarea, false); // grab the current playerState_t memcpy(&snap->ps, ps, sizeof(snap->ps)); @@ -2414,9 +2449,9 @@ void SVQ3_BuildClientSnapshot( client_t *client ) continue; //merge pvs bits so we can see other ents through it - sv.world.worldmodel->funcs.ClusterPVS(sv.world.worldmodel, sv.world.worldmodel->funcs.ClusterForPoint(sv.world.worldmodel, ent->s.origin2, &portalarea), &pvsbuffer, PVM_MERGE); + sv3.world->worldmodel->funcs.ClusterPVS(sv3.world->worldmodel, sv3.world->worldmodel->funcs.ClusterForPoint(sv3.world->worldmodel, ent->s.origin2, &portalarea), &pvsbuffer, PVM_MERGE); //and areabits too - sv.world.worldmodel->funcs.WriteAreaBits(sv.world.worldmodel, snap->areabits, snap->areabytes, portalarea, true); + sv3.world->worldmodel->funcs.WriteAreaBits(sv3.world->worldmodel, snap->areabits, snap->areabytes, portalarea, true); } // add all visible entities @@ -2464,7 +2499,7 @@ void SVQ3_BuildClientSnapshot( client_t *client ) if( q3_next_snapshot_entities + snap->num_entities >= 0x7FFFFFFE ) { - SV_Error("q3_next_snapshot_entities wrapped"); + plugfuncs->EndGame("q3_next_snapshot_entities wrapped"); } // find duplicated entities @@ -2637,12 +2672,12 @@ static void SVQ3_WriteServerCommandsToClient(client_t *client, sizebuf_t *msg) for(i=client->server_command_ack+1; i<=client->server_command_sequence; i++) { - MSG_WriteBits(msg, svcq3_serverCommand, 8); - MSG_WriteBits(msg, i, 32); + msgfuncs->WriteBits(msg, svcq3_serverCommand, 8); + msgfuncs->WriteBits(msg, i, 32); str = client->server_commands[i & Q3TEXTCMD_MASK]; len = strlen(str); for (j = 0; j <= len; j++) - MSG_WriteBits(msg, str[j], 8); + msgfuncs->WriteBits(msg, str[j], 8); } } @@ -2663,28 +2698,28 @@ void SVQ3_SendGameState(client_t *client) msg.packing = SZ_HUFFMAN; // write last clientCommand number we have processed - MSG_WriteBits(&msg, client->last_client_command_num, 32); + msgfuncs->WriteBits(&msg, client->last_client_command_num, 32); SVQ3_WriteServerCommandsToClient(client, &msg); - MSG_WriteBits(&msg, svcq3_gamestate, 8 ); - MSG_WriteBits(&msg, client->server_command_sequence, 32); + msgfuncs->WriteBits(&msg, svcq3_gamestate, 8 ); + msgfuncs->WriteBits(&msg, client->server_command_sequence, 32); switch (svs.gametype) { case GT_QUAKE3: // write configstrings - for( i=0; iWriteBits( &msg, svcq3_configstring, 8); + msgfuncs->WriteBits( &msg, i, 16 ); for (j = 0; configString[j]; j++) - MSG_WriteBits(&msg, configString[j], 8); - MSG_WriteBits(&msg, 0, 8); + msgfuncs->WriteBits(&msg, configString[j], 8); + msgfuncs->WriteBits(&msg, 0, 8); } // write baselines @@ -2693,7 +2728,7 @@ void SVQ3_SendGameState(client_t *client) if (!q3_baselines[i].number) continue; - MSG_WriteBits(&msg, svcq3_baseline, 8); + msgfuncs->WriteBits(&msg, svcq3_baseline, 8); MSGQ3_WriteDeltaEntity( &msg, NULL, &q3_baselines[i], true ); } break; @@ -2702,7 +2737,7 @@ void SVQ3_SendGameState(client_t *client) case GT_Q1QVM: SVQ3Q1_SendGamestateConfigstrings(&msg); - for (i = sv.allocated_client_slots+1; i < sv.world.num_edicts; i++) + for (i = sv.allocated_client_slots+1; i < sv3.world->num_edicts; i++) { edict_t *e = EDICT_NUM(svprogfuncs, i); if (e->baseline.modelindex) @@ -2721,13 +2756,13 @@ void SVQ3_SendGameState(client_t *client) } // write svc_eom command - MSG_WriteBits(&msg, svcq3_eom, 8); + msgfuncs->WriteBits(&msg, svcq3_eom, 8); - MSG_WriteBits(&msg, client - svs.clients, 32); - MSG_WriteBits(&msg, fs_key, 32); + msgfuncs->WriteBits(&msg, client - svs.clients, 32); + msgfuncs->WriteBits(&msg, fs_key, 32); // end of message marker - MSG_WriteBits(&msg, svcq3_eom, 8); + msgfuncs->WriteBits(&msg, svcq3_eom, 8); // send the datagram SVQ3_Netchan_Transmit(client, msg.cursize, msg.data); @@ -2750,7 +2785,7 @@ void SVQ3_SendMessage(client_t *client) SVQ3_BuildClientSnapshot(client); - MSG_WriteBits(&msg, client->last_client_command_num, 32); + msgfuncs->WriteBits(&msg, client->last_client_command_num, 32); // write pending serverCommands SVQ3_WriteServerCommandsToClient(client, &msg); @@ -2762,7 +2797,7 @@ void SVQ3_SendMessage(client_t *client) // SV_WriteDownloadToClient(client, &msg); // end of message marker - MSG_WriteBits(&msg, svcq3_eom, 8); + msgfuncs->WriteBits(&msg, svcq3_eom, 8); SVQ3_Netchan_Transmit(client, msg.cursize, msg.data); } @@ -2772,7 +2807,6 @@ void SVQ3_SendMessage(client_t *client) client_t *SVQ3_FindEmptyPlayerSlot(void) { - extern cvar_t maxclients; int pcount = 0; int i; for (i = 0; i < sv.allocated_client_slots; i++) @@ -2781,7 +2815,7 @@ client_t *SVQ3_FindEmptyPlayerSlot(void) pcount++; } //in q3, spectators are not special - if (pcount >= maxclients.value) + if (pcount >= sv_maxclients->value) return NULL; for (i = 0; i < sv.allocated_client_slots; i++) { @@ -2795,76 +2829,69 @@ client_t *SVQ3_FindExistingPlayerByIP(netadr_t *na, int qport) int i; for (i = 0; i < sv.allocated_client_slots; i++) { - if (svs.clients[i].state && NET_CompareAdr(&svs.clients[i].netchan.remote_address, na)) + if (svs.clients[i].state && msgfuncs->CompareAdr(&svs.clients[i].netchan.remote_address, na)) return &svs.clients[i]; } return NULL; } -qboolean Netchan_ProcessQ3 (netchan_t *chan); -static qboolean SVQ3_Netchan_Process(client_t *client) +static qboolean SVQ3_Netchan_Process(client_t *client, sizebuf_t *msg) { -#ifndef Q3_NOENCRYPT - int serverid; - int lastSequence; - int lastServerCommandNum; - qbyte bitmask; - qbyte c; - int i, j; - char *string; - int bit; - int readcount; -#endif - - if (!Netchan_ProcessQ3(&client->netchan)) + if (Netchan_ProcessQ3(&client->netchan, msg)) { - return false; +#ifndef Q3_NOENCRYPT + int serverid; + int lastSequence; + int lastServerCommandNum; + qbyte bitmask; + qbyte c; + int i, j; + char *string; + int bit; + + // archive buffer state + bit = msg->currentbit; + msg->packing = SZ_HUFFMAN; + + serverid = msgfuncs->ReadBits(32); + lastSequence = msgfuncs->ReadBits(32); + lastServerCommandNum = msgfuncs->ReadBits(32); + + // restore buffer state + msg->currentbit = bit; + msg->packing = SZ_RAWBYTES; + + // calculate bitmask + bitmask = (serverid ^ lastSequence ^ client->challenge) & 0xff; + string = client->server_commands[lastServerCommandNum & Q3TEXTCMD_MASK]; + + // decrypt the packet + for(i=msgfuncs->ReadCount()+12,j=0; icursize; i++,j++) + { + if(!string[j]) + { + j = 0; // another way around + } + c = string[j]; + if(c > 127 || c == '%') + { + c = '.'; + } + bitmask ^= c << (i & 1); + msg->data[i] ^= bitmask; + } +#endif + return true; } -#ifndef Q3_NOENCRYPT - // archive buffer state - bit = net_message.currentbit; - readcount = msg_readcount; - net_message.packing = SZ_HUFFMAN; - - serverid = MSG_ReadBits(32); - lastSequence = MSG_ReadBits(32); - lastServerCommandNum = MSG_ReadBits(32); - - // restore buffer state - net_message.currentbit = bit; - msg_readcount = readcount; - net_message.packing = SZ_RAWBYTES; - - // calculate bitmask - bitmask = (serverid ^ lastSequence ^ client->challenge) & 0xff; - string = client->server_commands[lastServerCommandNum & Q3TEXTCMD_MASK]; - - // decrypt the packet - for(i=msg_readcount+12,j=0; i 127 || c == '%') - { - c = '.'; - } - bitmask ^= c << (i & 1); - net_message.data[i] ^= bitmask; - } -#endif - - return true; + return false; } -void SVQ3_Netchan_Transmit(client_t *client, int length, qbyte *data) +static void SVQ3_Netchan_Transmit(client_t *client, int length, qbyte *data) { +#ifndef Q3_NOENCRYPT qbyte buffer[MAX_OVERALLMSGLEN]; int i; -#ifndef Q3_NOENCRYPT qbyte bitmask; qbyte c; int j; @@ -2881,24 +2908,18 @@ void SVQ3_Netchan_Transmit(client_t *client, int length, qbyte *data) for(j=0 ; i 127 || c == '%') - { c = '.'; - } bitmask ^= c << (i & 1); buffer[i] = data[i]^bitmask; } -#else - for( i=0 ; inetchan, length, buffer); + Netchan_TransmitQ3(sv3.server_state_static->sockets, &client->netchan, length, data); } int StringKey(const char *string, int length); @@ -2926,11 +2947,14 @@ void SVQ3_ParseUsercmd(client_t *client, qboolean delta) } // read number of usercmds in a packet - cmdCount = MSG_ReadBits(8); - if(cmdCount < 1) - SV_DropClient(client); - else if(cmdCount > MAX_PACKET_USERCMDS) - SV_DropClient(client); + cmdCount = msgfuncs->ReadBits(8); + if (cmdCount < 1 || + cmdCount > MAX_PACKET_USERCMDS || + svs.gametype != GT_QUAKE3) + { + worldfuncs->DropClient(client); + return; + } if(client->state < cs_connected) return; // was dropped @@ -2952,24 +2976,13 @@ void SVQ3_ParseUsercmd(client_t *client, qboolean delta) case cs_connected: // transition from CS_PRIMED to CS_ACTIVE memcpy(&client->lastcmd, &commands[cmdCount-1], sizeof(client->lastcmd)); - if (svs.gametype == GT_QUAKE3) - SVQ3_ClientBegin(client); - else - { - sv_player = host_client->edict; - SV_Begin_Core(client); - } + SVQ3_ClientBegin(client); client->state = cs_spawned; client->lastcmd.servertime = sv.time*1000; break; case cs_spawned: // run G_ClientThink() on each usercmd - if (svs.gametype != GT_QUAKE3) - { - sv_player = host_client->edict; - SV_PreRunCmd(); - } for(i=0,to=commands; iservertime <= client->lastcmd.servertime) @@ -2983,31 +2996,8 @@ void SVQ3_ParseUsercmd(client_t *client, qboolean delta) } memcpy(&client->lastcmd, to, sizeof(client->lastcmd)); - if (svs.gametype == GT_QUAKE3) - SVQ3_ClientThink(client); - else if (svs.gametype == GT_PROGS || svs.gametype == GT_Q1QVM) - { - usercmd_t temp; - temp = client->lastcmd; -#ifdef warningmsg -#pragma warningmsg("qwoverq3: you need to be aware of this if you're making a compatible cgame") -#endif - //if you read the q3 code, you'll see that the speed value used is 64 for walking, and 127 for running (full speed). - //so we map full to full here. - temp.sidemove *= client->maxspeed/127.0f; - temp.forwardmove *= client->maxspeed/127.0f; - temp.upmove *= client->maxspeed/127.0f; - temp.msec = bound(0, to->servertime - temp.servertime, 255); - - temp.buttons &= ~2; - if (temp.buttons & 64) - temp.buttons |= 2; - SV_RunCmd(&temp, false); - client->lastcmd.servertime = to->servertime; - } + SVQ3_ClientThink(client); } - if (svs.gametype != GT_QUAKE3) - SV_PostRunCmd(); break; default: break; // outdated usercmd packet @@ -3017,16 +3007,16 @@ void SVQ3_ParseUsercmd(client_t *client, qboolean delta) void SVQ3_UpdateUserinfo_f(client_t *cl) { - InfoBuf_FromString(&cl->userinfo, Cmd_Argv(1), false); - SV_ExtractFromUserinfo (cl, true); + worldfuncs->IBufFromInfo(&cl->userinfo, cmdfuncs->Argv(1, NULL, 0), false); + worldfuncs->ExtractFromUserinfo (cl, true); if (svs.gametype == GT_QUAKE3 && cl->spawned) - VM_Call(q3gamevm, GAME_CLIENT_USERINFO_CHANGED, (int)(cl-svs.clients)); + vmfuncs->Call(q3gamevm, GAME_CLIENT_USERINFO_CHANGED, (int)(cl-svs.clients)); } static void SVQ3_Drop_f(client_t *cl) { - SV_DropClient(cl); + worldfuncs->DropClient(cl); } //part of the sv_pure mechanism. verifies the client's pack list and kicks if they're wrong. @@ -3039,7 +3029,7 @@ static void SVQ3_Download_f(client_t *cl) { //clients might end up waiting for the download which will never come. //kick them so that doesn't happen. downloads are not supported at this time. not even reporting failure! :s - SV_DropClient(cl); + worldfuncs->DropClient(cl); // short 0 // long -1 } @@ -3081,12 +3071,13 @@ void SVQ3_ParseClientCommand(client_t *client) char *command; const ucmd_t *u; char buffer[2048]; + char arg0[256]; int i; - commandNum = MSG_ReadBits(32); + commandNum = msgfuncs->ReadBits(32); for (i = 0; ; i++) { - buffer[i] = MSG_ReadBits(8); + buffer[i] = msgfuncs->ReadBits(8); if (!buffer[i]) break; } @@ -3104,19 +3095,20 @@ void SVQ3_ParseClientCommand(client_t *client) if(commandNum > client->last_client_command_num) { Con_Printf("Client %s lost %i clientCommands\n", client->name, commandNum - client->last_client_command_num); - SV_DropClient(client); + worldfuncs->DropClient(client); return; } // copy current command for netchan encryption Q_strncpyz(client->last_client_command, command, sizeof(client->last_client_command)); - Cmd_TokenizeString(command, false, false); + cmdfuncs->TokenizeString(command); // check for server private commands first + cmdfuncs->Argv(0, arg0, sizeof(arg0)); for(u=ucmds; u->name; u++) { - if(!stricmp(Cmd_Argv(0), u->name)) + if(!Q_strcasecmp(arg0, u->name)) { if(u->func) u->func(client); @@ -3129,29 +3121,27 @@ void SVQ3_ParseClientCommand(client_t *client) SVQ3_ClientCommand(client); } -void SVQ3_ParseClientMessage(client_t *client) +void SVQ3_ParseClientMessage(client_t *client, sizebuf_t *msg) { int serverid; //sorta like the level number. int c; - host_client = client; - // remaining data is compressed - net_message.packing = SZ_HUFFMAN; - net_message.currentbit = msg_readcount*8; + msg->packing = SZ_HUFFMAN; + msg->currentbit = msgfuncs->ReadCount()*8; // read serverid - serverid = MSG_ReadBits(32); + serverid = msgfuncs->ReadBits(32); // read last server message sequence client received - client->last_sequence = MSG_ReadBits(32); + client->last_sequence = msgfuncs->ReadBits(32); if( client->last_sequence < 0 ) { return; // this shouldn't happen } // read last server command number client received - client->server_command_ack = MSG_ReadBits(32); + client->server_command_ack = msgfuncs->ReadBits(32); if( client->server_command_ack <= client->server_command_sequence - Q3TEXTCMD_BACKUP ) client->server_command_ack = client->server_command_sequence - Q3TEXTCMD_BACKUP + 1; //too old else if( client->server_command_ack > client->server_command_sequence ) @@ -3185,14 +3175,13 @@ void SVQ3_ParseClientMessage(client_t *client) if(client->state < cs_connected) return; // parsed command caused client to disconnect - if(msg_readcount > net_message.cursize) + c = msgfuncs->ReadBits(8); + if (c < 0) { Con_Printf("corrupt packet from %s\n", client->name); client->drop = true; return; } - - c = MSG_ReadBits(8); if (c == clcq3_eom) { break; @@ -3218,22 +3207,21 @@ void SVQ3_ParseClientMessage(client_t *client) } } - if (msg_readcount != net_message.cursize) + if (msg->currentbit+8 < (msg->cursize<<3)) { Con_Printf(CON_WARNING "WARNING: Junk at end of packet for client %s\n", client->name ); } }; -qboolean SVQ3_HandleClient(void) +qboolean SVQ3_HandleClient(netadr_t *from, sizebuf_t *msg) { int i; int qport; - if (net_message.cursize<6) - return false; //urm. :/ - - MSG_BeginReading(msg_nullnetprim); - MSG_ReadBits(32); - qport = (unsigned short)MSG_ReadBits(16); + msgfuncs->BeginReading(msg, msg_nullnetprim); + msgfuncs->ReadBits(32); + qport = msgfuncs->ReadBits(16); + if (qport < 0) + return false; for (i = 0; i < sv.allocated_client_slots; i++) { @@ -3241,7 +3229,7 @@ qboolean SVQ3_HandleClient(void) continue; if (svs.clients[i].netchan.qport != qport) continue; - if (!NET_CompareBaseAdr(&svs.clients[i].netchan.remote_address, &net_from)) + if (!msgfuncs->CompareBaseAdr(&svs.clients[i].netchan.remote_address, from)) continue; if (!ISQ3CLIENT(&svs.clients[i])) continue; @@ -3252,15 +3240,16 @@ qboolean SVQ3_HandleClient(void) if (i == sv.allocated_client_slots) return false; //nope - if (!SVQ3_Netchan_Process(&svs.clients[i])) + if (!SVQ3_Netchan_Process(&svs.clients[i], msg)) { return true; // wasn't accepted for some reason } - SVQ3_ParseClientMessage(&svs.clients[i]); + SVQ3_ParseClientMessage(&svs.clients[i], msg); return true; } + //Q3 gamecode does map_restart weirdly. //it simply reloads the gamecode without changing any maps/models/sounds //this won't work for q1/q2, but q3 expects it. @@ -3268,21 +3257,16 @@ qboolean SVQ3_HandleClient(void) qboolean SVQ3_RestartGamecode(void) { int i; - extern cvar_t maxclients; - int newmaxclients = max(8,maxclients.ival); + int newmaxclients = max(8,sv_maxclients->ival); if (sv.allocated_client_slots != newmaxclients) return false; //can't do it if maxclients needs to change. - Cvar_ApplyLatches(CVAR_MAPLATCH, false); - //reload the gamecode sv.state = ss_loading; - sv.restarting = true; - if (!SVQ3_InitGame(true)) + if (!SVQ3_InitGame(sv3.server_state_static, sv3.server_state, true)) return false; // svs.spawncount++; //so new snapshots get sent - sv.restartedtime = 0; //and then reconnect the players as appropriate // SVQ3_NewMapConnects(); @@ -3292,9 +3276,9 @@ qboolean SVQ3_RestartGamecode(void) if (svs.clients[i].state < cs_connected) continue; - if (VM_Call(q3gamevm, GAME_CLIENT_CONNECT, i, false, svs.clients[i].protocol == SCP_BAD)) + if (vmfuncs->Call(q3gamevm, GAME_CLIENT_CONNECT, i, false, svs.clients[i].protocol == SCP_BAD)) { - SV_DropClient(&svs.clients[i]); + worldfuncs->DropClient(&svs.clients[i]); continue; } if (svs.clients[i].spawned) @@ -3304,18 +3288,18 @@ qboolean SVQ3_RestartGamecode(void) } } - sv.starttime = Sys_DoubleTime() - sv.time; + sv.starttime = plugfuncs->GetSeconds() - sv.time; #ifdef SAVEDGAMES - sv.autosave_time = sv.time + sv_autosave.value*60; + sv.autosave_time = sv.time + cvarfuncs->GetFloat("sv_autosave")*60; #endif //basically done sv.state = ss_active; - sv.restarting = false; + sv3.restarting = false; //and an extra physics frame for luck sv.time+=0.1; - sv.world.physicstime=sv.time; + sv3.world->physicstime=sv.time; SVQ3_RunFrame(); SVQ3_SendServerCommand(NULL, "map_restart"); @@ -3330,7 +3314,7 @@ void SVQ3_NewMapConnects(void) /* Kick old bots in SP - eukara */ cvar_t *gametype; - gametype = Cvar_Get("g_gametype", "", CVAR_MAPLATCH|CVAR_SERVERINFO, "Q3 compatability"); + gametype = cvarfuncs->GetNVFDG("g_gametype", "", CVAR_MAPLATCH|CVAR_SERVERINFO, NULL, "Q3 compatability"); for (i = 0; i < sv.allocated_client_slots; i++) { @@ -3340,10 +3324,10 @@ void SVQ3_NewMapConnects(void) if (gametype->value == 2 && svs.clients[i].protocol == SCP_BAD) ret = true; else - ret = VM_Call(q3gamevm, GAME_CLIENT_CONNECT, i, false, svs.clients[i].protocol == SCP_BAD); + ret = vmfuncs->Call(q3gamevm, GAME_CLIENT_CONNECT, i, false, svs.clients[i].protocol == SCP_BAD); if (ret) { - SV_DropClient(&svs.clients[i]); + worldfuncs->DropClient(&svs.clients[i]); } else if (svs.clients[i].protocol == SCP_BAD) { //spawn bots now. @@ -3353,7 +3337,7 @@ void SVQ3_NewMapConnects(void) } } -void SVQ3_DirectConnect(void) //Actually connect the client, use up a slot, and let the gamecode know of it. +void SVQ3_DirectConnect(netadr_t *from, sizebuf_t *msg) //Actually connect the client, use up a slot, and let the gamecode know of it. { //this is only called when running q3 gamecode char *reason; @@ -3364,31 +3348,26 @@ void SVQ3_DirectConnect(void) //Actually connect the client, use up a slot, and int qport; char adr[MAX_ADR_SIZE]; - if (net_message.cursize < 13) + if (msg->cursize < 12) return; -#ifdef HUFFNETWORK - Huff_DecryptPacket(&net_message, 12); -#endif + if (msgfuncs->Huff_DecryptPacket) + msgfuncs->Huff_DecryptPacket(msg, 12); + cmdfuncs->TokenizeString((char*)msg->data+4); + userinfo = cmdfuncs->Argv(1, NULL, 0); + qport = atoi(worldfuncs->GetInfoKey(userinfo, "qport")); + challenge = atoi(worldfuncs->GetInfoKey(userinfo, "challenge")); - Cmd_TokenizeString((char*)net_message.data+4, false, false); - userinfo = Cmd_Argv(1); - qport = atoi(Info_ValueForKey(userinfo, "qport")); - challenge = atoi(Info_ValueForKey(userinfo, "challenge")); - - cl = SVQ3_FindExistingPlayerByIP(&net_from, qport); //use a duplicate first. + cl = SVQ3_FindExistingPlayerByIP(from, qport); //use a duplicate first. if (!cl) cl = SVQ3_FindEmptyPlayerSlot(); -#ifdef HUFFNETWORK - if (!Huff_CompressionCRC(HUFFCRC_QUAKE3)) + if (!msgfuncs->Huff_CompressionCRC || !msgfuncs->Huff_CompressionCRC(HUFFCRC_QUAKE3)) { reason = "Could not set up compression."; userinfo = NULL; } - else -#endif - if (!cl) + else if (!cl) { reason = "Server is full."; userinfo = NULL; @@ -3396,26 +3375,26 @@ void SVQ3_DirectConnect(void) //Actually connect the client, use up a slot, and else { if (cl->frameunion.q3frames) - BZ_Free(cl->frameunion.q3frames); + plugfuncs->Free(cl->frameunion.q3frames); memset(cl, 0, sizeof(*cl)); - challenge = atoi(Info_ValueForKey(userinfo, "challenge")); + challenge = atoi(worldfuncs->GetInfoKey(userinfo, "challenge")); - if (net_from.type != NA_LOOPBACK && !SV_ChallengePasses(challenge)) - reason = "Invalid challenge"; + if (from->type != NA_LOOPBACK && !worldfuncs->ChallengePasses(challenge)) + reason = "Invalid challenge\n"; else { - InfoBuf_FromString(&cl->userinfo, userinfo, false); - if (net_from.type == NA_LOOPBACK) + worldfuncs->IBufFromInfo(&cl->userinfo, userinfo, false); + if (from->type == NA_LOOPBACK) reason = "localhost"; //Q3 uses this specific string for listen servers. else - reason = NET_AdrToString(adr, sizeof(adr), &net_from); - InfoBuf_SetKey(&cl->userinfo, "ip", reason); //q3 gamecode needs to know the client's ip (server's perception of the client, NOT QW client's perception of the server/proxy) + reason = masterfuncs->AdrToString(adr, sizeof(adr), from); + worldfuncs->SetIBufKey(&cl->userinfo, "ip", reason); //q3 gamecode needs to know the client's ip (server's perception of the client, NOT QW client's perception of the server/proxy) - ret = VM_Call(q3gamevm, GAME_CLIENT_CONNECT, (int)(cl-svs.clients), true, false); + ret = vmfuncs->Call(q3gamevm, GAME_CLIENT_CONNECT, (int)(cl-svs.clients), true/*firsttime*/, false/*isbot*/); if (!ret) reason = NULL; else - reason = (char*)VM_MemoryBase(q3gamevm)+ret; + reason = (char*)vmfuncs->MemoryBase(q3gamevm)+ret; } } @@ -3423,7 +3402,7 @@ void SVQ3_DirectConnect(void) //Actually connect the client, use up a slot, and { Con_Printf("%s\n", reason); reason = va("\377\377\377\377print\n%s", reason); - NET_SendPacket (svs.sockets, strlen(reason), reason, &net_from); + msgfuncs->SendPacket (svs.sockets, strlen(reason), reason, from); return; } @@ -3431,8 +3410,8 @@ void SVQ3_DirectConnect(void) //Actually connect the client, use up a slot, and cl->state = cs_connected; cl->name = cl->namebuf; cl->team = cl->teambuf; - SV_ExtractFromUserinfo(cl, true); - Netchan_Setup(NS_SERVER, &cl->netchan, &net_from, qport); + worldfuncs->ExtractFromUserinfo(cl, true); + Netchan_SetupQ3(NS_SERVER, &cl->netchan, from, qport); cl->netchan.outgoing_sequence = 1; cl->challenge = challenge; @@ -3440,12 +3419,12 @@ void SVQ3_DirectConnect(void) //Actually connect the client, use up a slot, and cl->gamestatesequence = -1; - NET_SendPacket (svs.sockets, 19, "\377\377\377\377connectResponse", &net_from); + msgfuncs->SendPacket (svs.sockets, 19, "\377\377\377\377connectResponse", from); - cl->frameunion.q3frames = BZ_Malloc(Q3UPDATE_BACKUP*sizeof(*cl->frameunion.q3frames)); + cl->frameunion.q3frames = plugfuncs->Malloc(Q3UPDATE_BACKUP*sizeof(q3client_frame_t)); } -int SVQ3_AddBot(void) +static int SVQ3_AddBot(void) { client_t *cl; @@ -3470,7 +3449,7 @@ int SVQ3_AddBot(void) void SVQ3_DropClient(client_t *cl) { if (q3gamevm) - VM_Call(q3gamevm, GAME_CLIENT_DISCONNECT, (int)(cl-svs.clients)); + vmfuncs->Call(q3gamevm, GAME_CLIENT_DISCONNECT, (int)(cl-svs.clients)); } #endif diff --git a/engine/vk/vk_init.c b/engine/vk/vk_init.c index a4bb2ec3..f2937bc0 100644 --- a/engine/vk/vk_init.c +++ b/engine/vk/vk_init.c @@ -3497,7 +3497,7 @@ static void VK_PaintScreen(void) if (topmenu && topmenu->isopaque) nohud = true; #ifdef VM_CG - else if (CG_Refresh()) + else if (q3->cg.Redraw(cl.time)) nohud = true; #endif #ifdef CSQC_DAT diff --git a/imgtool.c b/imgtool.c index 02e990e3..0654a245 100644 --- a/imgtool.c +++ b/imgtool.c @@ -184,7 +184,7 @@ char *COM_SkipPath (const char *pathname) #ifdef __unix__ #include #endif -qbyte *FS_LoadMallocFile (const char *path, size_t *fsize) +void *FS_LoadMallocFile (const char *path, size_t *fsize) { qbyte *data = NULL; FILE *f; diff --git a/plugins/Makefile b/plugins/Makefile index fe2463d9..29d6379b 100644 --- a/plugins/Makefile +++ b/plugins/Makefile @@ -356,6 +356,51 @@ else $(PLUG_PREFIX)cef$(PLUG_NATIVE_EXT): @echo cef plugin not supported on this arch - $(FTE_TARGET) - $(CEF_ARCH) endif + +###################################### +#quake3 + +BOTLIBFILES=../engine/botlib/be_aas_bspq3.c \ + ../engine/botlib/be_aas_cluster.c \ + ../engine/botlib/be_aas_debug.c \ + ../engine/botlib/be_aas_entity.c \ + ../engine/botlib/be_aas_file.c \ + ../engine/botlib/be_aas_main.c \ + ../engine/botlib/be_aas_move.c \ + ../engine/botlib/be_aas_optimize.c \ + ../engine/botlib/be_aas_reach.c \ + ../engine/botlib/be_aas_routealt.c \ + ../engine/botlib/be_aas_route.c \ + ../engine/botlib/be_aas_sample.c \ + ../engine/botlib/be_ai_char.c \ + ../engine/botlib/be_ai_chat.c \ + ../engine/botlib/be_ai_gen.c \ + ../engine/botlib/be_ai_goal.c \ + ../engine/botlib/be_ai_move.c \ + ../engine/botlib/be_ai_weap.c \ + ../engine/botlib/be_ai_weight.c \ + ../engine/botlib/be_ea.c \ + ../engine/botlib/be_interface.c \ + ../engine/botlib/l_crc.c \ + ../engine/botlib/l_libvar.c \ + ../engine/botlib/l_log.c \ + ../engine/botlib/l_memory.c \ + ../engine/botlib/l_precomp.c \ + ../engine/botlib/l_script.c \ + ../engine/botlib/l_struct.c \ + ../engine/botlib/standalone.c +QUAKE3FILES=$(BOTLIBFILES) \ + plugin.c \ + ../engine/client/cl_cg.c \ + ../engine/client/cl_ui.c \ + ../engine/client/clq3_parse.c \ + ../engine/server/svq3_game.c \ + ../engine/common/q3common.c +$(PLUG_PREFIX)quake3$(PLUG_NATIVE_EXT): ${QUAKE3FILES} + $(CC) $(BASE_CFLAGS) $(CFLAGS) -DFTEPLUGIN -DBOTLIB -DBOTLIB_STATIC -o $@ -shared $(PLUG_CFLAGS) $^ $(PLUG_DEFFILE) $(PLUG_LDFLAGS_ZLIB) $(PLUG_LDFLAGS) + $(call EMBEDMETA,quake3,$@,Quake3 Compat,Quake3 Gamecode Compatibility) +NATIVE_PLUGINS+=quake3 + ###################################### #for custom/private plugins... diff --git a/plugins/avplug/avencode.c b/plugins/avplug/avencode.c index fd89464b..3de872a6 100644 --- a/plugins/avplug/avencode.c +++ b/plugins/avplug/avencode.c @@ -782,66 +782,43 @@ static media_encoder_funcs_t encoderfuncs = }; -qboolean AVEnc_ExecuteCommand(qboolean isinsecure) +static void AVEnc_Preset_Nvidia_f(void) { - char cmd[256]; - cmdfuncs->Argv(0, cmd, sizeof(cmd)); -/* - if (!strcmp(cmd, ENCODERNAME"_configure")) - { -menuclear -menualias menucallback + cvarfuncs->SetString("capturedriver", ENCODERNAME); //be sure to use our encoder + cvarfuncs->SetString(ENCODERNAME"_videocodec", "h264_nvenc"); + cvarfuncs->SetString("capturerate", "60"); //we should be able to cope with it, and the default of 30 sucks + cvarfuncs->SetString("capturedemowidth", "1920"); //force a specific size, some codecs need multiples of 16 or whatever. + cvarfuncs->SetString("capturedemoheight", "1080"); //so this avoids issues with various video codecs. -menubox 0 0 320 8 -menutext 0 0 "GO GO GO!!!" "radio21" -menutext 0 8 "Fall back" "radio22" -menutext 0 8 "Stick together" "radio23" -menutext 0 16 "Get in position" "radio24" -menutext 0 24 "Storm the front" "radio25" -menutext 0 24 "Report in" "radio26" -menutext 0 24 "Cancel" - return true; - } -*/ - if (!strcmp(cmd, ENCODERNAME"_nvidia")) - { - cvarfuncs->SetString("capturedriver", ENCODERNAME); //be sure to use our encoder - cvarfuncs->SetString(ENCODERNAME"_videocodec", "h264_nvenc"); - cvarfuncs->SetString("capturerate", "60"); //we should be able to cope with it, and the default of 30 sucks - cvarfuncs->SetString("capturedemowidth", "1920"); //force a specific size, some codecs need multiples of 16 or whatever. - cvarfuncs->SetString("capturedemoheight", "1080"); //so this avoids issues with various video codecs. + cvarfuncs->SetString("capturesound", "1"); + cvarfuncs->SetString("capturesoundchannels", "2"); + cvarfuncs->SetString("capturesoundbits", "16"); - cvarfuncs->SetString("capturesound", "1"); - cvarfuncs->SetString("capturesoundchannels", "2"); - cvarfuncs->SetString("capturesoundbits", "16"); + Con_Printf(ENCODERNAME": now configured for nvidia's hardware encoder\n"); + Con_Printf(ENCODERNAME": use ^[/capture foo.mp4^] or ^[/capturedemo foo.mvd foo.mkv^] commands to begin capturing\n"); +} +void AVEnc_Preset_Defaults_f(void) +{ //most formats will end up using the x264 encoder or something + cvarfuncs->SetString(ENCODERNAME"_format_force", ""); + cvarfuncs->SetString(ENCODERNAME"_videocodec", ""); + cvarfuncs->SetString(ENCODERNAME"_videobitrate", ""); + cvarfuncs->SetString(ENCODERNAME"_videoforcewidth", ""); + cvarfuncs->SetString(ENCODERNAME"_videoforceheight", ""); + cvarfuncs->SetString(ENCODERNAME"_videopreset", "veryfast"); + cvarfuncs->SetString(ENCODERNAME"_video_crf", ""); + cvarfuncs->SetString(ENCODERNAME"_audiocodec", ""); + cvarfuncs->SetString(ENCODERNAME"_audiobitrate", ""); - Con_Printf(ENCODERNAME": now configured for nvidia's hardware encoder\n"); - Con_Printf(ENCODERNAME": use ^[/capture foo.mp4^] or ^[/capturedemo foo.mvd foo.mkv^] commands to begin capturing\n"); - } - if (!strcmp(cmd, ENCODERNAME"_defaults")) - { //most formats will end up using the x264 encoder or something - cvarfuncs->SetString(ENCODERNAME"_format_force", ""); - cvarfuncs->SetString(ENCODERNAME"_videocodec", ""); - cvarfuncs->SetString(ENCODERNAME"_videobitrate", ""); - cvarfuncs->SetString(ENCODERNAME"_videoforcewidth", ""); - cvarfuncs->SetString(ENCODERNAME"_videoforceheight", ""); - cvarfuncs->SetString(ENCODERNAME"_videopreset", "veryfast"); - cvarfuncs->SetString(ENCODERNAME"_video_crf", ""); - cvarfuncs->SetString(ENCODERNAME"_audiocodec", ""); - cvarfuncs->SetString(ENCODERNAME"_audiobitrate", ""); + cvarfuncs->SetString("capturedriver", ENCODERNAME); + cvarfuncs->SetString("capturerate", "30"); + cvarfuncs->SetString("capturedemowidth", "0"); + cvarfuncs->SetString("capturedemoheight", "0"); + cvarfuncs->SetString("capturesound", "1"); + cvarfuncs->SetString("capturesoundchannels", "2"); + cvarfuncs->SetString("capturesoundbits", "16"); - cvarfuncs->SetString("capturedriver", ENCODERNAME); - cvarfuncs->SetString("capturerate", "30"); - cvarfuncs->SetString("capturedemowidth", "0"); - cvarfuncs->SetString("capturedemoheight", "0"); - cvarfuncs->SetString("capturesound", "1"); - cvarfuncs->SetString("capturesoundchannels", "2"); - cvarfuncs->SetString("capturesoundbits", "16"); - - Con_Printf(ENCODERNAME": capture settings reset to "ENCODERNAME" defaults\n"); - Con_Printf(ENCODERNAME": Note that some codecs may have restrictions on video sizes\n"); - } - return false; + Con_Printf(ENCODERNAME": capture settings reset to "ENCODERNAME" defaults\n"); + Con_Printf(ENCODERNAME": Note that some codecs may have restrictions on video sizes\n"); } @@ -864,12 +841,10 @@ qboolean AVEnc_Init(void) ffmpeg_audiocodec = cvarfuncs->GetNVFDG(ENCODERNAME"_audiocodec", "", 0, "Forces which audio encoder to use. If blank, guesses based upon container defaults.", ENCODERNAME); ffmpeg_audiobitrate = cvarfuncs->GetNVFDG(ENCODERNAME"_audiobitrate", "", 0, "Specifies the target audio bitrate", ENCODERNAME); - if (plugfuncs->ExportFunction("ExecuteCommand", AVEnc_ExecuteCommand)) - { -// cmdfuncs->AddCommand(ENCODERNAME"_configure"); - cmdfuncs->AddCommand(ENCODERNAME"_nvidia"); - cmdfuncs->AddCommand(ENCODERNAME"_defaults"); - } +// cmdfuncs->AddCommand(ENCODERNAME"_configure", AVEnc_LoadPreset_f); + cmdfuncs->AddCommand(ENCODERNAME"_nvidia", AVEnc_Preset_Nvidia_f, "Attempts to reconfigure video capture to use nvidia's hardware encoder."); + cmdfuncs->AddCommand(ENCODERNAME"_defaults", AVEnc_Preset_Defaults_f, "Reconfigures video capture to the "ENCODERNAME" plugin's default settings."); + //cmdfuncs->AddCommand(ENCODERNAME"_twitch", AVEnc_Preset_Twitch_f, "Reconfigures video capture to stream to twitch."); return true; } diff --git a/plugins/cef/cef.c b/plugins/cef/cef.c index 68077237..920f0dce 100644 --- a/plugins/cef/cef.c +++ b/plugins/cef/cef.c @@ -2174,38 +2174,31 @@ int NATIVEEXPORT CefSubprocessInit(plugcorefuncs_t *corefuncs) return Cef_Init(false); } -static qintptr_t Cef_ExecuteCommand(qintptr_t *args) +void Cef_ExecuteCommand(void) { - char cmd[256]; - cmdfuncs->Argv(0, cmd, sizeof(cmd)); - if (!strcmp(cmd, "cef")) + if (confuncs && Cef_Init(true)) { - if (confuncs && Cef_Init(true)) - { - static int sequence; - char f[128]; - char videomap[8192]; - Q_snprintf(f, sizeof(f), "libcef:%i", ++sequence); - newconsole = f; - strcpy(videomap, "cef:"); - cmdfuncs->Argv(1, videomap+4, sizeof(videomap)-4); - if (!videomap[4]) - strcpy(videomap, "cef:http://fte.triptohell.info"); - - confuncs->SetConsoleString(f, "title", videomap+4); - confuncs->SetConsoleFloat(f, "iswindow", true); - confuncs->SetConsoleFloat(f, "forceutf8", true); - confuncs->SetConsoleFloat(f, "wnd_w", 640+16); - confuncs->SetConsoleFloat(f, "wnd_h", 480+16+8); - confuncs->SetConsoleString(f, "backvideomap", videomap); - confuncs->SetConsoleFloat(f, "linebuffered", 2); - confuncs->SetActive(f); + static int sequence; + char f[128]; + char videomap[8192]; + Q_snprintf(f, sizeof(f), "libcef:%i", ++sequence); + newconsole = f; + strcpy(videomap, "cef:"); + cmdfuncs->Argv(1, videomap+4, sizeof(videomap)-4); + if (!videomap[4]) + strcpy(videomap, "cef:http://fte.triptohell.info"); - newconsole = NULL; - } - return true; + confuncs->SetConsoleString(f, "title", videomap+4); + confuncs->SetConsoleFloat(f, "iswindow", true); + confuncs->SetConsoleFloat(f, "forceutf8", true); + confuncs->SetConsoleFloat(f, "wnd_w", 640+16); + confuncs->SetConsoleFloat(f, "wnd_h", 480+16+8); + confuncs->SetConsoleString(f, "backvideomap", videomap); + confuncs->SetConsoleFloat(f, "linebuffered", 2); + confuncs->SetActive(f); + + newconsole = NULL; } - return false; } static qboolean QDECL Cef_PluginMayUnload(void) @@ -2249,8 +2242,7 @@ qboolean Plug_Init(void) return false; } - if (plugfuncs->ExportFunction("ExecuteCommand", Cef_ExecuteCommand)) - cmdfuncs->AddCommand("cef"); + cmdfuncs->AddCommand("cef", Cef_ExecuteCommand, "Open a web page!"); cef_incognito = cvarfuncs->GetNVFDG("cef_incognito", "0", 0, NULL, "browser settings"); cef_allowplugins = cvarfuncs->GetNVFDG("cef_allowplugins", "0", 0, NULL, "browser settings"); diff --git a/plugins/ezhud/ezquakeisms.c b/plugins/ezhud/ezquakeisms.c index 58a6fec5..b7f296fb 100644 --- a/plugins/ezhud/ezquakeisms.c +++ b/plugins/ezhud/ezquakeisms.c @@ -224,11 +224,13 @@ mpic_t *Draw_CachePicSafe(const char *name, qbool crash, qbool ignorewad) { if (!*name) return NULL; - return (mpic_t*)(qintptr_t)drawfuncs->LoadImage(name, false); + return (mpic_t*)(qintptr_t)drawfuncs->LoadImage(name); } mpic_t *Draw_CacheWadPic(const char *name) { - return (mpic_t*)(qintptr_t)drawfuncs->LoadImage(name, true); + char ftename[MAX_QPATH]; + Q_snprintf(ftename, sizeof(ftename), "gfx/%s.lmp", name); + return (mpic_t*)(qintptr_t)drawfuncs->LoadImage(ftename); } mpic_t *SCR_LoadCursorImage(char *cursorimage) @@ -506,40 +508,10 @@ void EZHud_UseNquake_f(void) cmdfuncs->AddText(hudstr, true); } -static struct -{ - xcommand_t cmd; - const char *name; -} concmds[128]; -static int numconcmds; qboolean Cmd_AddCommand (const char *funcname, xcommand_t function) { - if (numconcmds < sizeof(concmds)/sizeof(concmds[0])) - { - concmds[numconcmds].cmd = function; - concmds[numconcmds].name = funcname; - numconcmds++; - cmdfuncs->AddCommand(funcname); - return true; - } - Con_Printf("ezhud: too many console commands\n"); - return false; + return cmdfuncs->AddCommand(funcname, function, NULL); }; -static qboolean QDECL EZHud_ExecuteCommand(qboolean isinsecure) -{ - char buffer[128]; - int i; - cmdfuncs->Argv(0, buffer, sizeof(buffer)); - for (i = 0; i < numconcmds; i++) - { - if (!strcmp(buffer, concmds[i].name)) - { - concmds[i].cmd(); - return 1; - } - } - return 0; -} int IN_BestWeapon(void) { @@ -743,8 +715,7 @@ qboolean Plug_Init(void) if (cvarfuncs && drawfuncs && clientfuncs && filefuncs && inputfuncs && plugfuncs->ExportFunction("SbarBase", EZHud_Draw) && plugfuncs->ExportFunction("MenuEvent", EZHud_MenuEvent) && - plugfuncs->ExportFunction("Tick", EZHud_Tick) && - plugfuncs->ExportFunction("ExecuteCommand", EZHud_ExecuteCommand)) + plugfuncs->ExportFunction("Tick", EZHud_Tick)) { Cmd_AddCommand("ezhud_nquake", EZHud_UseNquake_f); HUD_Init(); diff --git a/plugins/irc/ircclient.c b/plugins/irc/ircclient.c index c475cea6..597e0ac2 100644 --- a/plugins/irc/ircclient.c +++ b/plugins/irc/ircclient.c @@ -29,31 +29,16 @@ enum tlsmode_e TLS_STARTING //don't send any nick/user/pass info while this is set }; -#define irccvars "IRC Console Variables" -static vmcvar_t irc_debug = {"irc_debug", "0", irccvars, 0}; -static vmcvar_t irc_motd = {"irc_motd", "0", irccvars, 0}; -static vmcvar_t irc_nick = {"irc_nick", "", irccvars, 0}; -static vmcvar_t irc_altnick = {"irc_altnick", "", irccvars, 0}; -static vmcvar_t irc_realname = {"irc_realname", "FTE IRC-Plugin", irccvars, 0}; -static vmcvar_t irc_hostname = {"irc_hostname", "localhost", irccvars, 0}; -static vmcvar_t irc_username = {"irc_username", "FTE", irccvars, 0}; -static vmcvar_t irc_timestamp = {"irc_timestamp", "0", irccvars, 0}; -static vmcvar_t irc_quitmessage = {"irc_quitmessage", "", irccvars, 0}; -static vmcvar_t irc_config = {"irc_config", "1", irccvars, 0}; -#undef irccvars - -static vmcvar_t *cvarlist[] ={ - &irc_debug, - &irc_motd, - &irc_nick, - &irc_altnick, - &irc_realname, - &irc_hostname, - &irc_username, - &irc_timestamp, - &irc_quitmessage, - NULL -}; +static cvar_t *irc_debug;// = {"irc_debug", "0", irccvars, 0}; +static cvar_t *irc_motd;// = {"irc_motd", "0", irccvars, 0}; +static cvar_t *irc_nick;// = {"irc_nick", "", irccvars, 0}; +static cvar_t *irc_altnick;// = {"irc_altnick", "", irccvars, 0}; +static cvar_t *irc_realname;// = {"irc_realname", "FTE IRC-Plugin", irccvars, 0}; +static cvar_t *irc_hostname;// = {"irc_hostname", "localhost", irccvars, 0}; +static cvar_t *irc_username;// = {"irc_username", "FTE", irccvars, 0}; +static cvar_t *irc_timestamp;// = {"irc_timestamp", "0", irccvars, 0}; +static cvar_t *irc_quitmessage;// = {"irc_quitmessage", "", irccvars, 0}; +static cvar_t *irc_config;// = {"irc_config", "1", irccvars, 0}; static icefuncs_t *piceapi; static int next_window_x; @@ -378,29 +363,21 @@ static void IRC_Printf(ircclient_t *irc, const char *subname, const char *format static void IRC_InitCvars(void) { - vmcvar_t *v; - int i; - for (i=0; cvarlist[i]; i++) - { - v = cvarlist[i]; - v->handle = cvarfuncs->Register(v->name, v->string, v->flags, v->group); - } -} - -static int IRC_CvarUpdate(void) // perhaps void instead? -{ - vmcvar_t *v; - int i; - for (i=0; cvarlist[i]; i++) - { - v = cvarlist[i]; - cvarfuncs->Update(v->handle, &v->modificationcount, v->string, sizeof(v->string), &v->value); - } - return 0; + const char *cvargroup = "IRC Console Variables"; + irc_debug = cvarfuncs->GetNVFDG("irc_debug", "0", 0, NULL, cvargroup); + irc_motd = cvarfuncs->GetNVFDG("irc_motd", "0", 0, NULL, cvargroup); + irc_nick = cvarfuncs->GetNVFDG("irc_nick", "", 0, NULL, cvargroup); + irc_altnick = cvarfuncs->GetNVFDG("irc_altnick", "", 0, NULL, cvargroup); + irc_realname = cvarfuncs->GetNVFDG("irc_realname", "FTE IRC-Plugin", 0, NULL, cvargroup); + irc_hostname = cvarfuncs->GetNVFDG("irc_hostname", "localhost", 0, NULL, cvargroup); + irc_username = cvarfuncs->GetNVFDG("irc_username", "FTE", 0, NULL, cvargroup); + irc_timestamp = cvarfuncs->GetNVFDG("irc_timestamp", "0", 0, NULL, cvargroup); + irc_quitmessage = cvarfuncs->GetNVFDG("irc_quitmessage", "", 0, NULL, cvargroup); + irc_config = cvarfuncs->GetNVFDG("irc_config", "1", 0, NULL, cvargroup); } void IRC_Command(ircclient_t *ircclient, char *dest, char *args); -qboolean IRC_ExecuteCommand(qboolean isinsecure); +void IRC_ExecuteCommand_f(void); int IRC_ConExecuteCommand(qboolean isinsecure); void IRC_Frame(double realtime, double gametime); qboolean IRC_ConsoleLink(void); @@ -416,10 +393,9 @@ qboolean Plug_Init(void) if (netfuncs && filefuncs && - plugfuncs->ExportFunction("Tick", IRC_Frame) && - plugfuncs->ExportFunction("ExecuteCommand", IRC_ExecuteCommand)) + plugfuncs->ExportFunction("Tick", IRC_Frame)) { - cmdfuncs->AddCommand(COMMANDNAME); + cmdfuncs->AddCommand(COMMANDNAME, IRC_ExecuteCommand_f, "Internet Relay Chat client, use ^[/"COMMANDNAME" /help^] for help"); plugfuncs->ExportFunction("ConsoleLink", IRC_ConsoleLink); if (!confuncs || !plugfuncs->ExportFunction("ConExecuteCommand", IRC_ConExecuteCommand)) @@ -441,20 +417,13 @@ qboolean Plug_Init(void) -qboolean IRC_ExecuteCommand(qboolean isinsecure) +void IRC_ExecuteCommand_f(void) { - char cmd[256]; - cmdfuncs->Argv(0, cmd, sizeof(cmd)); - if (!strcmp(cmd, COMMANDNAME)) - { - ircclient_t *ircclient = ircclients; - char imsg[8192]; - cmdfuncs->Args(imsg, sizeof(imsg)); - //FIXME: select an irc network more inteligently - IRC_Command(ircclient, ircclient?ircclient->defaultdest:"", imsg); - return true; - } - return false; + ircclient_t *ircclient = ircclients; + char imsg[8192]; + cmdfuncs->Args(imsg, sizeof(imsg)); + //FIXME: select an irc network more inteligently + IRC_Command(ircclient, ircclient?ircclient->defaultdest:"", imsg); } int IRC_ConExecuteCommand(qboolean isinsecure) { @@ -500,7 +469,7 @@ static void IRC_AddClientMessage(ircclient_t *irc, char *msg) memcpy(irc->bufferedoutmessage + irc->bufferedoutammount, output, len); irc->bufferedoutammount += len; - if (irc_debug.value == 1) { IRC_Printf(irc, DEFAULTCONSOLE,COLOURYELLOW "<< %s \n",msg); } + if (irc_debug->value == 1) { IRC_Printf(irc, DEFAULTCONSOLE,COLOURYELLOW "<< %s \n",msg); } } static ircclient_t *IRC_FindAccount(const char *server) @@ -534,8 +503,6 @@ static ircclient_t *IRC_Create(const char *server, const char *nick, const char Q_strlcpy(irc->server, server, sizeof(irc->server)); - IRC_CvarUpdate(); - Q_strlcpy(irc->primarynick, nick, sizeof(irc->primarynick)); Q_strlcpy(irc->nick, nick, sizeof(irc->nick)); Q_strlcpy(irc->realname, realname, sizeof(irc->realname)); @@ -570,8 +537,6 @@ static void IRC_SetNick(ircclient_t *irc, char *nick) } static void IRC_SetUser(ircclient_t *irc, char *user) { - IRC_CvarUpdate(); - if (irc->tlsmode != TLS_STARTING) { const char *username = irc->username; @@ -632,7 +597,7 @@ static qboolean IRC_Establish(ircclient_t *irc) irc->nicktries = 0; IRC_SetPass(irc, irc->pwd); IRC_SetNick(irc, irc->nick); - IRC_SetUser(irc, irc_username.string); + IRC_SetUser(irc, irc_username->string); } return true; @@ -692,7 +657,7 @@ static void IRC_WriteConfig(void) { qhandle_t config; - if (irc_config.value == 0) + if (irc_config->value == 0) return; filefuncs->Open("**plugconfig", &config, 2); @@ -981,8 +946,6 @@ static void IRC_TryNewNick(ircclient_t *irc, char *nickname) { char *seedednick; - IRC_CvarUpdate(); - if (irc->tlsmode == TLS_STARTING) { //don't submit any of this info here. @@ -1002,18 +965,18 @@ static void IRC_TryNewNick(ircclient_t *irc, char *nickname) if (irc->nicktries == 1) { irc->nicktries++; - if (*irc_nick.string && strcmp(nickname, irc_nick.string)) + if (*irc_nick->string && strcmp(nickname, irc_nick->string)) { - IRC_SetNick(irc, irc_nick.string); + IRC_SetNick(irc, irc_nick->string); return; } } if (irc->nicktries == 2) { irc->nicktries++; - if (*irc_altnick.string && strcmp(nickname, irc_altnick.string)) + if (*irc_altnick->string && strcmp(nickname, irc_altnick->string)) { - IRC_SetNick(irc, irc_altnick.string); + IRC_SetNick(irc, irc_altnick->string); return; } } @@ -1028,10 +991,10 @@ static void IRC_TryNewNick(ircclient_t *irc, char *nickname) //IRC_Printf(irc, DEFAULTCONSOLE, COLOURRED "ERROR: primary nickname in use. Attempting random nickname.\n"); if (*irc->primarynick && irc->nicktries < 7) seedednick = va("%.6s%i", irc->primarynick, rand()); - else if (*irc_nick.string && irc->nicktries < 8) - seedednick = va("%.6s%i", irc_nick.string, rand()); - else if (*irc_altnick.string && irc->nicktries < 9) - seedednick = va("%.6s%i", irc_altnick.string, rand()); + else if (*irc_nick->string && irc->nicktries < 8) + seedednick = va("%.6s%i", irc_nick->string, rand()); + else if (*irc_altnick->string && irc->nicktries < 9) + seedednick = va("%.6s%i", irc_altnick->string, rand()); else seedednick = va("%.6s%i", "FTE", rand()); seedednick[9] = 0; //'Each client is distinguished from other clients by a unique nickname having a maximum length of nine (9) characters' @@ -1057,7 +1020,7 @@ static void numbered_command(int comm, char *msg, ircclient_t *irc) // move vars if (irc->tlsmode != TLS_STARTING) irc->connecting = 0; // ok we are connected - if (irc_motd.value) + if (irc_motd->value) IRC_Printf(irc, DEFAULTCONSOLE, COLOURYELLOW "SERVER STATS: %s\n",casevar[3]); return; } @@ -1068,13 +1031,13 @@ static void numbered_command(int comm, char *msg, ircclient_t *irc) // move vars // } case 20: /* RPL_HELLO */ { - if (irc_motd.value) + if (irc_motd->value) IRC_Printf(irc, DEFAULTCONSOLE, COLOURYELLOW "%s\n",casevar[3]); return; } case 42: /*RPL_YOURID */ { - if (irc_motd.value) + if (irc_motd->value) IRC_Printf(irc, DEFAULTCONSOLE, COLOURYELLOW "%s\n",casevar[3]); return; } @@ -1091,7 +1054,7 @@ static void numbered_command(int comm, char *msg, ircclient_t *irc) // move vars case 265: case 266: { - if (irc_motd.value) + if (irc_motd->value) IRC_Printf(irc, DEFAULTCONSOLE, COLOURYELLOW "SERVER STATS: %s\n",casevar[3]); return; } @@ -1211,11 +1174,9 @@ static void numbered_command(int comm, char *msg, ircclient_t *irc) // move vars { char *motdmessage = casevar[3]+1; - IRC_CvarUpdate(); - - if (irc_motd.value == 2) + if (irc_motd->value == 2) IRC_Printf(irc, DEFAULTCONSOLE, "MOTD: %s\n", motdmessage); - else if (irc_motd.value) + else if (irc_motd->value) IRC_Printf(irc, DEFAULTCONSOLE, "%s\n", motdmessage); if (*irc->autochannels) @@ -1318,7 +1279,7 @@ static void numbered_command(int comm, char *msg, ircclient_t *irc) // move vars irc->nicktries = 0; IRC_SetPass(irc, irc->pwd); IRC_SetNick(irc, irc->nick); - IRC_SetUser(irc, irc_username.string); + IRC_SetUser(irc, irc_username->string); return; } case 691: /* ERR_STARTTLS */ @@ -1937,10 +1898,8 @@ static int IRC_ClientFrame(ircclient_t *irc) } - IRC_CvarUpdate(); // is this the right place for it? - -// 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]); } +// 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]); } if (*msg == ':') //we need to strip off the prefix { @@ -2005,7 +1964,7 @@ static int IRC_ClientFrame(ircclient_t *irc) to++; for (end = to + strlen(to)-1; end >= to && *end <= ' '; end--) *end = '\0'; - if (!strcmp(to, irc_nick.string)) + if (!strcmp(to, irc_nick->string)) to = prefix; //This was directed straight at us. //So change the 'to', to the 'from'. @@ -2258,7 +2217,7 @@ static int IRC_ClientFrame(ircclient_t *irc) else if (!strncmp(msg, "372 ", 4)) { char *text = strstr(msg, ":-"); - if (!*irc->autochannels || irc_motd.value) + if (!*irc->autochannels || irc_motd->value) { if (text) IRC_Printf(irc, DEFAULTCONSOLE, "%s\n", text+2); @@ -2395,9 +2354,7 @@ static int IRC_ClientFrame(ircclient_t *irc) numbered_command(atoi(var[2]), msg, irc); - IRC_CvarUpdate(); - - if (irc_debug.value == 1) { IRC_Printf(irc, DEFAULTCONSOLE, "%s\n", msg); } + if (irc_debug->value == 1) { IRC_Printf(irc, DEFAULTCONSOLE, "%s\n", msg); } } else IRC_Printf(irc, DEFAULTCONSOLE, "%s\n", msg); @@ -2488,7 +2445,7 @@ void IRC_Command(ircclient_t *ircclient, char *dest, char *args) //set up some defaults if (!*nick) - Q_strlcpy(nick, irc_nick.string, sizeof(nick)); + Q_strlcpy(nick, irc_nick->string, sizeof(nick)); if (!*nick) cvarfuncs->GetString("name", nick, sizeof(nick)); @@ -2502,7 +2459,7 @@ void IRC_Command(ircclient_t *ircclient, char *dest, char *args) } } else - ircclient = IRC_Create(server, nick, irc_realname.string, irc_hostname.string, irc_username.string, password, channels); + ircclient = IRC_Create(server, nick, irc_realname->string, irc_hostname->string, irc_username->string, password, channels); if (ircclient) { IRC_MakeDefault(ircclient); @@ -2529,7 +2486,7 @@ void IRC_Command(ircclient_t *ircclient, char *dest, char *args) { msg = COM_Parse(msg, token, sizeof(token)); if (!ircclient) //not yet connected. - cvarfuncs->SetString(irc_nick.name, token); + cvarfuncs->SetString(irc_nick->name, token); else { if (!handleisvalid(ircclient->socket)) @@ -2543,7 +2500,7 @@ void IRC_Command(ircclient_t *ircclient, char *dest, char *args) else if (!strcmp(token+1, "user")) { msg = COM_Parse(msg, token, sizeof(token)); - cvarfuncs->SetString(irc_username.name, token); + cvarfuncs->SetString(irc_username->name, token); if (ircclient) IRC_SetUser(ircclient, token); @@ -2723,7 +2680,7 @@ void IRC_Command(ircclient_t *ircclient, char *dest, char *args) if (*token) IRC_AddClientMessage(ircclient, va("QUIT :%s", token)); else - IRC_AddClientMessage(ircclient, va("QUIT :%s", irc_quitmessage.string)); + IRC_AddClientMessage(ircclient, va("QUIT :%s", irc_quitmessage->string)); ircclient->quitting = true; IRC_WriteConfig(); diff --git a/plugins/jabber/jabberclient.c b/plugins/jabber/jabberclient.c index 58c959fa..1aebbbb1 100644 --- a/plugins/jabber/jabberclient.c +++ b/plugins/jabber/jabberclient.c @@ -867,23 +867,21 @@ static struct { {NULL} }; -qboolean JCL_ExecuteCommand(qboolean isinsecure) +static void JCL_ExecuteCommand_f(void) { + qboolean isinsecure = cmdfuncs->IsInsecure(); char cmd[256]; cmdfuncs->Argv(0, cmd, sizeof(cmd)); if (!strcmp(cmd, COMMANDPREFIX) || !strcmp(cmd, COMMANDPREFIX2) || !strcmp(cmd, COMMANDPREFIX3)) { if (!isinsecure || cmdfuncs->Argc() == 1) JCL_Command(0, ""); - return true; } - if (!strncmp(cmd, COMMANDPREFIX, strlen(COMMANDPREFIX))) + else if (!strncmp(cmd, COMMANDPREFIX, strlen(COMMANDPREFIX))) { if (!isinsecure || cmdfuncs->Argc() == 1) JCL_Command(atoi(cmd+strlen(COMMANDPREFIX)), ""); - return true; } - return false; } qboolean JCL_ConsoleLink(void); @@ -903,6 +901,7 @@ static void QDECL JCL_UpdateVideo(int width, int height) qboolean Plug_Init(void) { + const char *cmddesc = "XMPP client - ^[/"COMMANDPREFIX" /help^] for help."; jclient_needreadconfig = true; confuncs = (plugsubconsolefuncs_t*)plugfuncs->GetEngineInterface(plugsubconsolefuncs_name, sizeof(*confuncs)); @@ -913,8 +912,7 @@ qboolean Plug_Init(void) if (netfuncs && filefuncs && plugfuncs->ExportFunction("Tick", JCL_Frame) && - plugfuncs->ExportFunction("Shutdown", JCL_Shutdown) && - plugfuncs->ExportFunction("ExecuteCommand", JCL_ExecuteCommand)) + plugfuncs->ExportFunction("Shutdown", JCL_Shutdown)) { Con_Printf("XMPP Plugin Loaded. For help, use: ^[/"COMMANDPREFIX" /help^]\n"); @@ -931,26 +929,26 @@ qboolean Plug_Init(void) else Con_TrySubPrint = confuncs->SubPrint; - cmdfuncs->AddCommand(COMMANDPREFIX); - cmdfuncs->AddCommand(COMMANDPREFIX2); - cmdfuncs->AddCommand(COMMANDPREFIX3); + cmdfuncs->AddCommand(COMMANDPREFIX, JCL_ExecuteCommand_f, cmddesc); + cmdfuncs->AddCommand(COMMANDPREFIX2, JCL_ExecuteCommand_f, cmddesc); + cmdfuncs->AddCommand(COMMANDPREFIX3, JCL_ExecuteCommand_f, cmddesc); - cmdfuncs->AddCommand(COMMANDPREFIX"0"); - cmdfuncs->AddCommand(COMMANDPREFIX"1"); - cmdfuncs->AddCommand(COMMANDPREFIX"2"); - cmdfuncs->AddCommand(COMMANDPREFIX"3"); - cmdfuncs->AddCommand(COMMANDPREFIX"4"); - cmdfuncs->AddCommand(COMMANDPREFIX"5"); - cmdfuncs->AddCommand(COMMANDPREFIX"6"); - cmdfuncs->AddCommand(COMMANDPREFIX"7"); + cmdfuncs->AddCommand(COMMANDPREFIX"0", JCL_ExecuteCommand_f, cmddesc); + cmdfuncs->AddCommand(COMMANDPREFIX"1", JCL_ExecuteCommand_f, cmddesc); + cmdfuncs->AddCommand(COMMANDPREFIX"2", JCL_ExecuteCommand_f, cmddesc); + cmdfuncs->AddCommand(COMMANDPREFIX"3", JCL_ExecuteCommand_f, cmddesc); + cmdfuncs->AddCommand(COMMANDPREFIX"4", JCL_ExecuteCommand_f, cmddesc); + cmdfuncs->AddCommand(COMMANDPREFIX"5", JCL_ExecuteCommand_f, cmddesc); + cmdfuncs->AddCommand(COMMANDPREFIX"6", JCL_ExecuteCommand_f, cmddesc); + cmdfuncs->AddCommand(COMMANDPREFIX"7", JCL_ExecuteCommand_f, cmddesc); //flags&1 == archive - cvarfuncs->Register("xmpp_nostatus", "0", 0, "xmpp"); - cvarfuncs->Register("xmpp_showstatusupdates", "0", 0, "xmpp"); - cvarfuncs->Register("xmpp_autoacceptjoins", "0", 0, "xmpp"); - cvarfuncs->Register("xmpp_autoacceptinvites", "0", 0, "xmpp"); - cvarfuncs->Register("xmpp_autoacceptvoice", "0", 0, "xmpp"); - cvarfuncs->Register("xmpp_debug", "0", 0, "xmpp"); + cvarfuncs->GetNVFDG("xmpp_nostatus", "0", 0, NULL, "xmpp"); + cvarfuncs->GetNVFDG("xmpp_showstatusupdates", "0", 0, NULL, "xmpp"); + cvarfuncs->GetNVFDG("xmpp_autoacceptjoins", "0", 0, NULL, "xmpp"); + cvarfuncs->GetNVFDG("xmpp_autoacceptinvites", "0", 0, NULL, "xmpp"); + cvarfuncs->GetNVFDG("xmpp_autoacceptvoice", "0", 0, NULL, "xmpp"); + cvarfuncs->GetNVFDG("xmpp_debug", "0", 0, NULL, "xmpp"); #ifdef JINGLE piceapi = plugfuncs->GetEngineInterface(ICE_API_CURRENT, sizeof(*piceapi)); diff --git a/plugins/models/models.c b/plugins/models/models.c index cea3d847..8cc72736 100644 --- a/plugins/models/models.c +++ b/plugins/models/models.c @@ -818,28 +818,22 @@ extern qboolean QDECL Mod_LoadGLTFModel (struct model_s *mod, void *buffer, size extern qboolean QDECL Mod_LoadGLBModel (struct model_s *mod, void *buffer, size_t fsize); extern void Mod_ExportIQM(char *fname, int flags, galiasinfo_t *mesh); -qboolean Mod_ExecuteCommand(qboolean isinsecure) +#if !defined(SERVERONLY) && defined(SKELETALMODELS) +static void Mod_ExportIQM_f(void) { char tok[128]; - cmdfuncs->Argv(0, tok, sizeof(tok)); -#if !defined(SERVERONLY) && defined(SKELETALMODELS) - if (!strcmp(tok, "exportiqm")) + model_t *mod; + cmdfuncs->Argv(1, tok, sizeof(tok)); + mod = modfuncs->GetModel(tok, MLV_WARNSYNC); + if (!mod || mod->type != mod_alias || !mod->meshinfo) + Con_Printf("Couldn't load \"%s\"\n", tok); + else { - model_t *mod; - cmdfuncs->Argv(1, tok, sizeof(tok)); - mod = modfuncs->GetModel(tok, MLV_WARNSYNC); - if (!mod || mod->type != mod_alias || !mod->meshinfo) - Con_Printf("Couldn't load \"%s\"\n", tok); - else - { - cmdfuncs->Argv(2, tok, sizeof(tok)); - Mod_ExportIQM(tok, mod->flags, mod->meshinfo); - } - return true; + cmdfuncs->Argv(2, tok, sizeof(tok)); + Mod_ExportIQM(tok, mod->flags, mod->meshinfo); } -#endif - return false; } +#endif qboolean Plug_Init(void) { @@ -860,8 +854,9 @@ qboolean Plug_Init(void) Plug_GLTF_Init(); #endif - plugfuncs->ExportFunction("ExecuteCommand", Mod_ExecuteCommand); - cmdfuncs->AddCommand("exportiqm"); +#if !defined(SERVERONLY) && defined(SKELETALMODELS) + cmdfuncs->AddCommand("exportiqm", Mod_ExportIQM_f, NULL); +#endif return true; } return false; diff --git a/plugins/namemaker/namemaker.c b/plugins/namemaker/namemaker.c index f48dc06e..eac40639 100644 --- a/plugins/namemaker/namemaker.c +++ b/plugins/namemaker/namemaker.c @@ -37,10 +37,10 @@ static void LoadPics(void) char buffer[256]; //main bar (add cvars later) - con_chars = drawfuncs->LoadImage("gfx/conchars.lmp", false); + con_chars = drawfuncs->LoadImage("gfx/conchars.lmp"); cvarfuncs->GetString("cl_cursor", buffer, sizeof(buffer)); if (*buffer) - pic_cursor = drawfuncs->LoadImage(buffer, false); + pic_cursor = drawfuncs->LoadImage(buffer); else pic_cursor = 0; } @@ -171,18 +171,11 @@ static qboolean QDECL Plug_MenuEvent(int eventtype, int param, int unicode, floa return 0; } -static qboolean Plug_ExecuteCommand(qboolean isinsecure) +static void Plug_NameMaker_f(void) { - char cmd[256]; - cmdfuncs->Argv(0, cmd, sizeof(cmd)); - if (!strcmp("namemaker", cmd)) - { - inputfuncs->SetMenuFocus(true, NULL, 0, 0, 0); //grab input focus - cvarfuncs->GetString("name", (char*)namebuffer, sizeof(namebuffer)); - insertpos = strlen(namebuffer); - return 1; - } - return 0; + inputfuncs->SetMenuFocus(true, NULL, 0, 0, 0); //grab input focus + cvarfuncs->GetString("name", (char*)namebuffer, sizeof(namebuffer)); + insertpos = strlen(namebuffer); } qboolean Plug_Init(void) @@ -192,7 +185,6 @@ qboolean Plug_Init(void) if (drawfuncs && inputfuncs && // plugfuncs->ExportFunction("SbarBase", UI_StatusBar) && // plugfuncs->ExportFunction("SbarOverlay", UI_ScoreBoard) && - plugfuncs->ExportFunction("ExecuteCommand", Plug_ExecuteCommand) && plugfuncs->ExportFunction("MenuEvent", Plug_MenuEvent)) { @@ -213,7 +205,7 @@ qboolean Plug_Init(void) K_PAGEDOWN = inputfuncs->GetKeyCode("pgdn", NULL); K_BACKSPACE = inputfuncs->GetKeyCode("backspace", NULL); - cmdfuncs->AddCommand("namemaker"); + cmdfuncs->AddCommand("namemaker", Plug_NameMaker_f, "Provides a simple way to select from quake's glyphs."); LoadPics(); diff --git a/plugins/openxr.c b/plugins/openxr.c index af3ac4e8..71a7ba56 100644 --- a/plugins/openxr.c +++ b/plugins/openxr.c @@ -886,7 +886,7 @@ static qboolean XR_Init(vrsetup_t *qreqs, rendererstate_t *info) return true; } -static qboolean XR_HapticCommand_f(qboolean isinsecure) +static void XR_HapticCommand_f(void) { size_t u; char actionname[XR_MAX_ACTION_NAME_SIZE]; @@ -910,10 +910,9 @@ static qboolean XR_HapticCommand_f(qboolean isinsecure) haptic.frequency = *actionname?atof(actionname):XR_FREQUENCY_UNSPECIFIED; xrApplyHapticFeedback(xr.session, &info, (XrHapticBaseHeader*)&haptic); } - return true; + break; } } - return false; } static XrAction XR_DefineAction(enum actset_e set, XrActionType type, const char *name, const char *description, const char *root) @@ -994,7 +993,7 @@ static XrAction XR_DefineAction(enum actset_e set, XrActionType type, const char Con_Printf("openxr: Unable to create action %s [%s] - %s\n", info.actionName, info.localizedActionName, XR_StringForResult(res)); if (info.actionType == XR_ACTION_TYPE_VIBRATION_OUTPUT) - cmdfuncs->AddCommand(xr.actions[u].actname); + cmdfuncs->AddCommand(xr.actions[u].actname, XR_HapticCommand_f, "Linked to an OpenXR haptic feedback."); return xr.actions[u].action; } @@ -2285,7 +2284,6 @@ qboolean Plug_Init(void) fsfuncs = plugfuncs->GetEngineInterface(plugfsfuncs_name, sizeof(*fsfuncs)); inputfuncs = plugfuncs->GetEngineInterface(pluginputfuncs_name, sizeof(*inputfuncs)); plugfuncs->ExportFunction("MayUnload", XR_PluginMayUnload); - plugfuncs->ExportFunction("ExecuteCommand", XR_HapticCommand_f); if (plugfuncs->ExportInterface(plugvrfuncs_name, &openxr, sizeof(openxr))) { xr_enable = cvarfuncs->GetNVFDG("xr_enable", "1", 0, "Controls whether to use openxr rendering or not.", "OpenXR configuration"); diff --git a/plugins/plugin.c b/plugins/plugin.c index 40650017..fa6f2137 100644 --- a/plugins/plugin.c +++ b/plugins/plugin.c @@ -255,6 +255,31 @@ void Sys_Errorf(const char *format, ...) plugfuncs->Error(string); } + +qboolean ZF_ReallocElements(void **ptr, size_t *elements, size_t newelements, size_t elementsize) +{ + void *n; + size_t oldsize; + size_t newsize; + + //protect against malicious overflows + if (newelements > SIZE_MAX / elementsize) + return false; + + oldsize = *elements * elementsize; + newsize = newelements * elementsize; + + n = plugfuncs->Realloc(*ptr, newsize); + if (!n) + return false; + if (newsize > oldsize) + memset((char*)n+oldsize, 0, newsize - oldsize); + *elements = newelements; + *ptr = n; + return true; +} + + #ifdef __cplusplus extern "C" #endif diff --git a/plugins/plugin.h b/plugins/plugin.h index 0343821e..95daedb4 100644 --- a/plugins/plugin.h +++ b/plugins/plugin.h @@ -15,10 +15,13 @@ #define false qfalse #define true qtrue #endif + typedef float vec4_t[4]; typedef float vec3_t[3]; + typedef float vec2_t[2]; typedef unsigned char qbyte; #include + #define qint64_t int64_t #define quint64_t uint64_t typedef quint64_t qofs_t; @@ -184,6 +187,7 @@ struct wstats_s; #define F(t, n, args) t (QDECL *n) args #define dllhandle_t void struct dllfunction_s; +struct zonegroup_s; typedef struct //core stuff { //Basic builtins: @@ -192,8 +196,12 @@ typedef struct //core stuff F(qboolean, ExportInterface, (const char *interfacename, void *interfaceptr, size_t structsize)); //export a named interface struct to the engine F(qboolean, GetPluginName, (int plugnum, char *buffer, size_t bufsize)); //query loaded plugin names. -1 == active plugin F(void, Print, (const char *message)); //print on (main) console. - F(void, Error, (const char *message)); //abort the entire engine. + F(void, Error, (const char *message, ...)); //abort the entire engine. + F(void, EndGame, (const char *reason, ...)); //some sort of networking problem happened and we need to disconnect. Engine can continue running (displaying the message to the user). F(quintptr_t,GetMilliseconds, (void)); + F(double, GetSeconds, (void)); + + //for soft linking (with more readable error messages). F(dllhandle_t*,LoadDLL, (const char *modulename, struct dllfunction_s *funcs)); F(void*, GetDLLSymbol, (dllhandle_t *handle, const char *symbolname)); F(void, CloseDLL, (dllhandle_t *handle)); //not guarenteed to actually do anything, of course. @@ -205,6 +213,7 @@ typedef struct //core stuff //for lazy mallocs F(void*, GMalloc, (struct zonegroup_s *ctx, size_t size)); + F(void, GFree, (struct zonegroup_s *ctx, void *ptr)); F(void, GFreeAll, (struct zonegroup_s *ctx)); #define plugcorefuncs_name "Core" } plugcorefuncs_t; @@ -233,12 +242,14 @@ typedef struct //console command/tokenizing/cbuf functions F(char *, ParsePunctuation, (const char *data, const char *punctuation, char *token, size_t tokenlen, enum com_tokentype_e *tokentype)); //use explicit punctuation. F(void, TokenizeString, (const char *msg)); //tokenize a string. + F(void, ShiftArgs, (int args)); //updates tokenize state to ignore arg 0 (and updates Args). F(void, Args, (char *buffer, int bufsize)); //Gets the extra args - F(void, Argv, (int argnum, char *buffer, size_t bufsize)); //Gets a 0-based token + F(char *, Argv, (int argnum, char *buffer, size_t bufsize)); //Gets a 0-based token F(int, Argc, (void)); //gets the number of tokens available. - F(qboolean, AddCommand, (const char *cmdname)); //Registers a console command. + F(qboolean, IsInsecure, (void)); + F(qboolean, AddCommand, (const char *cmdname, void (*func)(void), const char *desc)); //Registers a console command. F(void, AddText, (const char *text, qboolean insert)); #define plugcmdfuncs_name "Cmd" @@ -250,16 +261,24 @@ typedef struct //console command and cbuf functions F(void, SetFloat, (const char *name, float value)); F(qboolean, GetString, (const char *name, char *retstring, quintptr_t sizeofretstring)); F(float, GetFloat, (const char *name)); - F(qhandle_t,Register, (const char *name, const char *defaultval, int flags, const char *grouphint)); - F(qboolean, Update, (qhandle_t handle, int *modificationcount, char *outstringv, size_t stringsize, float *outfloatv)); //stringv is 256 chars long, don't expect this function to do anything if modification count is unchanged. F(cvar_t*, GetNVFDG, (const char *name, const char *defaultval, unsigned int flags, const char *description, const char *groupname)); + F(void, ForceSetString, (const char *name, const char *value)); #define plugcvarfuncs_name "Cvar" } plugcvarfuncs_t; typedef struct { - F(void, LocalSound, (const char *soundname, int channel, float volume)); - F(void, RawAudio, (int sourceid, void *data, int speed, int samples, int channels, int width, float volume)); + F(void, LocalSound, (const char *soundname, int channel, float volume)); + F(void, RawAudio, (int sourceid, void *data, int speed, int samples, int channels, int width, float volume)); + + F(void, Spacialize, (unsigned int seat, int entnum, vec3_t origin, vec3_t *axis, int reverb, vec3_t velocity)); + F(qboolean, UpdateReverb, (size_t slot, void *reverb, size_t reverbsize)); + F(struct sfx_s*,PrecacheSound, (const char *sample)); + F(void, StartSound, (int entnum, int entchannel, struct sfx_s *sfx, vec3_t origin, vec3_t velocity, float fvol, float attenuation, float timeofs, float pitchadj, unsigned int flags)); + F(float, GetChannelLevel, (int entnum, int entchannel)); + F(int, Voip_ClientLoudness,(unsigned int plno)); + F(qboolean, ChangeMusicTrack, (const char *initialtrack, const char *looptrack)); + #define plugaudiofuncs_name "Audio" } plugaudiofuncs_t; @@ -290,21 +309,33 @@ typedef struct //q1 client/network info F(int, GetWeaponStats, (int player, struct wstats_s *result, size_t maxresults)); F(float, GetTrackerOwnFrags, (int seat, char *text, size_t textsize)); F(void, GetPredInfo, (int seat, vec3_t outvel)); + + F(void, ClearClientState, (void)); //called at the start of map changes. + F(void, UpdateGameTime, (double)); //tells the client an updated snapshot time for interpolation/timedrift. #define plugclientfuncs_name "Client" } plugclientfuncs_t; +struct menu_s; typedef struct //for menu-like stuff { //for menus - F(qboolean, SetMenuFocus, (qboolean wantkeyfocus, const char *cursorname, float hot_x, float hot_y, float scale)); //null cursorname=relmouse, set/empty cursorname=absmouse - F(qboolean, HasMenuFocus, (void)); + F(qboolean, SetMenuFocus, (qboolean wantkeyfocus, const char *cursorname, float hot_x, float hot_y, float scale)); //null cursorname=relmouse, set/empty cursorname=absmouse + F(qboolean, HasMenuFocus, (void)); + + F(void, Menu_Push, (struct menu_s *menu, qboolean prompt)); + F(void, Menu_Unlink, (struct menu_s *menu, qboolean forced)); //for menu input - F(int, GetKeyCode, (const char *keyname, int *out_modifier)); - F(const char*,GetKeyName, (int keycode, int modifier)); - F(int, FindKeysForCommand,(int bindmap, const char *command, int *out_keycodes, int *out_modifiers, int maxkeys)); - F(const char*,GetKeyBind, (int bindmap, int keynum, int modifier)); - F(void, SetKeyBind, (int bindmap, int keycode, int modifier, const char *newbinding)); + F(int, GetKeyCode, (const char *keyname, int *out_modifier)); + F(const char*, GetKeyName, (int keycode, int modifier)); + F(int, FindKeysForCommand, (int bindmap, const char *command, int *out_keycodes, int *out_modifiers, int maxkeys)); + F(const char*, GetKeyBind, (int bindmap, int keynum, int modifier)); + F(void, SetKeyBind, (int bindmap, int keycode, int modifier, const char *newbinding)); + + F(qboolean, IsKeyDown, (int keycode)); + F(void, ClearKeyStates, (void)); //forget any keys that are still held. + F(unsigned int, GetMoveCount, (void)); + F(usercmd_t*, GetMoveEntry, (unsigned int move)); //GetMoveEntry(GetMoveCount()) gives you the partial entry. forgotten entries return NULL. unsigned int (*GetKeyDest) (void); void (*KeyEvent) (unsigned int devid, int down, int keycode, int unicode); @@ -316,14 +347,50 @@ typedef struct //for menu-like stuff #define pluginputfuncs_name "Input" } pluginputfuncs_t; +#if defined(FTEENGINE) || defined(FTEPLUGIN) +typedef struct +{ + F(void, BeginReading, (sizebuf_t *sb, struct netprim_s prim)); + F(int, ReadCount, (void)); + F(int, ReadBits, (int bits)); + F(int, ReadByte, (void)); + F(int, ReadShort, (void)); + F(int, ReadLong, (void)); + F(void, ReadData, (void *data, int len)); + F(char*, ReadString, (void)); + + F(void, BeginWriting, (sizebuf_t *sb, struct netprim_s prim, void *bufferstorage, size_t buffersize)); + F(void, WriteBits, (sizebuf_t *sb, int value, int bits)); + F(void, WriteByte, (sizebuf_t *sb, int c)); + F(void, WriteShort, (sizebuf_t *sb, int c)); + F(void, WriteLong, (sizebuf_t *sb, int c)); + F(void, WriteData, (sizebuf_t *sb, const void *data, int len)); + F(void, WriteString, (sizebuf_t *sb, const char *s)); + + F(qboolean, CompareAdr, (netadr_t *a, netadr_t *b)); + F(qboolean, CompareBaseAdr, (netadr_t *a, netadr_t *b)); + F(char*, AdrToString, (char *s, int len, netadr_t *a)); + F(size_t, StringToAdr, (const char *s, int defaultport, netadr_t *a, size_t addrcount, const char **pathstart)); + F(neterr_t, SendPacket, (struct ftenet_connections_s *col, int length, const void *data, netadr_t *to)); + + F(huffman_t*,Huff_CompressionCRC, (int crc)); + F(void, Huff_EncryptPacket, (sizebuf_t *msg, int offset)); + F(void, Huff_DecryptPacket, (sizebuf_t *msg, int offset)); +#define plugmsgfuncs_name "Messaging" +} plugmsgfuncs_t; +#endif + typedef struct //for huds and menus alike { + F(qboolean, GetVideoSize, (float *vsize, unsigned int *psize)); //returns false if there's no video yet... //note: these use handles instead of shaders, to make them persistent over renderer restarts. F(qhandle_t,LoadImageData, (const char *name, const char *mime, void *data, size_t datasize)); //load/replace a named texture F(qhandle_t,LoadImageShader,(const char *name, const char *defaultshader)); //loads a shader. - F(qhandle_t,LoadImage, (const char *name, qboolean iswadimage)); //wad image is ONLY for loading out of q1 gfx.wad. loads a shader. + F(qhandle_t,LoadImage, (const char *name)); //wad image is ONLY for loading out of q1 gfx.wad. loads a shader. use gfx/foo.lmp for hud stuff. + F(struct shader_s*,ShaderFromId, (qhandle_t shaderid)); F(void, UnloadImage, (qhandle_t image)); F(int, Image, (float x, float y, float w, float h, float s1, float t1, float s2, float t2, qhandle_t image)); + F(int, Image2dQuad, (const vec2_t *points, const vec2_t *tcoords, const vec4_t *colours, qhandle_t image)); F(int, ImageSize, (qhandle_t image, float *x, float *y)); F(void, Fill, (float x, float y, float w, float h)); F(void, Line, (float x1, float y1, float x2, float y2)); @@ -335,10 +402,95 @@ typedef struct //for huds and menus alike F(void, Colourpa, (int palcol, float a)); //for legacy code F(void, Colour4f, (float r, float g, float b, float a)); + F(void, RedrawScreen, (void)); //redraws the entire screen and presents it. for loading screen type things. + F(void, LocalSound, (const char *soundname, int channel, float volume)); #define plug2dfuncs_name "2D" } plug2dfuncs_t; +#if defined(FTEENGINE) || defined(FTEPLUGIN) +struct entity_s; +typedef struct +{ + struct + { + float x,y,w,h; + } rect; + vec2_t fov; + vec2_t fov_viewmodel; + vec3_t viewaxisorg[4]; + vec3_t skyroom_org; + float time; + unsigned int flags; +} plugrefdef_t; +typedef struct //for huds and menus alike +{ + F(model_t *, LoadModel, (const char *modelname, enum mlverbosity_e sync)); + F(qhandle_t, ModelToId, (model_t *model)); + F(model_t *, ModelFromId, (qhandle_t modelid)); + + F(void, RemapShader, (const char *sourcename, const char *destname, float timeoffset)); + F(qhandle_t, ShaderForSkin, (qhandle_t modelid, int surfaceidx, int skinnum, float time)); + F(skinid_t, RegisterSkinFile, (const char *skinname)); + F(skinfile_t *, LookupSkin, (skinid_t id)); + F(int, TagNumForName, (struct model_s *model, const char *name, int firsttag)); + F(qboolean, GetTag, (struct model_s *model, int tagnum, framestate_t *framestate, float *transforms)); + F(void, ClipDecal, (struct model_s *mod, vec3_t center, vec3_t normal, vec3_t tangent1, vec3_t tangent2, float size, unsigned int surfflagmask, unsigned int surflagmatch, void (*callback)(void *ctx, vec3_t *fte_restrict points, size_t numpoints, shader_t *shader), void *ctx)); + + F(void, NewMap, (model_t *worldmode)); + F(void, ClearScene, (void)); + F(void, AddEntity, (struct entity_s *ent)); + F(unsigned int, AddPolydata, (struct shader_s *s, unsigned int befflags, size_t numverts, size_t numidx, vecV_t **vertcoord, vec2_t **texcoord, vec4_t **colour, index_t **indexes)); //allocates space for some polygons + F(dlight_t *, NewDlight, (int key, const vec3_t origin, float radius, float time, float r, float g, float b)); + F(dlight_t *, AllocDlightOrg, (int keyidx, vec3_t keyorg)); + F(qboolean, CalcModelLighting, (entity_t *e, model_t *clmodel)); + F(void, RenderScene, (plugrefdef_t *viewer, size_t areabytes, const qbyte *areadata)); +#define plug3dfuncs_name "3D" +} plug3dfuncs_t; + +typedef struct //for collision stuff +{ + F(model_t *, LoadModel, (const char *modelname, enum mlverbosity_e sync)); + F(const char *, FixName, (const char *modname, const char *worldname)); + F(const char *, GetEntitiesString, (struct model_s *mod)); + + F(qboolean, TransformedTrace, (struct model_s *model, int hulloverride, framestate_t *framestate, vec3_t start, vec3_t end, vec3_t mins, vec3_t maxs, qboolean capsule, struct trace_s *trace, vec3_t origin, vec3_t angles, unsigned int hitcontentsmask)); + F(model_t *, TempBoxModel, (const vec3_t mins, const vec3_t maxs)); + + //general things that probably shouldn't be here... + F(size_t, IBufToInfo, (infobuf_t *info, char *infostring, size_t maxsize, const char **priority, const char **ignore, const char **exclusive, infosync_t *sync, void *synccontext)); + F(void, IBufFromInfo, (infobuf_t *info, const char *infostring, qboolean append)); + F(qboolean, SetIBufKey, (infobuf_t *info, const char *key, const char *val)); + F(char *, GetIBufKey, (infobuf_t *info, const char *key)); + F(char*, GetInfoKey, (const char *s, const char *key)); + F(void, SetInfoKey, (char *s, const char *key, const char *value, int maxsize)); + + //server things, shouldn't really be here but small. null in client-only builds + F(void, DropClient, (client_t *drop)); + F(void, ExtractFromUserinfo,(client_t *cl, qboolean verbose)); + F(qboolean, ChallengePasses, (int challenge)); +#define plugworldfuncs_name "World" +} plugworldfuncs_t; + +typedef struct //for querying master servers +{ + F(size_t, StringToAdr, (const char *s, int defaultport, netadr_t *a, size_t numaddresses, const char **pathstart)); + F(char *, AdrToString, (char *s, int len, netadr_t *a)); + F(struct serverinfo_s*,InfoForServer,(netadr_t *addr, const char *brokerid)); + F(qboolean, QueryServers, (void)); + F(void, QueryServer, (struct serverinfo_s *server)); + F(void, CheckPollSockets, (void)); + F(unsigned int, TotalCount, (void)); + F(struct serverinfo_s*,InfoForNum, (int num)); + F(char *, ReadKeyString, (struct serverinfo_s *server, unsigned int keynum)); + F(float, ReadKeyFloat, (struct serverinfo_s *server, unsigned int keynum)); + F(void, WriteServers, (void)); + F(char *, ServerToString, (char *s, int len, struct serverinfo_s *a)); +#define plugmasterfuncs_name "Master" +} plugmasterfuncs_t; +#endif + +struct flocation_s; typedef struct //for plugins that need to read/write files... { F(int, Open, (const char *name, qhandle_t *handle, int mode)); @@ -349,8 +501,12 @@ typedef struct //for plugins that need to read/write files... F(qboolean, GetLen, (qhandle_t handle, qofs_t *outsize)); + F(int, LocateFile, (const char *filename, unsigned int lflags, struct flocation_s *loc)); F(vfsfile_t*,OpenVFS, (const char *filename, const char *mode, enum fs_relative relativeto)); //opens a direct vfs file, without any access checks, and so can be used in threaded plugins F(qboolean, NativePath, (const char *name, enum fs_relative relativeto, char *out, int outlen)); + F(qboolean, Rename, (const char *oldf, const char *newf, enum fs_relative relativeto)); + F(qboolean, Remove, (const char *fname, enum fs_relative relativeto)); + F(void, EnumerateFiles, (const char *match, int (QDECL *callback)(const char *fname, qofs_t fsize, time_t mtime, void *ctx, struct searchpathfuncs_s *package), void *ctx)); //helpers @@ -359,7 +515,14 @@ typedef struct //for plugins that need to read/write files... F(void, FileBase, (const char *in, char *out, int outlen)); F(void, CleanUpPath, (char *str)); F(unsigned int,BlockChecksum,(const void *buffer, int length)); //mostly for pack hashes. - F(qbyte*, LoadFile, (const char *fname, size_t *fsize)); //plugfuncs->Free + F(void*, LoadFile, (const char *fname, size_t *fsize)); //plugfuncs->Free + + //stuff that's useful for networking. + F(char*, GetPackHashes, (char *buffer, int buffersize, qboolean referencedonly)); + F(char*, GetPackNames, (char *buffer, int buffersize, int referencedonly, qboolean ext)); + F(qboolean, GenCachedPakName, (const char *pname, const char *crc, char *local, int llen)); + F(void, PureMode, (const char *gamedir, int mode, char *purenamelist, char *purecrclist, char *refnamelist, char *refcrclist, int seed)); + F(char*, GenerateClientPacksList, (char *buffer, int maxlen, int basechecksum)); #define plugfsfuncs_name "Filesystem" } plugfsfuncs_t; @@ -387,6 +550,20 @@ typedef struct //for when you need basic socket access, hopefully rare... #define plugnetfuncs_name "Net" } plugnetfuncs_t; +//fixme: this sucks. +struct vm_s; +typedef qintptr_t (QDECL *sys_calldll_t) (qintptr_t arg, ...); +typedef int (*sys_callqvm_t) (void *offset, quintptr_t mask, int fn, const int *arg); +typedef struct +{ + F(struct vm_s *,Create, (const char *dllname, sys_calldll_t syscalldll, const char *qvmname, sys_callqvm_t syscallqvm)); + F(qboolean, NonNative, (struct vm_s *vm)); + F(void *, MemoryBase, (struct vm_s *vm)); + F(qintptr_t, Call, (struct vm_s *vm, qintptr_t instruction, ...)); + F(void, Destroy, (struct vm_s *vm)); +#define plugq3vmfuncs_name "Quake3 QVM" +} plugq3vmfuncs_t; + #undef F extern plugcorefuncs_t *plugfuncs; diff --git a/plugins/qi/qi.c b/plugins/qi/qi.c index 49419fa3..db188ecb 100644 --- a/plugins/qi/qi.c +++ b/plugins/qi/qi.c @@ -961,30 +961,24 @@ static int QDECL QI_ConExecuteCommand(qboolean isinsecure) return true; } -static qboolean QI_ExecuteCommand(qboolean isinsecure) +static void QI_ExecuteCommand_f(void) { char cmd[256]; - cmdfuncs->Argv(0, cmd, sizeof(cmd)); - if (!strcmp(cmd, "qi") || !strcmp(cmd, "quaddicted")) + if (cmdfuncs->Argc() > 1) { - if (cmdfuncs->Argc() > 1) - { - cmdfuncs->Args(cmd, sizeof(cmd)); - QI_UpdateFilter(cmd); - } - else if (QI_SetupWindow(WINDOWNAME, false)) - { - confuncs->SetActive(WINDOWNAME); - return true; - } - - if (!thedatabase && dlcontext == -1) - filefuncs->Open(DATABASEURL, &dlcontext, 1); - - QI_RefreshMapList(true); - return true; + cmdfuncs->Args(cmd, sizeof(cmd)); + QI_UpdateFilter(cmd); } - return false; + else if (QI_SetupWindow(WINDOWNAME, false)) + { + confuncs->SetActive(WINDOWNAME); + return; + } + + if (!thedatabase && dlcontext == -1) + filefuncs->Open(DATABASEURL, &dlcontext, 1); + + QI_RefreshMapList(true); } void QI_GenPackages(const char *url, vfsfile_t *pipe) @@ -1013,12 +1007,11 @@ qboolean Plug_Init(void) plugfuncs->ExportFunction("UpdateVideo", QI_UpdateVideo); if (plugfuncs->ExportFunction("Tick", QI_Tick) && plugfuncs->ExportFunction("Shutdown", QI_Shutdown) && - plugfuncs->ExportFunction("ExecuteCommand", QI_ExecuteCommand) && plugfuncs->ExportFunction("ConExecuteCommand", QI_ConExecuteCommand) && plugfuncs->ExportFunction("ConsoleLink", QI_ConsoleLink)) { - cmdfuncs->AddCommand("qi"); - cmdfuncs->AddCommand("quaddicted"); + cmdfuncs->AddCommand("qi", QI_ExecuteCommand_f, "Select or install maps or mods from Quaddicted's database."); + cmdfuncs->AddCommand("quaddicted", QI_ExecuteCommand_f, "Select or install maps or mods from Quaddicted's database."); return true; } }