1
0
Fork 0
forked from fte/fteqw

Added sys_openfile console command(and menu option) to web and flatpak(via cmake+dbus) builds, to 'install' packages on sandboxed systems a bit more easily.

Cmake: Add FTE_WERROR option, defaults to true in debug builds and off in release builds (in case future compilers have issues).
Cmake: Pull in libXscreensaver so we don't get interrupted by screensavers when playing demos.
Make: Added `make webcl-rel` for a web build without server bloat (eg for sites focused on demo playback. Yes, this means you XantoM).
fteqcc: Include the decompiler in fteqcc (non-gui) builds ('-d' arg).
fteqcc: Decompiler can now mostly handle hexen2 mods without any unknown opcodes.
Allow ezHud and OpenSSL to be compiled as in-engine plugins, potentially for web and windows ports respectively.
Web: Fix support for ogg vorbis. Add support for voip.
Web: Added basic support for WebXR.
QTV: Don't try seeking on unseekable qtv streams. Don't spam when developer 1 is set.
QTV: add support for some eztv extensions.
MVD: added hack to use ktx's vweps in mvd where mvdsv doesn't bother to record the info.
qwfwd: hack around a hack in qwfwd, allowing it to work again.
recording: favour qwd in single player, instead of mvd.
Protocol: reduce client memory used for precache names. Bump maximum precache counts - some people are just abusive, yes you Orl.
hexen2: add enough clientside protocol compat to play the demo included with h2mp. lacks effects.
in_xflip: restored this setting.
fs_hidesyspaths: new cvar, defaults to enabled so you won't find your username or whatever turning up in screenshots or the like. change it to 0 before debuging stuff eg via 'path'.
gl_overbright_models: Added cvar to match QS.
netchan: Added MTU determination, we'll no longer fail to connect when routers stupidly drop icmp packets.
Win: try a few other versions of xinput too.
CSQC: Added a CSQC_GenerateMaterial function, to give the csqc a chance to generate custom materials.
MenuQC: Added support for the skeletal objects API.
This commit is contained in:
Shpoike 2024-04-09 18:13:59 +01:00
parent ea0509805b
commit 8dadfb4878
199 changed files with 10060 additions and 3764 deletions

View file

@ -174,6 +174,19 @@ IF(JPEG_FOUND)
ELSE() ELSE()
MESSAGE(WARNING "libjpeg library NOT available. Who cares?") MESSAGE(WARNING "libjpeg library NOT available. Who cares?")
SET(FTE_LIB_DEFINES ${FTE_LIB_DEFINES};NO_JPEG) SET(FTE_LIB_DEFINES ${FTE_LIB_DEFINES};NO_JPEG)
SET(JPEG_LIBRARIES)
ENDIF()
SET(FTE_DEP_DBUS true CACHE BOOL "Link against libdbus.")
IF(FTE_DEP_DBUS)
FIND_PACKAGE(DBus1)
ENDIF()
IF(DBUS1_FOUND)
INCLUDE_DIRECTORIES( ${DBus1_INCLUDE_DIRS} )
SET(FTE_LIB_DEFINES ${FTE_LIB_DEFINES};HAVE_DBUS)
SET(FTE_LIBS ${FTE_LIBS} ${DBus1_LIBRARIES})
ELSE()
MESSAGE(WARNING "libdbus-1 library NOT available. Who cares?")
ENDIF() ENDIF()
SET(FTE_DEP_PNG true CACHE BOOL "Link against libpng.") SET(FTE_DEP_PNG true CACHE BOOL "Link against libpng.")
@ -187,6 +200,7 @@ IF(PNG_FOUND)
ELSE() ELSE()
MESSAGE(WARNING "libpng library NOT available. Good luck with screenshots.") MESSAGE(WARNING "libpng library NOT available. Good luck with screenshots.")
SET(FTE_LIB_DEFINES ${FTE_LIB_DEFINES};NO_PNG) SET(FTE_LIB_DEFINES ${FTE_LIB_DEFINES};NO_PNG)
SET(PNG_LIBRARIES)
ENDIF() ENDIF()
SET(FTE_DEP_FREETYPE true CACHE BOOL "Link against libfreetype.") SET(FTE_DEP_FREETYPE true CACHE BOOL "Link against libfreetype.")
@ -221,7 +235,7 @@ ELSE()
ENDIF() ENDIF()
SET(FTE_DEP_VORBISFILE true CACHE BOOL "Link against libvorbisfile.") SET(FTE_DEP_VORBISFILE true CACHE BOOL "Link against libvorbisfile.")
IF(FTE_DEP_VROBISFILE) IF(FTE_DEP_VORBISFILE)
FIND_LIBRARY(VORBISFILE_LIBRARY NAMES vorbisfile) FIND_LIBRARY(VORBISFILE_LIBRARY NAMES vorbisfile)
ENDIF() ENDIF()
IF(NOT VORBISFILE_LIBRARY) IF(NOT VORBISFILE_LIBRARY)
@ -230,18 +244,30 @@ IF(NOT VORBISFILE_LIBRARY)
SET(FTE_LIB_DEFINES ${FTE_LIB_DEFINES};NO_OGG) SET(FTE_LIB_DEFINES ${FTE_LIB_DEFINES};NO_OGG)
ENDIF() ENDIF()
IF(CMAKE_BUILD_TYPE MATCHES "Debug")
SET(FTE_WERROR true CACHE BOOL "Warnings as errors.")
ELSE()
SET(FTE_WERROR false CACHE BOOL "Warnings as errors.")
ENDIF()
IF(FTE_WERROR)
SET(FTE_WERROR_ARG "-Werror")
ELSE()
SET(FTE_WERROR_ARG "")
ENDIF()
IF(CMAKE_C_COMPILER_ID MATCHES "Clang") IF(CMAKE_C_COMPILER_ID MATCHES "Clang")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-pointer-sign") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-pointer-sign")
IF(CMAKE_BUILD_TYPE MATCHES "Debug") IF(CMAKE_BUILD_TYPE MATCHES "Debug")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Werror -Wno-pointer-sign -Wno-unknown-pragmas -Wno-format-zero-length -Wno-strict-aliasing -Wno-error=cpp") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall ${FTE_WERROR_ARG} -Wno-pointer-sign -Wno-unknown-pragmas -Wno-format-zero-length -Wno-strict-aliasing -Wno-error=cpp")
ELSE() ELSE()
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O3") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O3 ${FTE_WERROR_ARG}")
ENDIF() ENDIF()
endif() endif()
IF(CMAKE_C_COMPILER_ID MATCHES "GNU") IF(CMAKE_C_COMPILER_ID MATCHES "GNU")
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wstrict-prototypes") # SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wstrict-prototypes") #
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wold-style-definition") #k&r c is weird and can't cope with 64bit types. SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wold-style-definition") #k&r c is weird and can't cope with 64bit types.
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wmissing-parameter-type") #k&r c is weird and can't cope with 64bit types.
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wold-style-declaration") # SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wold-style-declaration") #
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wpointer-arith") #void* stuff SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wpointer-arith") #void* stuff
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wvla") #msvc doesn't support vla SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wvla") #msvc doesn't support vla
@ -254,9 +280,9 @@ IF(CMAKE_C_COMPILER_ID MATCHES "GNU")
#might as well do this, public builds use the regular Makefile. #might as well do this, public builds use the regular Makefile.
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -march=native") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -march=native")
IF(CMAKE_BUILD_TYPE MATCHES "Debug") IF(CMAKE_BUILD_TYPE MATCHES "Debug")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Werror -Wno-pointer-sign -Wno-unknown-pragmas -Wno-format-zero-length -Wno-strict-aliasing -Wno-error=cpp") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall ${FTE_WERROR_} -Wno-pointer-sign -Wno-unknown-pragmas -Wno-format-zero-length -Wno-strict-aliasing -Wno-error=cpp")
ELSE() ELSE()
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O3") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O3 ${FTE_WERROR_}")
ENDIF() ENDIF()
IF (NOT FTE_USE_SDL) IF (NOT FTE_USE_SDL)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wl,--warn-common") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wl,--warn-common")
@ -266,8 +292,8 @@ ENDIF()
IF(CMAKE_BUILD_TYPE MATCHES "Debug") IF(CMAKE_BUILD_TYPE MATCHES "Debug")
IF(NOT ${WIN32}) IF(NOT ${WIN32})
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fstack-protector-strong") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fstack-protector-strong")
ENDIF()
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=gnu89") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=gnu89")
ENDIF()
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -D_DEBUG") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -D_DEBUG")
ENDIF() ENDIF()
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -D_FILE_OFFSET_BITS=64") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -D_FILE_OFFSET_BITS=64")
@ -289,6 +315,32 @@ FUNCTION(EMBED_PLUGIN_META PLUGNAME PLUGTITLE PLUGDESC)
VERBATIM) VERBATIM)
ENDFUNCTION() ENDFUNCTION()
SET(FTE_DEP_GNUTLS true CACHE BOOL "Link against gnutls")
IF(FTE_DEP_GNUTLS)
FIND_PACKAGE(GnuTLS)
IF(NOT GNUTLS_FOUND)
MESSAGE(WARNING "gnutls library NOT available. HTTPS/DTLS will not be available.")
SET(FTE_LIB_DEFINES ${FTE_LIB_DEFINES};NO_GNUTLS)
ELSE()
IF(WIN32)
SET(GNUTLS_STATIC true CACHE BOOL "Link gnutls statically.") #usually as an .so though. :/
ELSE()
SET(GNUTLS_STATIC false CACHE BOOL "Link gnutls statically.") #usually as an .so though. :/
ENDIF()
IF(GNUTLS_STATIC)
SET(FTE_LIB_DEFINES ${FTE_LIB_DEFINES};GNUTLS_STATIC)
SET(FTE_LIBS ${FTE_LIBS} ${GNUTLS_LIBRARY})
SET(FTESV_LIBS ${FTESV_LIBS} ${GNUTLS_LIBRARY})
ENDIF()
ENDIF()
ENDIF()
IF(WIN32)
SET(FTE_DEP_WINSSPI true CACHE BOOL "Link against winsspi(schannel)")
IF(NOT FTE_DEP_WINSSPI)
SET(FTE_DEFINES ${FTE_DEFINES};NO_WINSSPI)
ENDIF()
ENDIF()
IF(${ANDROID}) IF(${ANDROID})
# FIND_PACKAGE(Freetype REQUIRED) # FIND_PACKAGE(Freetype REQUIRED)
@ -315,6 +367,7 @@ ELSEIF(WIN32 AND NOT FTE_USE_SDL)
engine/client/winquake.rc engine/client/winquake.rc
engine/common/sys_win_threads.c engine/common/sys_win_threads.c
engine/common/net_ssl_winsspi.c engine/common/net_ssl_winsspi.c
engine/common/net_ssl_gnutls.c
engine/common/fs_win32.c engine/common/fs_win32.c
engine/client/cd_win.c engine/client/cd_win.c
engine/client/in_win.c engine/client/in_win.c
@ -345,25 +398,13 @@ ELSEIF(WIN32 AND NOT FTE_USE_SDL)
engine/client/winquake.rc engine/client/winquake.rc
engine/common/sys_win_threads.c engine/common/sys_win_threads.c
engine/common/net_ssl_winsspi.c engine/common/net_ssl_winsspi.c
engine/common/net_ssl_gnutls.c
engine/common/fs_win32.c engine/common/fs_win32.c
engine/server/sv_sys_win.c engine/server/sv_sys_win.c
) )
ELSEIF(UNIX AND NOT FTE_USE_SDL) #linux(ish) ELSEIF(UNIX AND NOT FTE_USE_SDL) #linux(ish)
#openbsd will have issues with snd_linux.c #openbsd will have issues with snd_linux.c
FIND_PACKAGE(GnuTLS)
IF(NOT GNUTLS_FOUND)
MESSAGE(WARNING "gnutls library NOT available. HTTPS/DTLS will not be available.")
SET(FTE_LIB_DEFINES ${FTE_LIB_DEFINES};NO_GNUTLS)
ELSE()
SET(GNUTLS_STATIC false CACHE BOOL "Link gnutls statically.") #usually as an .so though. :/
IF(GNUTLS_STATIC)
SET(FTE_LIB_DEFINES ${FTE_LIB_DEFINES};GNUTLS_STATIC)
SET(FTE_LIBS ${FTE_LIBS} ${GNUTLS_LIBRARY})
SET(FTESV_LIBS ${FTESV_LIBS} ${GNUTLS_LIBRARY})
ENDIF()
ENDIF()
#linux-only packages #linux-only packages
FIND_PACKAGE(ALSA) FIND_PACKAGE(ALSA)
IF(ALSA_FOUND) IF(ALSA_FOUND)
@ -382,6 +423,10 @@ ELSEIF(UNIX AND NOT FTE_USE_SDL) #linux(ish)
SET(FTE_LIB_DEFINES ${FTE_LIB_DEFINES};NO_X11_RANDR) SET(FTE_LIB_DEFINES ${FTE_LIB_DEFINES};NO_X11_RANDR)
MESSAGE(WARNING "Xrandr library NOT available.") MESSAGE(WARNING "Xrandr library NOT available.")
ENDIF() ENDIF()
IF (NOT X11_Xscreensaver_FOUND)
SET(FTE_LIB_DEFINES ${FTE_LIB_DEFINES};NO_X11_XSS)
MESSAGE(WARNING "Xss library NOT available.")
ENDIF()
ELSE() ELSE()
MESSAGE(WARNING "x11 library NOT available.") MESSAGE(WARNING "x11 library NOT available.")
SET(FTE_LIB_DEFINES ${FTE_LIB_DEFINES};NO_X11) SET(FTE_LIB_DEFINES ${FTE_LIB_DEFINES};NO_X11)
@ -450,7 +495,7 @@ ELSEIF(UNIX AND NOT FTE_USE_SDL) #linux(ish)
ENDIF() ENDIF()
ENDIF() ENDIF()
SET(FTESV_DEFINES MULTITHREAD) SET(FTESV_DEFINES ${FTESV_DEFINES};MULTITHREAD)
SET(FTESV_ARCH_FILES ${FTESV_ARCH_FILES} SET(FTESV_ARCH_FILES ${FTESV_ARCH_FILES}
engine/server/sv_sys_unix.c engine/server/sv_sys_unix.c
engine/common/sys_linux_threads.c engine/common/sys_linux_threads.c
@ -481,7 +526,7 @@ ELSEIF(1) #SDL
engine/gl/gl_vidsdl.c engine/gl/gl_vidsdl.c
) )
SET(FTESV_DEFINES FTE_SDL) SET(FTESV_DEFINES ${FTESV_DEFINES};MULTITHREAD)
SET(FTESV_LIBS ${FTESV_LIBS} ${SYS_LIBS} ${CMAKE_DL_LIBS} ${SDL2_LIBRARIES}) SET(FTESV_LIBS ${FTESV_LIBS} ${SYS_LIBS} ${CMAKE_DL_LIBS} ${SDL2_LIBRARIES})
IF(WIN32) IF(WIN32)
@ -505,6 +550,7 @@ ELSEIF(1) #SDL
engine/common/sys_linux_threads.c engine/common/sys_linux_threads.c
engine/server/sv_sys_unix.c engine/server/sv_sys_unix.c
) )
SET(FTESV_LIBS ${FTESV_LIBS} pthread)
ENDIF() ENDIF()
ELSE() ELSE()
# engine/common/sys_linux_threads.c # engine/common/sys_linux_threads.c
@ -862,7 +908,7 @@ SET(FTE_Q3_FILES
) )
#For annoying compressed gltf2 files. #For annoying compressed gltf2 files.
SET(FTE_DEP_DRACO false CACHE BOOL "Link against libdraco.") SET(FTE_DEP_DRACO false CACHE BOOL "Link against libdraco (apache2).")
IF(FTE_DEP_DRACO) IF(FTE_DEP_DRACO)
FIND_LIBRARY( FIND_LIBRARY(
DRACO_LIBRARY DRACO_LIBRARY
@ -1052,8 +1098,8 @@ ELSE()
imgtool.c imgtool.c
iqm/iqm.h iqm/iqm.h
) )
SET_TARGET_PROPERTIES(iqmtool PROPERTIES COMPILE_DEFINITIONS "IQMTOOL;${DRACO_CFLAGS};${FTE_REVISON}") SET_TARGET_PROPERTIES(iqmtool PROPERTIES COMPILE_DEFINITIONS "IQMTOOL;${DRACO_CFLAGS};${FTE_LIB_DEFINES};${FTE_REVISON}")
TARGET_LINK_LIBRARIES(iqmtool ${CMAKE_DL_LIBS} ${DRACO_LIBRARY}) TARGET_LINK_LIBRARIES(iqmtool ${CMAKE_DL_LIBS} ${DRACO_LIBRARY} ${JPEG_LIBRARIES} ${PNG_LIBRARIES})
SET(INSTALLTARGS ${INSTALLTARGS} iqmtool) SET(INSTALLTARGS ${INSTALLTARGS} iqmtool)
ENDIF() ENDIF()
@ -1151,6 +1197,7 @@ ELSE()
engine/qclib/qcc_pr_lex.c engine/qclib/qcc_pr_lex.c
engine/qclib/qccmain.c engine/qclib/qccmain.c
engine/qclib/qcd_main.c engine/qclib/qcd_main.c
engine/qclib/decomp.c
engine/qclib/packager.c engine/qclib/packager.c
) )
SET_TARGET_PROPERTIES(fteqcc PROPERTIES COMPILE_DEFINITIONS "${FTE_LIB_DEFINES};${FTE_REVISON}") SET_TARGET_PROPERTIES(fteqcc PROPERTIES COMPILE_DEFINITIONS "${FTE_LIB_DEFINES};${FTE_REVISON}")
@ -1260,6 +1307,8 @@ SET(FTE_PLUG_OPENSSL false CACHE BOOL "Compile OpenSSL.")
IF(FTE_PLUG_OPENSSL) IF(FTE_PLUG_OPENSSL)
#the openssl license is incompatible with the GPL, so while we have code to use it distributing the binaries built with it is not a (legal) option. #the openssl license is incompatible with the GPL, so while we have code to use it distributing the binaries built with it is not a (legal) option.
#note that openssl 3.0.0 upwards are apache-2 licensed, which IS gpl-3 compatible (though not gpl-2). debian has not caught up with that yet, however. #note that openssl 3.0.0 upwards are apache-2 licensed, which IS gpl-3 compatible (though not gpl-2). debian has not caught up with that yet, however.
#Crosscompile linux->win64: sudo ln -s ${pwd}/engine/libs-x86_64-w64-mingw32/openssl-openssl-3.0.1/ /usr/x86_64-w64-mingw32/OpenSSL
SET(OPENSSL_USE_STATIC_LIBS true CACHE BOOL "Link openssl statically.") #usually as an .so though. :/)
FIND_PACKAGE(OpenSSL) FIND_PACKAGE(OpenSSL)
IF(OPENSSL_VERSION_MAJOR LESS 3) IF(OPENSSL_VERSION_MAJOR LESS 3)
SET(FTE_PRIVATE_USE_ONLY false CACHE BOOL "Ignore license violations.") SET(FTE_PRIVATE_USE_ONLY false CACHE BOOL "Ignore license violations.")
@ -1275,11 +1324,15 @@ IF(FTE_PLUG_OPENSSL)
MESSAGE(WARNING "Using openssl. Resulting plugin must be licensed as GPLv3.") MESSAGE(WARNING "Using openssl. Resulting plugin must be licensed as GPLv3.")
ENDIF() ENDIF()
SET(FTE_LIB_DEFINES ${FTE_LIB_DEFINES}) SET(FTE_LIB_DEFINES ${FTE_LIB_DEFINES})
if (WIN32)
SET(OPENSSL_LIBRARIES ${OPENSSL_LIBRARIES} ws2_32)
ENDIF()
ADD_LIBRARY(plug_openssl MODULE ADD_LIBRARY(plug_openssl MODULE
plugins/plugin.c plugins/plugin.c
plugins/net_ssl_openssl.c plugins/net_ssl_openssl.c
) )
TARGET_INCLUDE_DIRECTORIES(plug_openssl PRIVATE ${OPENSSL_INCLUDE_DIR})
SET_TARGET_PROPERTIES(plug_openssl PROPERTIES COMPILE_DEFINITIONS "FTEPLUGIN;${FTE_LIB_DEFINES}") SET_TARGET_PROPERTIES(plug_openssl PROPERTIES COMPILE_DEFINITIONS "FTEPLUGIN;${FTE_LIB_DEFINES}")
TARGET_LINK_LIBRARIES(plug_openssl ${SYS_LIBS} ${OPENSSL_LIBRARIES}) TARGET_LINK_LIBRARIES(plug_openssl ${SYS_LIBS} ${OPENSSL_LIBRARIES})
@ -1291,7 +1344,7 @@ ENDIF()
#IF(FTE_PLUG_GNUTLS) #IF(FTE_PLUG_GNUTLS)
# FIND_PACKAGE(GnuTLS) # FIND_PACKAGE(GnuTLS)
# IF(NOT GNUTLS_FOUND) # IF(NOT GNUTLS_FOUND)
# MESSAGE(WARNING "openssl library NOT available. you'll have to use some other library.") # MESSAGE(WARNING "gnutls library NOT available. you'll have to use some other library.")
# ELSE() # ELSE()
# SET(FTE_LIB_DEFINES ${FTE_LIB_DEFINES}) # SET(FTE_LIB_DEFINES ${FTE_LIB_DEFINES})
# #
@ -1628,7 +1681,8 @@ IF(FTE_MENU_SYS)
DEPENDS fteqcc DEPENDS fteqcc
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/quakec/menusys/" WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/quakec/menusys/"
COMMAND fteqcc -srcfile "menu.src" -o "${CMAKE_CURRENT_BINARY_DIR}/menu.dat" -DREVISION="${SVNREVISION}" -DDATE="${FTE_DATE}" -DBRANCH="${FTE_BRANCH}" COMMAND fteqcc -srcfile "menu.src" -o "${CMAKE_CURRENT_BINARY_DIR}/menu.dat" -DREVISION="${SVNREVISION}" -DDATE="${FTE_DATE}" -DBRANCH="${FTE_BRANCH}"
BYPRODUCTS "${CMAKE_CURRENT_BINARY_DIR}/menu.dat" "${CMAKE_CURRENT_BINARY_DIR}/menu.lno" COMMAND /bin/echo -e "{\\n package fte_menusys\\n ver \"${SVNREVISION}\"\\n category Plugins\\n title \"Replacement Menus\"\\n gamedir \"id1\"\\n desc \"Modern menus to replace the ancient quake ones\"\\n}" | zip -j -q -9 -fz- "${CMAKE_CURRENT_BINARY_DIR}/menusys.pk3" - "${CMAKE_CURRENT_BINARY_DIR}/menu.dat"
BYPRODUCTS "${CMAKE_CURRENT_BINARY_DIR}/menu.dat" "${CMAKE_CURRENT_BINARY_DIR}/menu.lno" "${CMAKE_CURRENT_BINARY_DIR}/menusys.pk3"
SOURCES SOURCES
quakec/menusys/menu.src quakec/menusys/menu.src
quakec/menusys/fteextensions.qc quakec/menusys/fteextensions.qc
@ -1665,12 +1719,8 @@ IF(FTE_MENU_SYS)
quakec/menusys/menu/quit.qc quakec/menusys/menu/quit.qc
) )
ADD_CUSTOM_COMMAND(
TARGET menusys POST_BUILD
COMMAND /bin/echo -e "{\\n package fte_menusys\\n ver \"${SVNREVISION}\"\\n category Plugins\\n title \"Replacement Menus\"\\n gamedir \"id1\"\\n desc \"Modern menus to replace the ancient quake ones\"\\n}" | zip -q -9 -fz- menusys.pk3 - menu.dat
VERBATIM)
INSTALL(FILES INSTALL(FILES
menusys.pk3 ${CMAKE_CURRENT_BINARY_DIR}/menusys.pk3
DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/games/quake/id1/") DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/games/quake/id1/")
ENDIF() ENDIF()
@ -1681,7 +1731,8 @@ IF(FTE_CSADDON)
DEPENDS fteqcc DEPENDS fteqcc
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/quakec/csaddon/src/" WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/quakec/csaddon/src/"
COMMAND fteqcc -srcfile "csaddon.src" -o "${CMAKE_CURRENT_BINARY_DIR}/csaddon.dat" COMMAND fteqcc -srcfile "csaddon.src" -o "${CMAKE_CURRENT_BINARY_DIR}/csaddon.dat"
BYPRODUCTS "${CMAKE_CURRENT_BINARY_DIR}/csaddon.dat" "${CMAKE_CURRENT_BINARY_DIR}/csaddon.lno" COMMAND /bin/echo -e "{\\n package fte_csaddon\\n ver \"${SVNREVISION}\"\\n category Plugins\\n title \"${PLUGTITLE}\"\\n gamedir \"id1\"\\n desc \"${PLUGDESC}\"\\n}" | zip -j -q -9 -fz- "${CMAKE_CURRENT_BINARY_DIR}/csaddon.pk3" - "${CMAKE_CURRENT_BINARY_DIR}/csaddon.dat"
BYPRODUCTS "${CMAKE_CURRENT_BINARY_DIR}/csaddon.dat" "${CMAKE_CURRENT_BINARY_DIR}/csaddon.lno" "${CMAKE_CURRENT_BINARY_DIR}/csaddon.pk3"
SOURCES SOURCES
quakec/csaddon/src/csaddon.src quakec/csaddon/src/csaddon.src
@ -1704,11 +1755,7 @@ IF(FTE_CSADDON)
quakec/csaddon/src/csaddon.qc quakec/csaddon/src/csaddon.qc
) )
ADD_CUSTOM_COMMAND(
TARGET csaddon POST_BUILD
COMMAND /bin/echo -e "{\\n package fte_csaddon\\n ver \"${SVNREVISION}\"\\n category Plugins\\n title \"${PLUGTITLE}\"\\n gamedir \"id1\"\\n desc \"${PLUGDESC}\"\\n}" | zip -q -9 -fz- csaddon.pk3 - csaddon.dat
VERBATIM)
INSTALL(FILES INSTALL(FILES
csaddon.pk3 ${CMAKE_CURRENT_BINARY_DIR}/csaddon.pk3
DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/games/quake/id1/") DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/games/quake/id1/")
ENDIF() ENDIF()

View file

@ -137,14 +137,10 @@ endif
ifneq (,$(findstring DLINK_QUAKE3,$(FTE_CONFIG_EXTRA))) ifneq (,$(findstring DLINK_QUAKE3,$(FTE_CONFIG_EXTRA)))
LINK_QUAKE3=1 LINK_QUAKE3=1
endif endif
ifeq ($(findstring web,$(FTE_TARGET)),) #the web target uses javascript/browser loaders for common audio+image files instead of needing to embed our own, which keeps sizes down slightly.
ifeq (,$(findstring DNO_VORBISFILE,$(FTE_CONFIG_EXTRA))) ifeq (,$(findstring DNO_VORBISFILE,$(FTE_CONFIG_EXTRA)))
USE_VORBISFILE=1 USE_VORBISFILE=1
endif endif
ifneq (,$(findstring DLINK_FREETYPE,$(FTE_CONFIG_EXTRA)))
LINK_FREETYPE=1
LINK_ZLIB=1
LINK_PNG=1
endif
ifneq (,$(findstring DLINK_JPEG,$(FTE_CONFIG_EXTRA))) ifneq (,$(findstring DLINK_JPEG,$(FTE_CONFIG_EXTRA)))
LINK_JPEG=1 LINK_JPEG=1
endif endif
@ -152,6 +148,12 @@ ifneq (,$(findstring DLINK_PNG,$(FTE_CONFIG_EXTRA)))
LINK_ZLIB=1 LINK_ZLIB=1
LINK_PNG=1 LINK_PNG=1
endif endif
endif
ifneq (,$(findstring DLINK_FREETYPE,$(FTE_CONFIG_EXTRA)))
LINK_FREETYPE=1
LINK_ZLIB=1
LINK_PNG=1
endif
ifneq (,$(findstring -Os,$(FTE_CONFIG_EXTRA))) ifneq (,$(findstring -Os,$(FTE_CONFIG_EXTRA)))
CPUOPTIMIZATIONS+=-Os CPUOPTIMIZATIONS+=-Os
BRANDFLAGS:=$(filter-out -O%,$(BRANDFLAGS)) BRANDFLAGS:=$(filter-out -O%,$(BRANDFLAGS))
@ -164,6 +166,12 @@ ifneq (,$(findstring DLINK_INTERNAL_BULLET,$(FTE_CONFIG_EXTRA)))
#bullet plugin will be built into the exe itself #bullet plugin will be built into the exe itself
INTERNAL_BULLET=1 INTERNAL_BULLET=1
endif endif
ifneq (,$(findstring DLINK_EZHUD,$(FTE_CONFIG_EXTRA)))
LINK_EZHUD=1
endif
ifneq (,$(findstring DLINK_OPENSSL,$(FTE_CONFIG_EXTRA)))
LINK_OPENSSL=1
endif
ifeq ($(BITS),64) ifeq ($(BITS),64)
CC:=$(CC) -m64 CC:=$(CC) -m64
@ -249,8 +257,9 @@ DO_CMAKE=cmake -DCMAKE_C_COMPILER="$(firstword $(CC))" -DCMAKE_C_FLAGS="$(wordli
ifeq ($(DROID_ARCH),) ifeq ($(DROID_ARCH),)
#armeabi armeabi-v7a arm64-v8a x86 x86_64 mips mips64 #armeabi armeabi-v7a arm64-v8a x86 x86_64 mips mips64
DROID_ARCH=armeabi-v7a DROID_ARCH+=armeabi-v7a #old 32bit android. yucky.
DROID_ARCH+=x86 DROID_ARCH+=arm64-v8a #modern android devices are 64bit-only. urgh.
DROID_ARCH+=x86 #mostly for testing...
#DROID_ARCH+=x86_64 #starting with DROID_API_LEVEL 21 #DROID_ARCH+=x86_64 #starting with DROID_API_LEVEL 21
endif endif
ifeq ($(FTE_TARGET),droid) ifeq ($(FTE_TARGET),droid)
@ -632,8 +641,6 @@ ifeq (win,$(findstring cyg,$(FTE_TARGET))$(findstring win,$(FTE_TARGET)))
# OGGVORBISLDFLAGS=$(MINGW_LIBS_DIR)/libvorbisfile.a $(MINGW_LIBS_DIR)/libvorbis.a $(MINGW_LIBS_DIR)/libogg.a # OGGVORBISLDFLAGS=$(MINGW_LIBS_DIR)/libvorbisfile.a $(MINGW_LIBS_DIR)/libvorbis.a $(MINGW_LIBS_DIR)/libogg.a
endif endif
OGGVORBISLDFLAGS ?= -lvorbisfile -lvorbis -logg
#BASELDFLAGS=-lm -lz #BASELDFLAGS=-lm -lz
XLDFLAGS=-L$(ARCHLIBS) $(IMAGELDFLAGS) XLDFLAGS=-L$(ARCHLIBS) $(IMAGELDFLAGS)
@ -987,8 +994,8 @@ ifeq (1,$(LINK_QUAKE3))
l_struct.o l_struct.o
endif endif
COMMONLIBFLAGS= COMMONLIBFLAGS?=
COMMONLDDEPS= COMMONLDDEPS?=
CLIENTLIBFLAGS=$(COMMONLIBFLAGS) $(LIBOPUS_STATIC) $(LIBSPEEX_STATIC) $(OGGVORBISFILE_STATIC) CLIENTLIBFLAGS=$(COMMONLIBFLAGS) $(LIBOPUS_STATIC) $(LIBSPEEX_STATIC) $(OGGVORBISFILE_STATIC)
SERVERLIBFLAGS=$(COMMONLIBFLAGS) SERVERLIBFLAGS=$(COMMONLIBFLAGS)
CLIENTLDDEPS=$(COMMONLDDEPS) $(LIBOPUS_LDFLAGS) $(LIBSPEEX_LDFLAGS) $(OGGVORBISLDFLAGS) CLIENTLDDEPS=$(COMMONLDDEPS) $(LIBOPUS_LDFLAGS) $(LIBSPEEX_LDFLAGS) $(OGGVORBISLDFLAGS)
@ -997,14 +1004,17 @@ ifeq (1,$(USE_OPUS))
LIBOPUS_STATIC=-DOPUS_STATIC LIBOPUS_STATIC=-DOPUS_STATIC
LIBOPUS_LDFLAGS=-lopus LIBOPUS_LDFLAGS=-lopus
ALL_CFLAGS+=-I/usr/include/opus ALL_CFLAGS+=-I/usr/include/opus
MAKELIBS+=libs-$(ARCH)/libopus.a
endif endif
ifeq (1,$(USE_SPEEX)) ifeq (1,$(USE_SPEEX))
LIBSPEEX_STATIC=-DSPEEX_STATIC LIBSPEEX_STATIC=-DSPEEX_STATIC
LIBSPEEX_LDFLAGS=-lspeex -lspeexdsp LIBSPEEX_LDFLAGS=-lspeex -lspeexdsp
MAKELIBS+=libs-$(ARCH)/libspeex.a libs-$(ARCH)/libspeexdsp.a
endif endif
ifeq (1,$(USE_VORBISFILE)) ifeq (1,$(USE_VORBISFILE))
OGGVORBISFILE_STATIC=-DLIBVORBISFILE_STATIC OGGVORBISFILE_STATIC=-DLIBVORBISFILE_STATIC
OGGVORBISLDFLAGS ?= -lvorbisfile -lvorbis -logg
else else
OGGVORBISLDFLAGS= OGGVORBISLDFLAGS=
OGGVORBISFILE_STATIC= OGGVORBISFILE_STATIC=
@ -1062,6 +1072,34 @@ ifeq (1,$(strip $(INTERNAL_BULLET)))
LDCC=$(CXX) LDCC=$(CXX)
MAKELIBS+=libs-$(ARCH)/libBulletDynamics.a MAKELIBS+=libs-$(ARCH)/libBulletDynamics.a
endif endif
ifeq (1,$(LINK_EZHUD))
VPATH := $(VPATH) : $(BASE_DIR)/../plugins/ezhud
ALL_CFLAGS+=-DSTATIC_EZHUD #let the plugins code know it needs to add the appropriate entry.
CLIENT_OBJS += \
ezquakeisms.o \
hud.o \
hud_common.o \
hud_editor.o
endif
ifeq (1,$(LINK_OPENSSL))
ifeq (1,$(shell $(PKGCONFIG) --version-atleast 3 openssl && echo 1)) #must exist... and if its not openssl3 then its not gpl3-compatible so refuse to use it.
VPATH := $(VPATH) : $(BASE_DIR)/../plugins
ALL_CFLAGS+=-DSTATIC_OPENSSL #let the plugins code know it needs to add the appropriate entry.
COMMON_OBJS += \
net_ssl_openssl.o
ALL_DFLAGS+=$(shell $(PKGCONFIG) openssl --cflags --silence-errors)
COMMONLDDEPS+=$(shell $(PKGCONFIG) openssl --libs --silence-errors)
endif
endif
ifeq (1,$(shell $(PKGCONFIG) --exists gnutls && echo 1))
ALL_CFLAGS+=$(shell $(PKGCONFIG) gnutls --cflags --silence-errors)
#ALL_CFLAGS+=-DGNUTLS_STATIC
#COMMONLDDEPS+=$(shell $(PKGCONFIG) gnutls --static --libs --silence-errors) #we soft-link, so we don't need the -lgnutls stuff.
else
ALL_CFLAGS+=-DNO_GNUTLS
endif
#the defaults for sdl come first #the defaults for sdl come first
#CC_MACHINE:=$(shell $(CC) -dumpmachine) #CC_MACHINE:=$(shell $(CC) -dumpmachine)
@ -1761,13 +1799,14 @@ ifeq ($(FTE_TARGET),web)
#GLCL_OBJS=$(GL_OBJS) $(D3DGL_OBJS) $(GLQUAKE_OBJS) cd_null.o #GLCL_OBJS=$(GL_OBJS) $(D3DGL_OBJS) $(GLQUAKE_OBJS) cd_null.o
#GL_LDFLAGS=$(GLLDFLAGS) #GL_LDFLAGS=$(GLLDFLAGS)
GLB_DIR=gl_web GLB_DIR=gl_web
GLCL_DIR=glcl_web
GL_EXE_NAME=../ftewebgl.js GL_EXE_NAME=../ftewebgl.js
GLCL_EXE_NAME=../ftewebglcl.js
GL_LDFLAGS=$(GLLDFLAGS) $(IMAGELDFLAGS) GL_LDFLAGS=$(GLLDFLAGS) $(IMAGELDFLAGS)
GL_CFLAGS=$(GLCFLAGS) GL_CFLAGS=$(GLCFLAGS) $(CLIENTLIBFLAGS)
IMAGELDFLAGS= IMAGELDFLAGS=
CLIENTLDDEPS=
SERVERLDDEPS= SERVERLDDEPS=
#generate deps properly #generate deps properly
@ -2074,17 +2113,24 @@ qccgui-scintilla: scintilla$(BITS)_static
@LTO= $(MAKE) _qcc-tmp TYPE=_out-rel REQDIR=reldir EXE_NAME="../fteqccgui$(BITS)" OUT_DIR="$(RELEASE_DIR)/$(QCC_DIR)scin" SOBJS="qccgui.o qccguistuff.o packager.o decomp.o fteqcc.o" WCFLAGS="$(WCFLAGS) -DSCISTATIC" LDFLAGS="$(LDFLAGS) $(RELEASE_DIR)/scintilla$(BITS).a -static -luuid -lole32 -limm32 -lstdc++ -loleaut32 -lcomdlg32 -lcomctl32 -lshlwapi -mwindows" @LTO= $(MAKE) _qcc-tmp TYPE=_out-rel REQDIR=reldir EXE_NAME="../fteqccgui$(BITS)" OUT_DIR="$(RELEASE_DIR)/$(QCC_DIR)scin" SOBJS="qccgui.o qccguistuff.o packager.o decomp.o fteqcc.o" WCFLAGS="$(WCFLAGS) -DSCISTATIC" LDFLAGS="$(LDFLAGS) $(RELEASE_DIR)/scintilla$(BITS).a -static -luuid -lole32 -limm32 -lstdc++ -loleaut32 -lcomdlg32 -lcomctl32 -lshlwapi -mwindows"
ifdef windir ifdef windir
debugdir: outdir:
@-mkdir -p "$(subst /,\, $(OUT_DIR))" ifneq "$(OUT_DIR)" ""
reldir:
@-mkdir -p "$(subst /,\, $(OUT_DIR))" @-mkdir -p "$(subst /,\, $(OUT_DIR))"
endif
debugdir: outdir
@-mkdir -p "$(subst /,\, $(RELEASE_DIR))"
reldir: outdir
@-mkdir -p "$(subst /,\, $(DEBUG_DIR))"
else else
reldir: outdir:
ifneq "$(OUT_DIR)" ""
@-mkdir -p "$(OUT_DIR)"
endif
debugdir: outdir
reldir: outdir
@-mkdir -p "$(RELEASE_DIR)" @-mkdir -p "$(RELEASE_DIR)"
@-mkdir -p "$(OUT_DIR)" debugdir: outdir
debugdir:
@-mkdir -p "$(DEBUG_DIR)" @-mkdir -p "$(DEBUG_DIR)"
@-mkdir -p "$(OUT_DIR)"
endif endif
plugins-dbg: plugins-dbg:
@ -2172,15 +2218,23 @@ else
endif endif
web-rel: web-rel:
@PATH="$(EMSCRIPTENPATH)" $(MAKE) gl-rel FTE_TARGET=web CC="$(EMCC)" @PATH="$(EMSCRIPTENPATH)" $(MAKE) makelibs FTE_TARGET=web CC="$(EMCC)" && PATH="$(EMSCRIPTENPATH)" $(MAKE) gl-rel FTE_TARGET=web CC="$(EMCC)"
cp $(BASE_DIR)/web/fteshell.html $(RELEASE_DIR)/ftewebgl.html @cp $(BASE_DIR)/web/fteshell.html $(RELEASE_DIR)/ftewebgl.html
@gzip -kf $(RELEASE_DIR)/ftewebgl.html @gzip -kf $(RELEASE_DIR)/ftewebgl.html
@gzip -kf $(RELEASE_DIR)/ftewebgl.js @gzip -kf $(RELEASE_DIR)/ftewebgl.js
@gzip -kf $(RELEASE_DIR)/ftewebgl.wasm @gzip -kf $(RELEASE_DIR)/ftewebgl.wasm
webcl-rel:
@PATH="$(EMSCRIPTENPATH)" $(MAKE) makelibs FTE_TARGET=web CC="$(EMCC)" && PATH="$(EMSCRIPTENPATH)" $(MAKE) glcl-rel FTE_TARGET=web CC="$(EMCC)"
@cp $(BASE_DIR)/web/fteshell.html $(RELEASE_DIR)/ftewebglcl.html
@sed -i 's/ftewebgl.js/ftewebglcl.js/g' release/ftewebglcl.html #swap out the .js filename for the client-only one.
@gzip -kf $(RELEASE_DIR)/ftewebglcl.html
@gzip -kf $(RELEASE_DIR)/ftewebglcl.js
@gzip -kf $(RELEASE_DIR)/ftewebglcl.wasm
web-dbg: web-dbg:
@PATH="$(EMSCRIPTENPATH)" $(MAKE) gl-dbg FTE_TARGET=web CC="$(EMCC)" @PATH="$(EMSCRIPTENPATH)" $(MAKE) gl-dbg FTE_TARGET=web CC="$(EMCC)"
cp $(BASE_DIR)/web/fteshell.html $(DEBUG_DIR)/ftewebgl.html @cp $(BASE_DIR)/web/fteshell.html $(DEBUG_DIR)/ftewebgl.html
@gzip -kf $(DEBUG_DIR)/ftewebgl.html @gzip -kf $(DEBUG_DIR)/ftewebgl.html
@gzip -kf $(DEBUG_DIR)/ftewebgl.js @gzip -kf $(DEBUG_DIR)/ftewebgl.js
@gzip -kf $(DEBUG_DIR)/ftewebgl.wasm @gzip -kf $(DEBUG_DIR)/ftewebgl.wasm
@ -2288,23 +2342,26 @@ AR?=$(ARCH)-ar
CONFIGARGS+= -host=$(ARCH) --enable-shared=no CC="$(CC)" CONFIGARGS+= -host=$(ARCH) --enable-shared=no CC="$(CC)"
CONFIGARGS:= $(CONFIGARGS) CONFIGARGS:= $(CONFIGARGS)
#--disable-silent-rules #--disable-silent-rules
OPUSCONFIGARGS=$(CONFIGARGS)
TOOLOVERRIDES+=CFLAGS="$$CFLAGS -Os" TOOLOVERRIDES+=CFLAGS="$$CFLAGS -Os"
TOOLCONGIGUREOVERRIDES=$(TOOLOVERRIDES)
TOOLMAKEOVERRIDES=$(TOOLOVERRIDES)
ifeq (web,$(FTE_TARGET))
TOOLCONFIGUREOVERRIDES=emconfigure
TOOLMAKEOVERRIDES=emmake
OPUSCONFIGARGS=--disable-rtcd --disable-hardening --enable-stack-protector=no --enable-shared=no
CONFIGARGS=--enable-shared=no
endif
libs-$(ARCH)/libjpeg.a: libs-$(ARCH)/libjpeg.a:
test -f jpegsrc.v$(JPEGVER).tar.gz || wget http://www.ijg.org/files/jpegsrc.v$(JPEGVER).tar.gz test -f jpegsrc.v$(JPEGVER).tar.gz || wget http://www.ijg.org/files/jpegsrc.v$(JPEGVER).tar.gz
-test -f libs-$(ARCH)/libjpeg.a || (mkdir -p libs-$(ARCH) && cd libs-$(ARCH) && tar -xvzf ../jpegsrc.v$(JPEGVER).tar.gz && cd jpeg-$(JPEGVER) && $(TOOLOVERRIDES) ./configure $(CONFIGARGS) && $(TOOLOVERRIDES) $(MAKE) && cp .libs/libjpeg.a ../ && $(TOOLOVERRIDES) $(AR) -s ../libjpeg.a && cp jconfig.h jerror.h jmorecfg.h jpeglib.h jversion.h ../ ) test -f libs-$(ARCH)/libjpeg.a || (mkdir -p libs-$(ARCH) && cd libs-$(ARCH) && tar -xvzf ../jpegsrc.v$(JPEGVER).tar.gz && cd jpeg-$(JPEGVER) && $(CONFIGUREOVERRIDES) ./configure $(CONFIGARGS) && $(TOOLOVERRIDES) $(MAKE) && cp .libs/libjpeg.a ../ && $(TOOLOVERRIDES) $(AR) -s ../libjpeg.a && cp jconfig.h jerror.h jmorecfg.h jpeglib.h jversion.h ../ )
ifeq ($(FTE_TARGET),web)
libs-$(ARCH)/libz.a libs-$(ARCH)/libz.pc: libs-$(ARCH)/libz.a libs-$(ARCH)/libz.pc:
test -f zlib-$(ZLIBVER).tar.gz || wget http://zlib.net/fossils/zlib-$(ZLIBVER).tar.gz test -f zlib-$(ZLIBVER).tar.gz || wget http://zlib.net/fossils/zlib-$(ZLIBVER).tar.gz
-test -f libs-$(ARCH)/libz.a || (mkdir -p libs-$(ARCH) && cd libs-$(ARCH) && tar -xvzf ../zlib-$(ZLIBVER).tar.gz && cd zlib-$(ZLIBVER) && emconfigure ./configure --static && emmake $(MAKE) libz.a CC="$(CC) $(W32_CFLAGS) -fPIC" && cp libz.a ../ && $(TOOLOVERRIDES) $(AR) -s ../libz.a && cp zlib.h zconf.h zutil.h zlib.pc ../ ) test -f libs-$(ARCH)/libz.a || (mkdir -p libs-$(ARCH) && cd libs-$(ARCH) && tar -xvzf ../zlib-$(ZLIBVER).tar.gz && cd zlib-$(ZLIBVER) && $(TOOLCONFIGUREOVERRIDES) ./configure --static && $(TOOLMAKEOVERRIDES) $(MAKE) libz.a CC="$(CC) $(W32_CFLAGS) -fPIC" && cp libz.a ../ && $(TOOLOVERRIDES) $(AR) -s ../libz.a && cp zlib.h zconf.h zutil.h zlib.pc ../ )
else
libs-$(ARCH)/libz.a libs-$(ARCH)/libz.pc:
test -f zlib-$(ZLIBVER).tar.gz || wget http://zlib.net/fossils/zlib-$(ZLIBVER).tar.gz
-test -f libs-$(ARCH)/libz.a || (mkdir -p libs-$(ARCH) && cd libs-$(ARCH) && tar -xvzf ../zlib-$(ZLIBVER).tar.gz && cd zlib-$(ZLIBVER) && $(TOOLOVERRIDES) ./configure --static && $(TOOLOVERRIDES) $(MAKE) libz.a CC="$(CC) $(W32_CFLAGS) -fPIC" && cp libz.a ../ && $(TOOLOVERRIDES) $(AR) -s ../libz.a && cp zlib.h zconf.h zutil.h zlib.pc ../ )
endif
libs-$(ARCH)/libz9.a: libs-$(ARCH)/libz.a libs-$(ARCH)/libz9.a: libs-$(ARCH)/libz.a
(cd libs-$(ARCH)/zlib-$(ZLIBVER) && \ (cd libs-$(ARCH)/zlib-$(ZLIBVER) && \
$(CC) -o contrib/infback9/infback9.o -c contrib/infback9/infback9.c -I. && \ $(CC) -o contrib/infback9/infback9.o -c contrib/infback9/infback9.c -I. && \
@ -2315,35 +2372,35 @@ libs-$(ARCH)/libz9.a: libs-$(ARCH)/libz.a
libs-$(ARCH)/libpng.a libs-$(ARCH)/libpng.pc: libs-$(ARCH)/libz.a libs-$(ARCH)/libz.pc libs-$(ARCH)/libpng.a libs-$(ARCH)/libpng.pc: libs-$(ARCH)/libz.a libs-$(ARCH)/libz.pc
test -f libpng-$(PNGVER).tar.gz || wget http://prdownloads.sourceforge.net/libpng/libpng-$(PNGVER).tar.gz?download -O libpng-$(PNGVER).tar.gz test -f libpng-$(PNGVER).tar.gz || wget http://prdownloads.sourceforge.net/libpng/libpng-$(PNGVER).tar.gz?download -O libpng-$(PNGVER).tar.gz
-test -f libs-$(ARCH)/libpng.a || (mkdir -p libs-$(ARCH) && cd libs-$(ARCH) && tar -xvzf ../libpng-$(PNGVER).tar.gz && cd libpng-$(PNGVER) && $(TOOLOVERRIDES) ./configure CPPFLAGS=-I$(NATIVE_ABSBASE_DIR)/libs-$(ARCH)/ LDFLAGS=-L$(NATIVE_ABSBASE_DIR)/libs-$(ARCH)/ $(CONFIGARGS) --enable-static && $(TOOLOVERRIDES) $(MAKE) && cp .libs/libpng16.a ../libpng.a && cp libpng.pc png*.h ../ ) test -f libs-$(ARCH)/libpng.a || (mkdir -p libs-$(ARCH) && cd libs-$(ARCH) && tar -xvzf ../libpng-$(PNGVER).tar.gz && cd libpng-$(PNGVER) && $(TOOLOVERRIDES) ./configure CPPFLAGS=-I$(NATIVE_ABSBASE_DIR)/libs-$(ARCH)/ LDFLAGS=-L$(NATIVE_ABSBASE_DIR)/libs-$(ARCH)/ $(CONFIGARGS) --enable-static && $(TOOLOVERRIDES) $(MAKE) && cp .libs/libpng16.a ../libpng.a && cp libpng.pc png*.h ../ )
libs-$(ARCH)/libogg.a: libs-$(ARCH)/libogg.a:
test -f libogg-$(OGGVER).tar.gz || wget http://downloads.xiph.org/releases/ogg/libogg-$(OGGVER).tar.gz test -f libogg-$(OGGVER).tar.gz || wget http://downloads.xiph.org/releases/ogg/libogg-$(OGGVER).tar.gz
-test -f libs-$(ARCH)/libogg.a || (mkdir -p libs-$(ARCH) && cd libs-$(ARCH) && tar -xvzf ../libogg-$(OGGVER).tar.gz && cd libogg-$(OGGVER) && $(TOOLOVERRIDES) ./configure $(CONFIGARGS) && $(TOOLOVERRIDES) $(MAKE) && cp src/.libs/libogg.a ../ && $(TOOLOVERRIDES) $(AR) -s ../libogg.a && mkdir ../ogg && cp include/ogg/*.h ../ogg) test -f libs-$(ARCH)/libogg.a || (mkdir -p libs-$(ARCH) && cd libs-$(ARCH) && tar -xvzf ../libogg-$(OGGVER).tar.gz && cd libogg-$(OGGVER) && $(TOOLOVERRIDES) ./configure $(CONFIGARGS) && $(TOOLOVERRIDES) $(MAKE) && cp src/.libs/libogg.a ../ && $(TOOLOVERRIDES) $(AR) -s ../libogg.a && mkdir ../ogg && cp include/ogg/*.h ../ogg)
libs-$(ARCH)/libvorbis.a: libs-$(ARCH)/libogg.a libs-$(ARCH)/libvorbis.a: libs-$(ARCH)/libogg.a
test -f libvorbis-$(VORBISVER).tar.gz || wget http://downloads.xiph.org/releases/vorbis/libvorbis-$(VORBISVER).tar.gz test -f libvorbis-$(VORBISVER).tar.gz || wget http://downloads.xiph.org/releases/vorbis/libvorbis-$(VORBISVER).tar.gz
-test -f libs-$(ARCH)/libvorbisfile.a || (mkdir -p libs-$(ARCH) && cd libs-$(ARCH) && tar -xvzf ../libvorbis-$(VORBISVER).tar.gz && cd libvorbis-$(VORBISVER) && $(TOOLOVERRIDES) ./configure PKG_CONFIG= $(CONFIGARGS) --disable-oggtest --with-ogg-libraries=.. --with-ogg-includes=$(NATIVE_ABSBASE_DIR)/libs-$(ARCH)/libogg-$(OGGVER)/include && $(TOOLOVERRIDES) $(MAKE) && cp lib/.libs/libvorbis.a ../ && cp lib/.libs/libvorbisfile.a ../ && mkdir ../vorbis && cp include/vorbis/*.h ../vorbis) test -f libs-$(ARCH)/libvorbisfile.a || (mkdir -p libs-$(ARCH) && cd libs-$(ARCH) && tar -xvzf ../libvorbis-$(VORBISVER).tar.gz && cd libvorbis-$(VORBISVER) && $(TOOLOVERRIDES) ./configure PKG_CONFIG= $(CONFIGARGS) --disable-oggtest --with-ogg-libraries=.. --with-ogg-includes=$(NATIVE_ABSBASE_DIR)/libs-$(ARCH)/libogg-$(OGGVER)/include && $(TOOLOVERRIDES) $(MAKE) && cp lib/.libs/libvorbis.a ../ && cp lib/.libs/libvorbisfile.a ../ && mkdir ../vorbis && cp include/vorbis/*.h ../vorbis)
libs-$(ARCH)/libopus.a: libs-$(ARCH)/libopus.a:
test -f opus-$(OPUSVER).tar.gz || wget https://archive.mozilla.org/pub/opus/opus-$(OPUSVER).tar.gz test -f opus-$(OPUSVER).tar.gz || wget https://archive.mozilla.org/pub/opus/opus-$(OPUSVER).tar.gz
-test -f libs-$(ARCH)/libopus.a || (mkdir -p libs-$(ARCH) && cd libs-$(ARCH) && tar -xvzf ../opus-$(OPUSVER).tar.gz && cd opus-$(OPUSVER) && CFLAGS="-D_FORTIFY_SOURCE=0 $(CFLAGS) -Os" $(TOOLOVERRIDES) ./configure $(CONFIGARGS) && $(TOOLOVERRIDES) $(MAKE) && cp .libs/libopus.a ../ && cp include/opus*.h ../) test -f libs-$(ARCH)/libopus.a || (mkdir -p libs-$(ARCH) && cd libs-$(ARCH) && tar -xvzf ../opus-$(OPUSVER).tar.gz && cd opus-$(OPUSVER) && CFLAGS="-D_FORTIFY_SOURCE=0 $(CFLAGS) -Os" $(TOOLCONFIGUREOVERRIDES) ./configure $(OPUSCONFIGARGS) --disable-extra-programs && $(TOOLMAKEOVERRIDES) $(MAKE) && cp .libs/libopus.a ../ && cp include/opus*.h ../)
libs-$(ARCH)/libspeex.a: libs-$(ARCH)/libspeex.a:
test -f speex-$(SPEEXVER).tar.gz || wget http://downloads.us.xiph.org/releases/speex/speex-$(SPEEXVER).tar.gz test -f speex-$(SPEEXVER).tar.gz || wget http://downloads.us.xiph.org/releases/speex/speex-$(SPEEXVER).tar.gz
-test -f libs-$(ARCH)/libspeex.a || (mkdir -p libs-$(ARCH)/speex && cd libs-$(ARCH) && tar -xvzf ../speex-$(SPEEXVER).tar.gz && cd speex-$(SPEEXVER) && CFLAGS="$(CFLAGS) -Os" $(TOOLOVERRIDES) ./configure $(CONFIGARGS) && $(TOOLOVERRIDES) $(MAKE) && cp libspeex/.libs/libspeex.a ../ && cp -r include/speex/*.h ../speex/) test -f libs-$(ARCH)/libspeex.a || (mkdir -p libs-$(ARCH)/speex && cd libs-$(ARCH) && tar -xvzf ../speex-$(SPEEXVER).tar.gz && cd speex-$(SPEEXVER) && CFLAGS="$(CFLAGS) -Os" $(TOOLCONFIGUREOVERRIDES) ./configure $(CONFIGARGS) --disable-binaries && $(TOOLMAKEOVERRIDES) $(MAKE) && cp libspeex/.libs/libspeex.a ../ && cp -r include/speex/*.h ../speex/)
libs-$(ARCH)/libspeexdsp.a: libs-$(ARCH)/libspeexdsp.a:
test -f speexdsp-$(SPEEXDSPVER).tar.gz || wget http://downloads.xiph.org/releases/speex/speexdsp-$(SPEEXDSPVER).tar.gz test -f speexdsp-$(SPEEXDSPVER).tar.gz || wget http://downloads.xiph.org/releases/speex/speexdsp-$(SPEEXDSPVER).tar.gz
-test -f libs-$(ARCH)/libspeexdsp.a || (mkdir -p libs-$(ARCH)/speex && cd libs-$(ARCH) && tar -xvzf ../speexdsp-$(SPEEXDSPVER).tar.gz && cd speexdsp-$(SPEEXDSPVER) && CFLAGS="$(CFLAGS) -Os" $(TOOLOVERRIDES) ./configure $(CONFIGARGS) && $(TOOLOVERRIDES) $(MAKE) && cp libspeexdsp/.libs/libspeexdsp.a ../ && cp -r include/speex/*.h ../speex/) test -f libs-$(ARCH)/libspeexdsp.a || (mkdir -p libs-$(ARCH)/speex && cd libs-$(ARCH) && tar -xvzf ../speexdsp-$(SPEEXDSPVER).tar.gz && cd speexdsp-$(SPEEXDSPVER) && CFLAGS="$(CFLAGS) -Os" $(TOOLCONFIGUREOVERRIDES) ./configure $(CONFIGARGS) && $(TOOLMAKEOVERRIDES) $(MAKE) && cp libspeexdsp/.libs/libspeexdsp.a ../ && cp -r include/speex/*.h ../speex/)
libs-$(ARCH)/libfreetype.a libs-$(ARCH)/ft2build.h: libs-$(ARCH)/libpng.a libs-$(ARCH)/libpng.pc libs-$(ARCH)/libfreetype.a libs-$(ARCH)/ft2build.h: libs-$(ARCH)/libpng.a libs-$(ARCH)/libpng.pc
test -f freetype-$(FREETYPEVER).tar.gz || wget https://download-mirror.savannah.gnu.org/releases/freetype/freetype-$(FREETYPEVER).tar.gz test -f freetype-$(FREETYPEVER).tar.gz || wget https://download-mirror.savannah.gnu.org/releases/freetype/freetype-$(FREETYPEVER).tar.gz
-test -f libs-$(ARCH)/libfreetype.a || (mkdir -p libs-$(ARCH) && cd libs-$(ARCH) && tar -xvzf ../freetype-$(FREETYPEVER).tar.gz && cd freetype-$(FREETYPEVER) && PKG_CONFIG_LIBDIR=$(NATIVE_ABSBASE_DIR)/libs-$(ARCH) CFLAGS="$(CFLAGS) -Os" $(TOOLOVERRIDES) ./configure CPPFLAGS=-I$(NATIVE_ABSBASE_DIR)/libs-$(ARCH)/ LDFLAGS=-L$(NATIVE_ABSBASE_DIR)/libs-$(ARCH)/ $(CONFIGARGS) --with-zlib=yes --with-png=yes --with-bzip2=no --with-harfbuzz=no && $(TOOLOVERRIDES) $(MAKE) && cp objs/.libs/libfreetype.a ../ && cp -r include/* ../) test -f libs-$(ARCH)/libfreetype.a || (mkdir -p libs-$(ARCH) && cd libs-$(ARCH) && tar -xvzf ../freetype-$(FREETYPEVER).tar.gz && cd freetype-$(FREETYPEVER) && PKG_CONFIG_LIBDIR=$(NATIVE_ABSBASE_DIR)/libs-$(ARCH) CFLAGS="$(CFLAGS) -Os" $(TOOLOVERRIDES) ./configure CPPFLAGS=-I$(NATIVE_ABSBASE_DIR)/libs-$(ARCH)/ LDFLAGS=-L$(NATIVE_ABSBASE_DIR)/libs-$(ARCH)/ $(CONFIGARGS) --with-zlib=yes --with-png=yes --with-bzip2=no --with-harfbuzz=no && $(TOOLOVERRIDES) $(MAKE) && cp objs/.libs/libfreetype.a ../ && cp -r include/* ../)
libs-$(ARCH)/libBulletDynamics.a: libs-$(ARCH)/libBulletDynamics.a:
test -f bullet3-$(BULLETVER).tar.gz || wget https://github.com/bulletphysics/bullet3/archive/$(BULLETVER).tar.gz -O bullet3-$(BULLETVER).tar.gz test -f bullet3-$(BULLETVER).tar.gz || wget https://github.com/bulletphysics/bullet3/archive/$(BULLETVER).tar.gz -O bullet3-$(BULLETVER).tar.gz
-test -f libs-$(ARCH)/libBulletDynamics.a || (mkdir -p libs-$(ARCH) && cd libs-$(ARCH) && tar -xvzf ../bullet3-$(BULLETVER).tar.gz && cd bullet3-$(BULLETVER) && CFLAGS="$(CFLAGS) -Os" $(TOOLOVERRIDES) $(DO_CMAKE) . && $(TOOLOVERRIDES) $(MAKE) LinearMath BulletDynamics BulletCollision && cp src/LinearMath/libLinearMath.a src/BulletDynamics/libBulletDynamics.a src/BulletCollision/libBulletCollision.a src/btBulletCollisionCommon.h src/btBulletDynamicsCommon.h ..) test -f libs-$(ARCH)/libBulletDynamics.a || (mkdir -p libs-$(ARCH) && cd libs-$(ARCH) && tar -xvzf ../bullet3-$(BULLETVER).tar.gz && cd bullet3-$(BULLETVER) && CFLAGS="$(CFLAGS) -Os" $(TOOLOVERRIDES) $(DO_CMAKE) . && $(TOOLOVERRIDES) $(MAKE) LinearMath BulletDynamics BulletCollision && cp src/LinearMath/libLinearMath.a src/BulletDynamics/libBulletDynamics.a src/BulletCollision/libBulletCollision.a src/btBulletCollisionCommon.h src/btBulletDynamicsCommon.h ..)
libs-$(ARCH)/vulkan/vulkan.h: libs-$(ARCH)/vulkan/vulkan.h:
test -f vulkan-sdk-$(VULKANVER).tar.gz || wget https://github.com/KhronosGroup/Vulkan-Headers/archive/refs/tags/vulkan-sdk-$(VULKANVER).tar.gz test -f vulkan-sdk-$(VULKANVER).tar.gz || wget https://github.com/KhronosGroup/Vulkan-Headers/archive/refs/tags/vulkan-sdk-$(VULKANVER).tar.gz
@ -2380,13 +2437,13 @@ $(RELEASE_DIR)/imgtool$(BITS)$(EXEPOSTFIX): $(IMGTOOL_OBJECTS)
imgtool-rel: $(RELEASE_DIR)/imgtool$(BITS)$(EXEPOSTFIX) imgtool-rel: $(RELEASE_DIR)/imgtool$(BITS)$(EXEPOSTFIX)
imgtool: imgtool-rel imgtool: imgtool-rel
MASTER_OBJECTS=server/sv_sys_unix.c common/sys_linux_threads.c common/net_ssl_gnutls.c server/sv_master.c common/net_wins.c common/net_ice.c common/cvar.c common/cmd.c common/sha1.c http/httpclient.c common/log.c common/fs.c common/fs_stdio.c common/common.c common/translate.c common/zone.c qclib/hash.c MASTER_OBJECTS=server/sv_sys_unix.c common/sys_linux_threads.c common/net_ssl_gnutls.c server/sv_master.c common/net_wins.c common/net_ice.c common/cvar.c common/cmd.c common/sha1.c common/sha2.c http/httpclient.c common/log.c common/fs.c common/fs_stdio.c common/common.c common/translate.c common/zone.c qclib/hash.c
$(RELEASE_DIR)/ftemaster$(BITS)$(EXEPOSTFIX): $(MASTER_OBJECTS) $(RELEASE_DIR)/ftemaster$(BITS)$(EXEPOSTFIX): $(MASTER_OBJECTS)
$(CC) -o $@ $(MASTER_OBJECTS) -flto=jobserver -fvisibility=hidden -Icommon -Iclient -Iqclib -Igl -Iserver -DMASTERONLY -Dstricmp=strcasecmp -Dstrnicmp=strncasecmp -lm -ldl -lz $(RELEASE_CFLAGS) $(RELEASE_LDFLAGS) $(CC) -o $@ $(MASTER_OBJECTS) -flto=jobserver -fvisibility=hidden -Icommon -Iclient -Iqclib -Igl -Iserver -DMASTERONLY -Dstricmp=strcasecmp -Dstrnicmp=strncasecmp -lm -ldl -lz $(RELEASE_CFLAGS) $(RELEASE_LDFLAGS)
$(DEBUG_DIR)/ftemaster$(BITS)$(EXEPOSTFIX): $(MASTER_OBJECTS) $(DEBUG_DIR)/ftemaster$(BITS)$(EXEPOSTFIX): $(MASTER_OBJECTS)
$(CC) -o $@ $(MASTER_OBJECTS) -Icommon -Iclient -Iqclib -Igl -Iserver -DMASTERONLY -Dstricmp=strcasecmp -Dstrnicmp=strncasecmp -lm -ldl -lz $(DEBUG_CFLAGS) $(DEBUG_LDFLAGS) $(CC) -o $@ $(MASTER_OBJECTS) -Icommon -Iclient -Iqclib -Igl -Iserver -DMASTERONLY -Dstricmp=strcasecmp -Dstrnicmp=strncasecmp -lm -ldl -lz $(DEBUG_CFLAGS) $(DEBUG_LDFLAGS)
master-rel: $(RELEASE_DIR)/ftemaster$(BITS)$(EXEPOSTFIX) master-rel: reldir $(RELEASE_DIR)/ftemaster$(BITS)$(EXEPOSTFIX)
master-dbg: $(DEBUG_DIR)/ftemaster$(BITS)$(EXEPOSTFIX) master-dbg: dbgdir $(DEBUG_DIR)/ftemaster$(BITS)$(EXEPOSTFIX)
master: master-rel master: master-rel
QTV_OBJECTS= \ QTV_OBJECTS= \

View file

@ -68,7 +68,7 @@ void Cam_AutoTrack_Update(const char *mode)
autotrack_statsrule = NULL; autotrack_statsrule = NULL;
if (!*mode || !Q_strcasecmp(mode, "auto")) if (!*mode || !Q_strcasecmp(mode, "auto"))
{ {
if (cls.demoplayback == DPB_MVD || cls.demoplayback == DPB_EZTV) if (cls.demoplayback == DPB_MVD)
{ {
autotrackmode = TM_STATS; autotrackmode = TM_STATS;
autotrack_statsrule = Z_StrDup(""); //default autotrack_statsrule = Z_StrDup(""); //default
@ -501,7 +501,7 @@ static int CL_AutoTrack_Choose(int seat)
best = cl.autotrack_killer; best = cl.autotrack_killer;
if (autotrackmode == TM_MODHINTS && seat == 0 && cl.autotrack_hint >= 0) if (autotrackmode == TM_MODHINTS && seat == 0 && cl.autotrack_hint >= 0)
best = cl.autotrack_hint; best = cl.autotrack_hint;
if (autotrackmode == TM_STATS && (cls.demoplayback == DPB_MVD || cls.demoplayback == DPB_EZTV)) if (autotrackmode == TM_STATS && cls.demoplayback == DPB_MVD)
best = CL_FindHighTrack(seat, autotrack_statsrule); best = CL_FindHighTrack(seat, autotrack_statsrule);
if (autotrackmode == TM_HIGHTRACK || best == -1) if (autotrackmode == TM_HIGHTRACK || best == -1)
best = CL_FindHighTrack(seat, "%f"); best = CL_FindHighTrack(seat, "%f");
@ -578,7 +578,7 @@ void Cam_Lock(playerview_t *pv, int playernum)
Skin_FlushPlayers(); Skin_FlushPlayers();
if (cls.demoplayback == DPB_MVD || cls.demoplayback == DPB_EZTV) if (cls.demoplayback == DPB_MVD)
{ {
memcpy(&pv->stats, cl.players[playernum].stats, sizeof(pv->stats)); memcpy(&pv->stats, cl.players[playernum].stats, sizeof(pv->stats));
// pv->cam_state = CAM_; // pv->cam_state = CAM_;
@ -1001,13 +1001,13 @@ void Cam_FinishMove(playerview_t *pv, usercmd_t *cmd)
if (cls.state != ca_active) if (cls.state != ca_active)
return; return;
if (!pv->spectator && (cls.demoplayback != DPB_MVD && cls.demoplayback != DPB_EZTV)) // only in spectator mode if (!pv->spectator && cls.demoplayback != DPB_MVD) // only in spectator mode
return; return;
if (cls.demoplayback == DPB_MVD || cls.demoplayback == DPB_EZTV) if (cls.demoplayback == DPB_MVD)
{ {
int nb; int nb = 0;
nb = (cmd->sidemove<0)?4:0; nb |= (cmd->sidemove<0)?4:0;
nb |= (cmd->sidemove>0)?8:0; nb |= (cmd->sidemove>0)?8:0;
nb |= (cmd->forwardmove<0)?16:0; nb |= (cmd->forwardmove<0)?16:0;
nb |= (cmd->forwardmove>0)?32:0; nb |= (cmd->forwardmove>0)?32:0;
@ -1015,6 +1015,8 @@ void Cam_FinishMove(playerview_t *pv, usercmd_t *cmd)
nb |= (cmd->upmove>0)?128:0; nb |= (cmd->upmove>0)?128:0;
if (Cam_TrackNum(pv) >= 0) if (Cam_TrackNum(pv) >= 0)
{ {
if (*cls.lastdemoname)
{ //changing rates or jumping doesn't make sense with mvds.
if (nb & (nb ^ pv->cam_oldbuttons) & 4) if (nb & (nb ^ pv->cam_oldbuttons) & 4)
Cvar_SetValue(&cl_demospeed, max(cl_demospeed.value - 0.1, 0)); Cvar_SetValue(&cl_demospeed, max(cl_demospeed.value - 0.1, 0));
if (nb & (nb ^ pv->cam_oldbuttons) & 8) if (nb & (nb ^ pv->cam_oldbuttons) & 8)
@ -1027,6 +1029,7 @@ void Cam_FinishMove(playerview_t *pv, usercmd_t *cmd)
Cbuf_AddText("demo_jump -10", RESTRICT_LOCAL); Cbuf_AddText("demo_jump -10", RESTRICT_LOCAL);
if (nb & (nb ^ pv->cam_oldbuttons) & (4|8)) if (nb & (nb ^ pv->cam_oldbuttons) & (4|8))
Con_Printf("playback speed: %g%%\n", cl_demospeed.value*100); Con_Printf("playback speed: %g%%\n", cl_demospeed.value*100);
}
if (nb & (nb ^ pv->cam_oldbuttons) & 64) if (nb & (nb ^ pv->cam_oldbuttons) & 64)
Cvar_SetValue(&cl_splitscreen, max(cl_splitscreen.ival - 1, 0)); Cvar_SetValue(&cl_splitscreen, max(cl_splitscreen.ival - 1, 0));
if (nb & (nb ^ pv->cam_oldbuttons) & 128) if (nb & (nb ^ pv->cam_oldbuttons) & 128)

View file

@ -78,6 +78,7 @@ void CL_StopPlayback (void)
cls.demoplayback = DPB_NONE; cls.demoplayback = DPB_NONE;
cls.demoseeking = false; //just in case cls.demoseeking = false; //just in case
cls.demotrack = -1; cls.demotrack = -1;
cls.demoeztv_ext = 0;
if (cls.timedemo) if (cls.timedemo)
CL_FinishTimeDemo (); CL_FinishTimeDemo ();
@ -215,7 +216,7 @@ int demo_preparsedemo(unsigned char *buffer, int bytes)
int ofs; int ofs;
unsigned int length; unsigned int length;
#define dem_mask 7 #define dem_mask 7
if (cls.demoplayback != DPB_MVD && cls.demoplayback != DPB_EZTV) if (cls.demoplayback != DPB_MVD)
return bytes; //no need if its not an mvd (this simplifies it a little) return bytes; //no need if its not an mvd (this simplifies it a little)
while (bytes>2) while (bytes>2)
@ -407,6 +408,12 @@ void CL_DemoJump_f(void)
return; return;
} }
if (!*cls.lastdemoname)
{
Con_Printf("unable to seak in qtv streams.\n");
return; //can't seek live streams...
}
if (*s == '+' || *s == '-') if (*s == '+' || *s == '-')
{ {
if (colon) if (colon)
@ -465,6 +472,12 @@ void CL_DemoNudge_f(void)
return; return;
} }
if (!*cls.lastdemoname)
{
Con_Printf("unable to seak in qtv streams.\n");
return; //can't seek live streams...
}
if (!move) if (!move)
move = 1; move = 1;
@ -519,6 +532,7 @@ qboolean CL_GetDemoMessage (void)
q1usercmd_t q1cmd; q1usercmd_t q1cmd;
int demopos = 0; int demopos = 0;
int msglength; int msglength;
static float throttle;
if (endofdemo) if (endofdemo)
{ {
@ -667,7 +681,7 @@ readnext:
} }
// read the time from the packet // read the time from the packet
if (cls.demoplayback == DPB_MVD || cls.demoplayback == DPB_EZTV) if (cls.demoplayback == DPB_MVD)
{ {
if (demtime < 0) if (demtime < 0)
{ {
@ -681,7 +695,9 @@ readnext:
if (readdemobytes(&demopos, &msecsadded, sizeof(msecsadded)) != sizeof(msecsadded)) if (readdemobytes(&demopos, &msecsadded, sizeof(msecsadded)) != sizeof(msecsadded))
{ {
Con_DPrintf("Not enough buffered\n"); Con_ThrottlePrintf(&throttle, 1, "Not enough buffered\n");
olddemotime = demtime+1;
demotime = olddemotime; demotime = olddemotime;
nextdemotime = demotime; nextdemotime = demotime;
return 0; return 0;
@ -696,7 +712,7 @@ readnext:
{ {
if (readdemobytes(&demopos, &demotime, sizeof(demotime)) != sizeof(demotime)) if (readdemobytes(&demopos, &demotime, sizeof(demotime)) != sizeof(demotime))
{ {
Con_DPrintf("Not enough buffered\n"); Con_ThrottlePrintf(&throttle, 1, "Not enough buffered\n");
olddemotime = demtime; //if we ran out of buffered demo, delay the demo parsing a little olddemotime = demtime; //if we ran out of buffered demo, delay the demo parsing a little
return 0; return 0;
} }
@ -763,15 +779,10 @@ readnext:
else else
demtime = demotime; // we're warping demtime = demotime; // we're warping
if (cls.demoplayback == DPB_MVD || cls.demoplayback == DPB_EZTV) if (cls.demoplayback == DPB_MVD)
{ {
if ((msecsadded || cls.netchan.incoming_sequence < 2) && olddemotime != demotime) if ((msecsadded || cls.netchan.incoming_sequence < 2) && olddemotime != demotime)
{ {
if (!(cls.fteprotocolextensions2 & PEXT2_REPLACEMENTDELTAS))
{
cls.netchan.incoming_sequence++;
cls.netchan.incoming_acknowledged++;
}
cls.netchan.frame_latency = 0; cls.netchan.frame_latency = 0;
cls.netchan.last_received = realtime; // just to happy timeout check cls.netchan.last_received = realtime; // just to happy timeout check
} }
@ -783,7 +794,7 @@ readnext:
// get the msg type // get the msg type
if (readdemobytes (&demopos, &c, sizeof(c)) != sizeof(c)) if (readdemobytes (&demopos, &c, sizeof(c)) != sizeof(c))
{ {
Con_DPrintf("Not enough buffered\n"); Con_ThrottlePrintf(&throttle, 1, "Not enough buffered\n");
olddemotime = demtime+1; olddemotime = demtime+1;
return 0; return 0;
} }
@ -805,7 +816,7 @@ readnext:
r = readdemobytes (&demopos, &q1cmd, sizeof(q1cmd)); r = readdemobytes (&demopos, &q1cmd, sizeof(q1cmd));
if (r != sizeof(q1cmd)) if (r != sizeof(q1cmd))
{ {
Con_DPrintf("Not enough buffered\n"); Con_ThrottlePrintf(&throttle, 1, "Not enough buffered\n");
olddemotime = demtime+1; olddemotime = demtime+1;
CL_StopPlayback (); CL_StopPlayback ();
return 0; return 0;
@ -843,7 +854,7 @@ readit:
// get the next message // get the next message
if (readdemobytes (&demopos, &msglength, 4) != 4) if (readdemobytes (&demopos, &msglength, 4) != 4)
{ {
Con_DPrintf("Not enough buffered\n"); Con_ThrottlePrintf(&throttle, 1, "Not enough buffered\n");
olddemotime = demtime+1; olddemotime = demtime+1;
return 0; return 0;
} }
@ -857,20 +868,27 @@ readit:
} }
if (readdemobytes (&demopos, net_message.data, msglength) != msglength) if (readdemobytes (&demopos, net_message.data, msglength) != msglength)
{ {
Con_DPrintf("Not enough buffered\n"); Con_ThrottlePrintf(&throttle, 1, "Not enough buffered\n");
olddemotime = demtime+1; olddemotime = demtime+1;
return 0; return 0;
} }
NET_UpdateRates(cls.sockets, true, msglength); //keep any rate calcs sane NET_UpdateRates(cls.sockets, true, msglength); //keep any rate calcs sane
net_message.cursize = msglength; net_message.cursize = msglength;
if (cls.demoplayback == DPB_MVD || cls.demoplayback == DPB_EZTV) if (cls.demoplayback == DPB_MVD)
{ {
int seat; int seat;
cl.defaultnetsplit = 0; cl.defaultnetsplit = 0;
switch(cls_lasttype) switch(cls_lasttype)
{ {
case dem_multiple: case dem_multiple:
if (!cls_lastto && (cls.ezprotocolextensions1 & EZPEXT1_HIDDEN_MESSAGES))
{ //an 'mvdsv hidden message' packet.
MSG_BeginReading(&net_message, cls.netchan.netprim);
CLEZ_ParseHiddenDemoMessage();
olddemotime = demotime;
goto readnext;
}
for (seat = 0; seat < cl.splitclients; seat++) for (seat = 0; seat < cl.splitclients; seat++)
{ {
tracknum = cl.playerview[seat].cam_spec_track; tracknum = cl.playerview[seat].cam_spec_track;
@ -939,7 +957,7 @@ readit:
NET_UpdateRates(cls.sockets, false, demopos); //keep any rate calcs sane NET_UpdateRates(cls.sockets, false, demopos); //keep any rate calcs sane
if (cls.demoplayback == DPB_MVD || cls.demoplayback == DPB_EZTV) if (cls.demoplayback == DPB_MVD)
cls.netchan.incoming_acknowledged = cls.netchan.incoming_sequence; cls.netchan.incoming_acknowledged = cls.netchan.incoming_sequence;
goto readnext; goto readnext;
@ -975,8 +993,21 @@ readit:
} }
demo_flushbytes(demopos); demo_flushbytes(demopos);
olddemotime = demotime; if (cls.demoplayback == DPB_MVD)
{
if ((msecsadded || cls.netchan.incoming_sequence < 2) && olddemotime != demotime)
{
if (!(cls.fteprotocolextensions2 & PEXT2_REPLACEMENTDELTAS))
{
cls.netchan.incoming_sequence++;
cls.netchan.incoming_acknowledged++;
}
cls.netchan.frame_latency = 0;
cls.netchan.last_received = realtime; // just to happy timeout check
}
}
olddemotime = demotime;
net_from.type = NA_INVALID; net_from.type = NA_INVALID;
return 1; return 1;
} }
@ -1009,6 +1040,7 @@ void CL_Stop_f (void)
} }
else else
#endif #endif
if (cls.demorecording == DPB_QUAKEWORLD)
{ {
SZ_Clear (&net_message); SZ_Clear (&net_message);
MSG_WriteLong (&net_message, -1); // -1 sequence means out of band MSG_WriteLong (&net_message, -1); // -1 sequence means out of band
@ -1139,12 +1171,16 @@ void CL_RecordMap_f (void)
CL_Disconnect_f(); CL_Disconnect_f();
SV_SpawnServer (mapname, NULL, false, false, 0); SV_SpawnServer (mapname, NULL, false, false, 0);
if (!sv.state)
return;
#ifdef MVD_RECORDING #ifdef MVD_RECORDING
if (svs.allocated_client_slots > 1)
COM_DefaultExtension(demoname, ".mvd", sizeof(demoname)); COM_DefaultExtension(demoname, ".mvd", sizeof(demoname));
#else else
COM_DefaultExtension(demoname, ".dem", sizeof(demoname));
#endif #endif
COM_DefaultExtension(demoname, ".qwd", sizeof(demoname));
COM_FileExtension(demoname, demoext, sizeof(demoext)); COM_FileExtension(demoname, demoext, sizeof(demoext));
#if defined(AVAIL_GZDEC) && !defined(CLIENTONLY) #if defined(AVAIL_GZDEC) && !defined(CLIENTONLY)
@ -1166,6 +1202,19 @@ void CL_RecordMap_f (void)
else else
#endif #endif
{ {
#ifdef NQPROT
if (!strcmp(demoext, "dem"))
cls.demorecording = DPB_NETQUAKE;
else
#endif
if (!strcmp(demoext, "qwd"))
cls.demorecording = DPB_QUAKEWORLD;
else
{
CL_Disconnect_f();
return;
}
cls.demooutfile = FS_OpenVFS (demoname, "wb", FS_GAME); cls.demooutfile = FS_OpenVFS (demoname, "wb", FS_GAME);
if (!cls.demooutfile) if (!cls.demooutfile)
{ {
@ -1176,16 +1225,10 @@ void CL_RecordMap_f (void)
if (!Q_strcasecmp(".gz", COM_GetFileExtension(demoname, NULL))) if (!Q_strcasecmp(".gz", COM_GetFileExtension(demoname, NULL)))
cls.demooutfile = FS_GZ_WriteFilter(cls.demooutfile, true, true); cls.demooutfile = FS_GZ_WriteFilter(cls.demooutfile, true, true);
#endif #endif
#ifdef NQPROT #ifdef NQPROT
if (!strcmp(demoext, "dem")) if (cls.demorecording == DPB_NETQUAKE)
{
cls.demorecording = DPB_NETQUAKE;
VFS_PUTS(cls.demooutfile, "-1\n"); VFS_PUTS(cls.demooutfile, "-1\n");
}
else
#endif #endif
cls.demorecording = DPB_QUAKEWORLD;
CL_WriteSetDemoMessage(); CL_WriteSetDemoMessage();
} }
} }
@ -1384,11 +1427,11 @@ void CLNQ_WriteServerData(sizebuf_t *buf) //for demo recording
MSG_WriteByte (buf, cl.deathmatch?GAME_DEATHMATCH:GAME_COOP); MSG_WriteByte (buf, cl.deathmatch?GAME_DEATHMATCH:GAME_COOP);
MSG_WriteString (buf, cl.levelname); MSG_WriteString (buf, cl.levelname);
for (i = 1; *cl.model_name[i] && i < MAX_PRECACHE_MODELS; i++) for (i = 1; cl.model_name[i] && i < MAX_PRECACHE_MODELS; i++)
MSG_WriteString (buf, cl.model_name[i]); MSG_WriteString (buf, cl.model_name[i]);
MSG_WriteByte (buf, 0); MSG_WriteByte (buf, 0);
for (i = 1; *cl.sound_name[i] && i < MAX_PRECACHE_SOUNDS ; i++) for (i = 1; cl.sound_name[i] && i < MAX_PRECACHE_SOUNDS ; i++)
MSG_WriteString (buf, cl.sound_name[i]); MSG_WriteString (buf, cl.sound_name[i]);
MSG_WriteByte (buf, 0); MSG_WriteByte (buf, 0);
} }
@ -2284,7 +2327,7 @@ void CL_PlayDemo_f (void)
} }
//dl is provided so that we can receive files via chunked/gziped http downloads and on systems that don't provide sockets etc. its tracked so we can cancel the download if the client aborts playback early. //dl is provided so that we can receive files via chunked/gziped http downloads and on systems that don't provide sockets etc. its tracked so we can cancel the download if the client aborts playback early.
void CL_PlayDemoStream(vfsfile_t *file, char *filename, qboolean issyspath, int demotype, float bufferdelay) void CL_PlayDemoStream(vfsfile_t *file, char *filename, qboolean issyspath, int demotype, float bufferdelay, unsigned int eztv_ext)
{ {
int protocol = CP_UNKNOWN; int protocol = CP_UNKNOWN;
@ -2295,7 +2338,6 @@ void CL_PlayDemoStream(vfsfile_t *file, char *filename, qboolean issyspath, int
switch(demotype) switch(demotype)
{ {
case DPB_EZTV:
case DPB_MVD: case DPB_MVD:
case DPB_QUAKEWORLD: case DPB_QUAKEWORLD:
protocol = CP_QUAKEWORLD; protocol = CP_QUAKEWORLD;
@ -2345,13 +2387,14 @@ void CL_PlayDemoStream(vfsfile_t *file, char *filename, qboolean issyspath, int
Con_Printf ("Playing demo from %s.\n", filename); Con_Printf ("Playing demo from %s.\n", filename);
} }
cls.findtrack = (demotype == DPB_MVD || demotype == DPB_EZTV); cls.findtrack = (demotype == DPB_MVD);
cls.demoplayback = demotype; cls.demoplayback = demotype;
cls.demoeztv_ext = eztv_ext;
cls.protocol = protocol; cls.protocol = protocol;
cls.state = ca_demostart; cls.state = ca_demostart;
net_message.packing = SZ_RAWBYTES; net_message.packing = SZ_RAWBYTES;
Netchan_Setup (NS_CLIENT, &cls.netchan, &net_from, 0); Netchan_Setup (NCF_CLIENT, &cls.netchan, &net_from, 0, 0);
demtime = -bufferdelay; demtime = -bufferdelay;
cls.demostarttime = 0; cls.demostarttime = 0;
@ -2391,20 +2434,20 @@ void CL_PlayDemoFile(vfsfile_t *f, char *demoname, qboolean issyspath)
if (!Q_strcasecmp(demoname + strlen(demoname) - 3, "dm2") || if (!Q_strcasecmp(demoname + strlen(demoname) - 3, "dm2") ||
!Q_strcasecmp(demoname + strlen(demoname) - 6, "dm2.gz")) !Q_strcasecmp(demoname + strlen(demoname) - 6, "dm2.gz"))
{ {
CL_PlayDemoStream(f, demoname, issyspath, DPB_QUAKE2, 0); CL_PlayDemoStream(f, demoname, issyspath, DPB_QUAKE2, 0, 0);
return; return;
} }
#endif #endif
if (!Q_strcasecmp(demoname + strlen(demoname) - 3, "mvd") || if (!Q_strcasecmp(demoname + strlen(demoname) - 3, "mvd") ||
!Q_strcasecmp(demoname + strlen(demoname) - 6, "mvd.gz")) !Q_strcasecmp(demoname + strlen(demoname) - 6, "mvd.gz"))
{ {
CL_PlayDemoStream(f, demoname, issyspath, DPB_MVD, 0); CL_PlayDemoStream(f, demoname, issyspath, DPB_MVD, 0, 0);
return; return;
} }
if (!Q_strcasecmp(demoname + strlen(demoname) - 3, "qwd") || if (!Q_strcasecmp(demoname + strlen(demoname) - 3, "qwd") ||
!Q_strcasecmp(demoname + strlen(demoname) - 6, "qwd.gz")) !Q_strcasecmp(demoname + strlen(demoname) - 6, "qwd.gz"))
{ {
CL_PlayDemoStream(f, demoname, issyspath, DPB_QUAKEWORLD, 0); CL_PlayDemoStream(f, demoname, issyspath, DPB_QUAKEWORLD, 0, 0);
return; return;
} }
@ -2436,7 +2479,7 @@ void CL_PlayDemoFile(vfsfile_t *f, char *demoname, qboolean issyspath)
else else
cls.demotrack = -1; cls.demotrack = -1;
CL_PlayDemoStream(f, demoname, issyspath, DPB_NETQUAKE, 0); CL_PlayDemoStream(f, demoname, issyspath, DPB_NETQUAKE, 0, 0);
return; return;
} }
VFS_SEEK(f, start); VFS_SEEK(f, start);
@ -2477,7 +2520,7 @@ void CL_PlayDemoFile(vfsfile_t *f, char *demoname, qboolean issyspath)
if (protocol >= PROTOCOL_VERSION_Q2_DEMO_MIN && protocol <= PROTOCOL_VERSION_Q2_DEMO_MAX) if (protocol >= PROTOCOL_VERSION_Q2_DEMO_MIN && protocol <= PROTOCOL_VERSION_Q2_DEMO_MAX)
{ {
VFS_SEEK(f, start); VFS_SEEK(f, start);
CL_PlayDemoStream(f, demoname, issyspath, DPB_QUAKE2, 0); CL_PlayDemoStream(f, demoname, issyspath, DPB_QUAKE2, 0, 0);
return; return;
} }
break; break;
@ -2493,7 +2536,7 @@ void CL_PlayDemoFile(vfsfile_t *f, char *demoname, qboolean issyspath)
//could also be .qwz or .dmz or whatever that nq extension is. we don't support either. //could also be .qwz or .dmz or whatever that nq extension is. we don't support either.
//mvd and qwd have no identifying markers, other than the extension. //mvd and qwd have no identifying markers, other than the extension.
CL_PlayDemoStream(f, demoname, issyspath, DPB_QUAKEWORLD, 0); CL_PlayDemoStream(f, demoname, issyspath, DPB_QUAKEWORLD, 0, 0);
} }
#ifdef WEBCLIENT #ifdef WEBCLIENT
void CL_PlayDownloadedDemo(struct dl_download *dl) void CL_PlayDownloadedDemo(struct dl_download *dl)
@ -2566,7 +2609,7 @@ void CL_Demo_ClientCommand(char *commandtext)
#ifdef warningmsg #ifdef warningmsg
#pragma warningmsg("this needs buffering safely") #pragma warningmsg("this needs buffering safely")
#endif #endif
if (cls.demoplayback == DPB_EZTV) if (cls.demoplayback == DPB_MVD && cls.demoeztv_ext)
{ {
VFS_WRITE(cls.demoinfile, &len, sizeof(len)); VFS_WRITE(cls.demoinfile, &len, sizeof(len));
VFS_WRITE(cls.demoinfile, &b, sizeof(b)); VFS_WRITE(cls.demoinfile, &b, sizeof(b));
@ -2947,8 +2990,9 @@ fail:
//eztv extensions to v1.0 //eztv extensions to v1.0
else if (!strcmp(s, "QTV_EZQUAKE_EXT")) else if (!strcmp(s, "QTV_EZQUAKE_EXT"))
{ {
iseztv = true; iseztv = atoi(colon);
Con_Printf("Warning: eztv extensions %s\n", colon); if (iseztv & ~(EZTV_DOWNLOAD|EZTV_SETINFO|EZTV_QTVUSERLIST))
Con_Printf(CON_WARNING"Warning: unknown eztv extensions %s\n", colon);
} }
//v1.1 sourcelist response includes SRCSRV, SRCHOST, SRCPLYRS, SRCVIEWS, SRCID //v1.1 sourcelist response includes SRCSRV, SRCHOST, SRCPLYRS, SRCVIEWS, SRCID
@ -3013,7 +3057,7 @@ fail:
Con_Printf("streaming \"%s\" from qtv\n", streamavailable); Con_Printf("streaming \"%s\" from qtv\n", streamavailable);
else else
Con_Printf("qtv connection established to %s\n", qtv->hostname); Con_Printf("qtv connection established to %s\n", qtv->hostname);
CL_PlayDemoStream(qtv->stream, NULL, false, iseztv?DPB_EZTV:DPB_MVD, BUFFERTIME); CL_PlayDemoStream(qtv->stream, NULL, false, DPB_MVD, BUFFERTIME, iseztv);
qtv->stream = NULL; qtv->stream = NULL;
demo_resetcache(qtv->requestsize - (tail-qtv->requestbuffer), tail); demo_resetcache(qtv->requestsize - (tail-qtv->requestbuffer), tail);
*link = qtv->next; *link = qtv->next;
@ -3194,8 +3238,8 @@ void CL_QTVPlay_f (void)
if (qtvcl_eztvextensions.ival) if (qtvcl_eztvextensions.ival)
{ {
Q_snprintfz(msg+msglen, sizeof(msg)-msglen, Q_snprintfz(msg+msglen, sizeof(msg)-msglen,
"QTV_EZQUAKE_EXT: 3\n" "QTV_EZQUAKE_EXT: %u\n"
"USERINFO: "); "USERINFO: ", EZTV_DOWNLOAD|EZTV_SETINFO|EZTV_QTVUSERLIST);
msglen += strlen(msg+msglen); msglen += strlen(msg+msglen);
InfoBuf_ToString(&cls.userinfo[0], msg+msglen, sizeof(msg)-msglen-1, basicuserinfos, NULL, NULL, NULL, NULL); InfoBuf_ToString(&cls.userinfo[0], msg+msglen, sizeof(msg)-msglen-1, basicuserinfos, NULL, NULL, NULL, NULL);
msglen += strlen(msg+msglen); msglen += strlen(msg+msglen);

View file

@ -925,7 +925,7 @@ void CLFTE_ReadDelta(unsigned int entnum, entity_state_t *news, entity_state_t *
if (bits & UF_DRAWFLAGS) if (bits & UF_DRAWFLAGS)
{ {
news->hexen2flags = MSG_ReadByte(); news->hexen2flags = MSG_ReadByte();
if ((news->hexen2flags & MLS_MASK) == MLS_ABSLIGHT) if ((news->hexen2flags & MLS_MASK) >= MLS_ADDLIGHT)
news->abslight = MSG_ReadByte(); news->abslight = MSG_ReadByte();
else else
news->abslight = 0; news->abslight = 0;
@ -1052,7 +1052,7 @@ void CLFTE_ParseEntities(void)
// Con_Printf("CL: Dropped %i\n", i); // Con_Printf("CL: Dropped %i\n", i);
// } // }
if (cls.demoplayback == DPB_MVD || cls.demoplayback == DPB_EZTV) if (cls.demoplayback == DPB_MVD)
{ {
cls.netchan.incoming_sequence++; cls.netchan.incoming_sequence++;
cls.netchan.incoming_acknowledged++; cls.netchan.incoming_acknowledged++;
@ -1291,7 +1291,7 @@ void CLQW_ParsePacketEntities (qboolean delta)
cl.inframes[newpacket].frameid = cls.netchan.incoming_sequence; cl.inframes[newpacket].frameid = cls.netchan.incoming_sequence;
cl.inframes[newpacket].receivedtime = realtime; cl.inframes[newpacket].receivedtime = realtime;
if (cls.protocol == CP_QUAKEWORLD && (cls.demoplayback == DPB_MVD || cls.demoplayback == DPB_EZTV)) if (cls.protocol == CP_QUAKEWORLD && cls.demoplayback == DPB_MVD)
{ {
extern float olddemotime; //time from the most recent demo packet extern float olddemotime; //time from the most recent demo packet
cl.oldgametime = cl.gametime; cl.oldgametime = cl.gametime;
@ -1317,7 +1317,7 @@ void CLQW_ParsePacketEntities (qboolean delta)
from = MSG_ReadByte (); from = MSG_ReadByte ();
// Con_Printf("%i %i from %i\n", cls.netchan.outgoing_sequence, cls.netchan.incoming_sequence, from); // Con_Printf("%i %i from %i\n", cls.netchan.outgoing_sequence, cls.netchan.incoming_sequence, from);
if (cls.demoplayback == DPB_MVD || cls.demoplayback == DPB_EZTV) if (cls.demoplayback == DPB_MVD)
from = oldpacket = cls.netchan.incoming_sequence - 1; from = oldpacket = cls.netchan.incoming_sequence - 1;
oldpacket = cl.inframes[from & UPDATE_MASK].frameid; oldpacket = cl.inframes[from & UPDATE_MASK].frameid;
@ -1851,6 +1851,209 @@ void CLDP_ParseDarkPlaces5Entities(void) //the things I do.. :o(
} }
} }
#ifdef HEXEN2
#define UH2_MOREBITS (1u<<0)
#define UH2_ORIGIN1 (1u<<1)
#define UH2_ORIGIN2 (1u<<2)
#define UH2_ORIGIN3 (1u<<3)
#define UH2_ANGLE2 (1u<<4)
#define UH2_STEP (1u<<5)
#define UH2_FRAME (1u<<6)
#define UH2_SIGNAL (1u<<7)
#define UH2_ANGLE1 (1u<<8)
#define UH2_ANGLE3 (1u<<9)
#define UH2_MODEL (1u<<10)
//#define UH2_ (1u<<11)
//#define UH2_ (1u<<12)
//#define UH2_ (1u<<13)
#define UH2_LONGENTITY (1u<<14)
#define UH2_EVENMORE (1u<<15)
#define UH2_SKIN (1u<<16)
#define UH2_EFFECTS (1u<<17)
#define UH2_SCALE (1u<<18)
#define UH2_COLORMAP (1u<<19)
void CLH2_ParseEntities(void)
{
//h2mp apparently uses some sort of delta compression
//there's three parts to this, the start, the updates, and the removes at the end.
//so we can be a bit lazy and parse the 'fast updates' here and assert they end with a final clear.
//entities are ordered.
packet_entities_t *oldpack, *newpack;
entity_state_t *to, *from;
unsigned int read, bits;
int oldi;
unsigned int removecount;
int frame = MSG_ReadByte();
int seq = MSG_ReadByte();
//not really sure what to do with this.
(void)frame;
(void)seq;
//server->client sequence
// if (cl.numackframes == sizeof(cl.ackframes)/sizeof(cl.ackframes[0]))
// cl.numackframes--;
// cl.ackframes[cl.numackframes++] = MSG_ReadLong(); /*server sequence to be acked*/
//client->server sequence ack
// if (cls.protocol_nq >= CPNQ_DP7)
// CL_AckedInputFrame(cls.netchan.incoming_sequence, MSG_ReadLong(), true); /*client input sequence which has been acked*/
if (cl.validsequence)
oldpack = &cl.inframes[(cl.validsequence)&UPDATE_MASK].packet_entities;
else
oldpack = NULL;
cl.validsequence = cls.netchan.incoming_sequence;
cl.inframes[(cls.netchan.incoming_sequence)&UPDATE_MASK].receivedtime = realtime;
cl.inframes[(cls.netchan.incoming_sequence)&UPDATE_MASK].frameid = cls.netchan.incoming_sequence;
newpack = &cl.inframes[(cls.netchan.incoming_sequence)&UPDATE_MASK].packet_entities;
newpack->servertime = cl.gametime;
//copy old state to new state
if (newpack != oldpack)
{
if (oldpack)
{
newpack->num_entities = oldpack->num_entities;
newpack->max_entities = newpack->num_entities+16; //for slop for new ents, to reduce reallocs
newpack->entities = BZ_Realloc(newpack->entities, sizeof(entity_state_t)*newpack->max_entities);
memcpy(newpack->entities, oldpack->entities, sizeof(entity_state_t)*newpack->num_entities);
}
else
newpack->num_entities = 0;
newpack->bonedatacur = 0;
//flag them all as having old bones
//they'll be renewed after parsing
for (oldi=0 ; oldi<newpack->num_entities ; oldi++)
newpack->entities[oldi].boneoffset |= 0x80000000;
}
for (;;)
{
bits = MSG_ReadByte();
if ((bits&0x80) == 0)
break; //no fast-update bit!
if (bits & UH2_MOREBITS)
bits |= MSG_ReadByte()<<8;
if (bits & UH2_EVENMORE)
bits |= MSG_ReadByte()<<16;
if (bits & UH2_LONGENTITY)
read = MSG_ReadUInt16();
else
read = MSG_ReadByte();
if (msg_badread)
Host_EndGame("Corrupt entity message packet\n");
if (!read)
break; //remove world signals end of packet.
if (read >= MAX_EDICTS)
Host_EndGame("Too many entities.\n");
if (!CL_CheckBaselines(read))
Host_EndGame("CLNQ_ParseEntity: check baselines failed with size %i", read);
from = &cl_baselines[read];
to = NULL;
for (oldi=0 ; oldi<newpack->num_entities ; oldi++)
{
if (read == newpack->entities[oldi].number)
{
from = &newpack->entities[oldi];
to = &newpack->entities[oldi];
break;
}
}
if (!to)
{ //okay, so this is new
if (newpack->num_entities==newpack->max_entities)
{
newpack->max_entities = newpack->num_entities+16;
newpack->entities = BZ_Realloc(newpack->entities, sizeof(entity_state_t)*newpack->max_entities);
}
to = &newpack->entities[newpack->num_entities];
newpack->num_entities++;
if (cl_shownet.ival >= 3)
Con_Printf("%3i: New %i %x\n", MSG_GetReadCount(), to->number, bits);
}
else if (cl_shownet.ival >= 3)
Con_Printf("%3i: Update %i %x\n", MSG_GetReadCount(), to->number, bits);
memcpy(to, from, sizeof(*to));
to->number = read;
if (bits & UH2_MODEL) to->modelindex = MSG_ReadShort();
if (bits & UH2_FRAME) to->frame = MSG_ReadByte();
if (bits & UH2_COLORMAP)to->colormap = MSG_ReadByte();
if (bits & UH2_SKIN) to->skinnum = MSG_ReadByte();
if (bits & UH2_SKIN) to->hexen2flags = MSG_ReadByte(); //yes, shared with skin
if (bits & UH2_EFFECTS) to->effects = MSG_ReadByte();
if (bits & UH2_ORIGIN1) to->origin[0] = MSG_ReadCoord();
if (bits & UH2_ANGLE1) to->angles[0] = MSG_ReadAngle();
if (bits & UH2_ORIGIN2) to->origin[1] = MSG_ReadCoord();
if (bits & UH2_ANGLE2) to->angles[1] = MSG_ReadAngle();
if (bits & UH2_ORIGIN3) to->origin[2] = MSG_ReadCoord();
if (bits & UH2_ANGLE3) to->angles[2] = MSG_ReadAngle();
if (bits & UH2_SCALE) to->scale = MSG_ReadByte()*(16.0/100);
if (bits & UH2_SCALE) to->abslight = MSG_ReadByte();
to->sequence = cls.netchan.incoming_sequence;
to->inactiveflag = 0;
}
//handle the removes
if (bits != 48)
Host_EndGame("Corrupt entity message packet\n");
removecount = (qbyte)MSG_ReadByte();
while (removecount --> 0)
{
read = MSG_ReadUInt16();
for (oldi=0 ; oldi<newpack->num_entities ; oldi++)
{
if (read == newpack->entities[oldi].number)
{
newpack->entities[oldi].inactiveflag = true;
break;
}
}
}
//sort them, just in case. the removes will bubble to the end.
qsort(newpack->entities, newpack->num_entities, sizeof(entity_state_t), CLDP_SortEntities);
while (newpack->num_entities)
{ //pop those removes.
if (newpack->entities[newpack->num_entities-1].inactiveflag)
newpack->num_entities--;
else
break;
}
//make sure any bone states are refreshed
for (oldi=0, to = newpack->entities; oldi<newpack->num_entities ; oldi++, to++)
{
if (to->bonecount && (to->boneoffset & 0x80000000))
{
unsigned int oldoffset = to->boneoffset & 0x7fffffff;
void *dest = AllocateBoneSpace(newpack, to->bonecount, &to->boneoffset);
void *src = GetBoneSpace(oldpack, oldoffset);
memcpy(dest, src, to->bonecount * sizeof(short)*7);
}
}
}
#endif
void CLNQ_ParseEntity(unsigned int bits) void CLNQ_ParseEntity(unsigned int bits)
{ {
int i; int i;
@ -3934,7 +4137,7 @@ static qboolean CL_ChooseInterpolationFrames(int *newf, int *oldf, float servert
qboolean CL_MayLerp(void) qboolean CL_MayLerp(void)
{ {
//force lerping when playing low-framerate demos. //force lerping when playing low-framerate demos.
if (cls.demoplayback == DPB_MVD || cls.demoplayback == DPB_EZTV) if (cls.demoplayback == DPB_MVD)
return true; return true;
#ifdef NQPROT #ifdef NQPROT
if (cls.demoplayback == DPB_NETQUAKE) if (cls.demoplayback == DPB_NETQUAKE)
@ -3956,13 +4159,13 @@ void CL_TransitionEntities (void)
qboolean nolerp; qboolean nolerp;
float servertime, frac; float servertime, frac;
if (cls.protocol == CP_QUAKEWORLD && (cls.demoplayback == DPB_MVD || cls.demoplayback == DPB_EZTV)) if (cls.protocol == CP_QUAKEWORLD && cls.demoplayback == DPB_MVD)
{ {
nolerp = false; nolerp = false;
} }
else else
{ {
nolerp = !CL_MayLerp() && cls.demoplayback != DPB_MVD && cls.demoplayback != DPB_EZTV; nolerp = !CL_MayLerp() && cls.demoplayback != DPB_MVD;
} }
if (cl.demonudge < 0) if (cl.demonudge < 0)
@ -4825,8 +5028,26 @@ void CLQW_ParsePlayerinfo (void)
oldstate = &cl.inframes[oldparsecountmod].playerstate[num]; oldstate = &cl.inframes[oldparsecountmod].playerstate[num];
state = &cl.inframes[parsecountmod].playerstate[num]; state = &cl.inframes[parsecountmod].playerstate[num];
if (cls.demoplayback == DPB_MVD || cls.demoplayback == DPB_EZTV) if (cls.demoplayback == DPB_MVD)
{ {
#ifdef QUAKESTATS
int i;
const char *viewmodel = NULL;
static struct {
const char *vmdl;
const char *vwep;
} haxx[] =
{
{"progs/v_axe.mdl", "w_axe"},
{"progs/v_shot.mdl", "w_shot"},
{"progs/v_shot2.mdl", "w_shot2"},
{"progs/v_nail.mdl", "w_nail"},
{"progs/v_nail2.mdl", "w_nail2"},
{"progs/v_rock.mdl", "w_rock"},
{"progs/v_rock2.mdl", "w_rock2"},
{"progs/v_light.mdl", "w_light"},
};
#endif
player_state_t dummy; player_state_t dummy;
if (!cl.parsecount || info->prevcount > cl.parsecount || cl.parsecount - info->prevcount >= UPDATE_BACKUP - 1) if (!cl.parsecount || info->prevcount > cl.parsecount || cl.parsecount - info->prevcount >= UPDATE_BACKUP - 1)
{ {
@ -4853,11 +5074,38 @@ void CLQW_ParsePlayerinfo (void)
state->messagenum = cl.parsecount; state->messagenum = cl.parsecount;
state->command.msec = 0; state->command.msec = 0;
state->command.impulse = 0;
#ifdef QUAKESTATS
i = cl.players[num].stats[STAT_WEAPONMODELI];
if (i>0&&i<MAX_PRECACHE_MODELS && cl.model_name_vwep[0])
viewmodel = cl.model_name[i];
if(viewmodel)
{
for (i = 0; i < countof(haxx); i++)
{
if (!strcmp(viewmodel, haxx[i].vmdl))
{
viewmodel = haxx[i].vwep;
for (i = 1; i < countof(cl.model_name_vwep); i++)
{
if (!cl.model_name_vwep[i])
break;
if (!strcmp(viewmodel, cl.model_name_vwep[i]))
{
state->command.impulse = i;
break;
}
}
break;
}
}
}
#endif
state->frame = MSG_ReadByte (); state->frame = MSG_ReadByte ();
state->state_time = parsecounttime; state->state_time = parsecounttime;
state->command.msec = 0;
for (i = 0; i < 3; i++) for (i = 0; i < 3; i++)
{ {
@ -5365,7 +5613,7 @@ void CL_LinkPlayers (void)
frame = &cl.inframes[displayseq&UPDATE_MASK]; frame = &cl.inframes[displayseq&UPDATE_MASK];
predictplayers = cl_predict_players.ival; predictplayers = cl_predict_players.ival;
if (cls.demoplayback == DPB_MVD || cls.demoplayback == DPB_EZTV) if (cls.demoplayback == DPB_MVD)
predictplayers = false; predictplayers = false;
for (j=0, info=cl.players, state=frame->playerstate ; j < cl.allocated_client_slots for (j=0, info=cl.players, state=frame->playerstate ; j < cl.allocated_client_slots

View file

@ -1332,6 +1332,8 @@ void CL_AdjustAngles (int pnum, double frametime)
if (!cl_instantrotate.ival) if (!cl_instantrotate.ival)
quant *= speed*frametime; quant *= speed*frametime;
in_rotate -= quant; in_rotate -= quant;
if (r_xflip.ival)
quant *= -1;
if (ruleset_allow_frj.ival) if (ruleset_allow_frj.ival)
cl.playerview[pnum].viewanglechange[YAW] += quant; cl.playerview[pnum].viewanglechange[YAW] += quant;
} }
@ -1342,6 +1344,8 @@ void CL_AdjustAngles (int pnum, double frametime)
if ((cl.fpd & FPD_LIMIT_YAW) || !ruleset_allow_frj.ival) if ((cl.fpd & FPD_LIMIT_YAW) || !ruleset_allow_frj.ival)
quant = bound(-900, quant, 900); quant = bound(-900, quant, 900);
quant *= frametime; quant *= frametime;
if (r_xflip.ival)
quant *= -1;
cl.playerview[pnum].viewanglechange[YAW] -= quant * CL_KeyState (&in_right, pnum, false); cl.playerview[pnum].viewanglechange[YAW] -= quant * CL_KeyState (&in_right, pnum, false);
cl.playerview[pnum].viewanglechange[YAW] += quant * CL_KeyState (&in_left, pnum, false); cl.playerview[pnum].viewanglechange[YAW] += quant * CL_KeyState (&in_left, pnum, false);
} }
@ -1410,6 +1414,9 @@ static void CL_BaseMove (vec3_t moves, int pnum)
if ((in_speed.state[pnum] & 1) ^ cl_run.ival) if ((in_speed.state[pnum] & 1) ^ cl_run.ival)
scale *= cl_movespeedkey.value; scale *= cl_movespeedkey.value;
if (r_xflip.ival)
sidespeed *= -1;
moves[0] = 0; moves[0] = 0;
if (! (in_klook.state[pnum] & 1) ) if (! (in_klook.state[pnum] & 1) )
{ {
@ -1819,7 +1826,7 @@ static qboolean CLFTE_SendVRCmd (sizebuf_t *buf, unsigned int seats)
if (flags & VRM_LOSS) if (flags & VRM_LOSS)
MSG_WriteByte (buf, (qbyte)lost); MSG_WriteByte (buf, (qbyte)lost);
if (flags & VRM_DELAY) if (flags & VRM_DELAY)
MSG_WriteByte (buf, bound(0,cldelay,255)); //a byte should always be enough for any framerate above 40. MSG_WriteByte (buf, bound(0,cldelay,255)); //a byte should always be enough for any framerate above 40, and we don't want peole to be able to lie so easily.
if (flags & VRM_ACKS) if (flags & VRM_ACKS)
{ {
MSG_WriteUInt64(buf, cl.numackframes); MSG_WriteUInt64(buf, cl.numackframes);
@ -2122,7 +2129,7 @@ void VARGS CL_SendSeatClientCommand(qboolean reliable, unsigned int seat, char *
char string[2048]; char string[2048];
clcmdbuf_t *buf, *prev; clcmdbuf_t *buf, *prev;
if (cls.demoplayback && cls.demoplayback != DPB_EZTV) if (cls.demoplayback && !(cls.demoplayback == DPB_MVD && cls.demoeztv_ext))
return; //no point. return; //no point.
va_start (argptr, format); va_start (argptr, format);
@ -2783,7 +2790,7 @@ void CL_SendCmd (double frametime, qboolean mainloop)
if (cls.demoplayback != DPB_NONE || cls.state <= ca_demostart) if (cls.demoplayback != DPB_NONE || cls.state <= ca_demostart)
{ {
cursor_active = false; cursor_active = false;
if (!cls.state || cls.demoplayback == DPB_MVD || cls.demoplayback == DPB_EZTV) if (!cls.state || cls.demoplayback == DPB_MVD)
{ {
extern cvar_t cl_splitscreen; extern cvar_t cl_splitscreen;
cl.ackedmovesequence = cl.movesequence; cl.ackedmovesequence = cl.movesequence;

View file

@ -73,7 +73,8 @@ cvar_t cl_nolerp = CVARD("cl_nolerp", "0", "Disables interpolation. If set, miss
cvar_t cl_nolerp_netquake = CVARD("cl_nolerp_netquake", "0", "Disables interpolation when connected to an NQ server. Does affect players, even the local player. You probably don't want to set this."); cvar_t cl_nolerp_netquake = CVARD("cl_nolerp_netquake", "0", "Disables interpolation when connected to an NQ server. Does affect players, even the local player. You probably don't want to set this.");
static cvar_t cl_fullpitch_nq = CVARAFD("cl_fullpitch", "0", "pq_fullpitch", CVAR_SEMICHEAT, "When set, attempts to unlimit the default view pitch. Note that some servers will screw over your angles if you use this, resulting in terrible gameplay, while some may merely clamp your angle serverside. This is also considered a cheat in quakeworld, ^1so this will not function there^7. For the equivelent in quakeworld, use serverinfo minpitch+maxpitch instead, which applies to all players fairly."); static cvar_t cl_fullpitch_nq = CVARAFD("cl_fullpitch", "0", "pq_fullpitch", CVAR_SEMICHEAT, "When set, attempts to unlimit the default view pitch. Note that some servers will screw over your angles if you use this, resulting in terrible gameplay, while some may merely clamp your angle serverside. This is also considered a cheat in quakeworld, ^1so this will not function there^7. For the equivelent in quakeworld, use serverinfo minpitch+maxpitch instead, which applies to all players fairly.");
#endif #endif
static cvar_t cl_forcevrui = CVARD("cl_forcevrui", "0", "Force the use of VR UIs, even with no VR headset active."); static cvar_t cl_vrui_force = CVARD("cl_vrui_force", "0", "Force the use of VR UIs, even with no VR headset active.");
cvar_t cl_vrui_lock = CVARD("cl_vrui_lock", "1", "Controls how the UI is positioned when using VR/XR. 0: Repositioned infront of the head when the console/menus are toggled. 1: Locked infront of the reference position (which may require the user to turn around to find it).");
cvar_t *hud_tracking_show; cvar_t *hud_tracking_show;
cvar_t *hud_miniscores_show; cvar_t *hud_miniscores_show;
extern cvar_t net_compress; extern cvar_t net_compress;
@ -119,14 +120,18 @@ cvar_t cl_noblink = CVARD("cl_noblink", "0", "Disable the ^^b text blinking feat
cvar_t cl_servername = CVARFD("cl_servername", "", CVAR_NOSET, "The hostname of the last server you connected to"); cvar_t cl_servername = CVARFD("cl_servername", "", CVAR_NOSET, "The hostname of the last server you connected to");
cvar_t cl_serveraddress = CVARD("cl_serveraddress", "none", "The address of the last server you connected to"); cvar_t cl_serveraddress = CVARD("cl_serveraddress", "none", "The address of the last server you connected to");
cvar_t qtvcl_forceversion1 = CVAR("qtvcl_forceversion1", "0"); cvar_t qtvcl_forceversion1 = CVAR("qtvcl_forceversion1", "0");
cvar_t qtvcl_eztvextensions = CVAR("qtvcl_eztvextensions", "0"); cvar_t qtvcl_eztvextensions = CVAR("qtvcl_eztvextensions", "1");
cvar_t record_flush = CVARD("record_flush", "0", "If set, explicitly flushes demo data to disk while recording. This may be inefficient, depending on how your operating system is configured."); cvar_t record_flush = CVARD("record_flush", "0", "If set, explicitly flushes demo data to disk while recording. This may be inefficient, depending on how your operating system is configured.");
cvar_t cl_demospeed = CVARF("cl_demospeed", "1", 0); cvar_t cl_demospeed = CVARF("cl_demospeed", "1", 0);
cvar_t cl_demoreel = CVARFD("cl_demoreel", "0", CVAR_SAVE, "When enabled, the engine will begin playing a demo loop on startup."); cvar_t cl_demoreel = CVARFD("cl_demoreel", "0", CVAR_SAVE, "When enabled, the engine will begin playing a demo loop on startup.");
cvar_t cl_loopbackprotocol = CVARD("cl_loopbackprotocol", "qw", "Which protocol to use for single-player/the internal client. Should be one of: qw, qwid, nqid, nq, fitz, bjp3, dp6, dp7, auto. If 'auto', will use qw protocols for qw mods, and nq protocols for nq mods."); cvar_t cl_loopbackprotocol = CVARD("cl_loopbackprotocol", "qw", "Which protocol to use for single-player/the internal client. Should be one of: qw, qwid, nqid, nq, fitz, bjp3, dp6, dp7, auto. If 'auto', will use qw protocols for qw mods, and nq protocols for nq mods.");
#ifdef FTE_TARGET_WEB
static cvar_t cl_verify_urischeme = CVARAFD("cl_verify_urischeme", "2", "cl_verify_qwprotocol"/*ezquake, inappropriate for misc schemes*/, CVAR_NOSAVE/*checked at startup, so its only really default.cfg that sets it*/, "0: Do nothing.\n1: Check whether our protocol scheme is registered and prompt the user to register associations.\n2: Always re-register on every startup, without prompting. Sledgehammer style.");
#else
static cvar_t cl_verify_urischeme = CVARAFD("cl_verify_urischeme", "0", "cl_verify_qwprotocol"/*ezquake, inappropriate for misc schemes*/, CVAR_NOSAVE/*checked at startup, so its only really default.cfg that sets it*/, "0: Do nothing.\n1: Check whether our protocol scheme is registered and prompt the user to register associations.\n2: Always re-register on every startup, without prompting. Sledgehammer style."); static cvar_t cl_verify_urischeme = CVARAFD("cl_verify_urischeme", "0", "cl_verify_qwprotocol"/*ezquake, inappropriate for misc schemes*/, CVAR_NOSAVE/*checked at startup, so its only really default.cfg that sets it*/, "0: Do nothing.\n1: Check whether our protocol scheme is registered and prompt the user to register associations.\n2: Always re-register on every startup, without prompting. Sledgehammer style.");
#endif
cvar_t cl_threadedphysics = CVARD("cl_threadedphysics", "0", "When set, client input frames are generated and sent on a worker thread"); cvar_t cl_threadedphysics = CVARD("cl_threadedphysics", "0", "When set, client input frames are generated and sent on a worker thread");
@ -192,7 +197,6 @@ cvar_t cl_sendguid = CVARD("cl_sendguid", "", "Send a randomly generated 'glo
cvar_t cl_downloads = CVARAFD("cl_downloads", "1", /*q3*/"cl_allowDownload", CVAR_NOTFROMSERVER|CVAR_ARCHIVE, "Allows you to block all automatic downloads."); cvar_t cl_downloads = CVARAFD("cl_downloads", "1", /*q3*/"cl_allowDownload", CVAR_NOTFROMSERVER|CVAR_ARCHIVE, "Allows you to block all automatic downloads.");
cvar_t cl_download_csprogs = CVARFD("cl_download_csprogs", "1", CVAR_NOTFROMSERVER|CVAR_ARCHIVE, "Download updated client gamecode if available. Warning: If you clear this to avoid downloading vm code, you should also clear cl_download_packages."); cvar_t cl_download_csprogs = CVARFD("cl_download_csprogs", "1", CVAR_NOTFROMSERVER|CVAR_ARCHIVE, "Download updated client gamecode if available. Warning: If you clear this to avoid downloading vm code, you should also clear cl_download_packages.");
cvar_t cl_download_redirection = CVARFD("cl_download_redirection", "2", CVAR_NOTFROMSERVER|CVAR_ARCHIVE, "Follow download redirection to download packages instead of individual files. Also allows the server to send nearly arbitary download commands.\n2: allows redirection only to named packages files (and demos/*.mvd), which is a bit safer."); cvar_t cl_download_redirection = CVARFD("cl_download_redirection", "2", CVAR_NOTFROMSERVER|CVAR_ARCHIVE, "Follow download redirection to download packages instead of individual files. Also allows the server to send nearly arbitary download commands.\n2: allows redirection only to named packages files (and demos/*.mvd), which is a bit safer.");
cvar_t cl_download_mapsrc = CVARFD("cl_download_mapsrc", "", CVAR_ARCHIVE, "Specifies an http location prefix for map downloads. EG: \"http://example.com/path/gamemaps/\"");
cvar_t cl_download_packages = CVARFD("cl_download_packages", "1", CVAR_NOTFROMSERVER, "0=Do not download packages simply because the server is using them. 1=Download and load packages as needed (does not affect games which do not use this package). 2=Do download and install permanently (use with caution!)"); cvar_t cl_download_packages = CVARFD("cl_download_packages", "1", CVAR_NOTFROMSERVER, "0=Do not download packages simply because the server is using them. 1=Download and load packages as needed (does not affect games which do not use this package). 2=Do download and install permanently (use with caution!)");
cvar_t requiredownloads = CVARAFD("cl_download_wait", "1", /*old*/"requiredownloads", CVAR_ARCHIVE, "0=join the game before downloads have even finished (might be laggy). 1=wait for all downloads to complete before joining."); cvar_t requiredownloads = CVARAFD("cl_download_wait", "1", /*old*/"requiredownloads", CVAR_ARCHIVE, "0=join the game before downloads have even finished (might be laggy). 1=wait for all downloads to complete before joining.");
cvar_t mod_precache = CVARD("mod_precache","1", "Controls when models are loaded.\n0: Load them only when they're actually needed.\n1: Load them upfront.\n2: Lazily load them to shorten load times at the risk of brief stuttering during only the start of the map."); cvar_t mod_precache = CVARD("mod_precache","1", "Controls when models are loaded.\n0: Load them only when they're actually needed.\n1: Load them upfront.\n2: Lazily load them to shorten load times at the risk of brief stuttering during only the start of the map.");
@ -302,7 +306,7 @@ static struct
} ext; } ext;
int qport; int qport;
int challenge; //tracked as part of guesswork based upon what replies we get. int challenge; //tracked as part of guesswork based upon what replies we get.
int clchallenge; int clchallenge; //generated by the client, to ensure the response wasn't spoofed/spammed.
double time; //for connection retransmits double time; //for connection retransmits
qboolean clogged; //ignore time... qboolean clogged; //ignore time...
enum coninfomode_e enum coninfomode_e
@ -361,6 +365,9 @@ void VRUI_SnapAngle(void)
{ {
// VectorCopy(cl.playerview[0].viewangles, vrui.angles); // VectorCopy(cl.playerview[0].viewangles, vrui.angles);
vrui.angles[0] = 0; vrui.angles[0] = 0;
if (cl_vrui_lock.ival) //if its locked, then its locked infront of the unpitched player entity
vrui.angles[1] = cl.playerview[0].viewangles[1];
else //otherwise its moved to infront of the player's head any time the menu is displayed.
vrui.angles[1] = cl.playerview[0].aimangles[1]; vrui.angles[1] = cl.playerview[0].aimangles[1];
vrui.angles[2] = 0; vrui.angles[2] = 0;
} }
@ -796,6 +803,8 @@ static void CL_SendConnectPacket (netadr_t *to)
//cl.splitclients = 1; //cl.splitclients = 1;
if (q3) if (q3)
q3->cl.SendConnectPacket(cls.sockets, to, connectinfo.challenge, connectinfo.qport, cls.userinfo); q3->cl.SendConnectPacket(cls.sockets, to, connectinfo.challenge, connectinfo.qport, cls.userinfo);
else
CL_ConnectAbort("Q3 plugin not loaded, cannot connect to q3 servers without it.\n");
return; return;
} }
#endif #endif
@ -926,7 +935,7 @@ char *CL_TryingToConnect(void)
return cls.servername; return cls.servername;
} }
#ifdef NQPROT #if defined(NQPROT) && defined(HAVE_SERVER)
static void CL_NullReadPacket(void) static void CL_NullReadPacket(void)
{ //just drop it all { //just drop it all
} }
@ -942,9 +951,7 @@ struct resolvectx_s
}; };
static void CL_ResolvedServer(void *vctx, void *data, size_t a, size_t b) static void CL_ResolvedServer(void *vctx, void *data, size_t a, size_t b)
{ {
#ifdef HAVE_DTLS
size_t i; size_t i;
#endif
struct resolvectx_s *ctx = vctx; struct resolvectx_s *ctx = vctx;
//something screwed us over... //something screwed us over...
@ -971,7 +978,7 @@ static void CL_ResolvedServer(void *vctx, void *data, size_t a, size_t b)
if (connectinfo.mode == CIM_Q2EONLY) if (connectinfo.mode == CIM_Q2EONLY)
{ {
for (i = 0; i < ctx->found; i++) for (i = 0; i < ctx->found; i++)
{ //if we've already established a dtls connection, stick with it { //if we've already established a dtls connection, stick with it, otherwise 'upgrade' from udp to 'kexlan' transport layer.
if (ctx->adr[i].prot == NP_DGRAM) if (ctx->adr[i].prot == NP_DGRAM)
ctx->adr[i].prot = NP_KEXLAN; ctx->adr[i].prot = NP_KEXLAN;
} }
@ -986,8 +993,12 @@ static void CL_ResolvedServer(void *vctx, void *data, size_t a, size_t b)
static void CL_ResolveServer(void *vctx, void *data, size_t a, size_t b) static void CL_ResolveServer(void *vctx, void *data, size_t a, size_t b)
{ {
struct resolvectx_s *ctx = vctx; struct resolvectx_s *ctx = vctx;
//stupid logic for targ@prox2@prox1 chaining. just disable it if there's weird ws:// or whatever in there.
//FIXME: really shouldn't be in there
const char *res = strrchr(ctx->servername, '/');
const char *host = strrchr(ctx->servername+1, '@'); const char *host = strrchr(ctx->servername+1, '@');
if (host) if (host && !res)
host++; host++;
else else
host = ctx->servername; host = ctx->servername;
@ -1464,7 +1475,9 @@ void CL_CheckForResend (void)
if (contype & 1) if (contype & 1)
{ {
char tmp[256]; char tmp[256];
//vanilla: Q_snprintfz (data, sizeof(data), "%c%c%c%cgetchallenge\n", 255, 255, 255, 255); if (strrchr(cls.servername, '@')) //if we're apparently using qwfwd then strictly adhere to vanilla's protocol so that qwfwd does not bug out. this will pollute gamedirs if stuff starts autodownloading from the wrong type of server, and probably show up vanilla-vs-rerelease glitches everywhere..
Q_snprintfz (data, sizeof(data), "%c%c%c%cgetchallenge\n", 255, 255, 255, 255);
else
Q_snprintfz (data, sizeof(data), "%c%c%c%cgetchallenge %i %s\n", 255, 255, 255, 255, connectinfo.clchallenge, COM_QuotedString(com_protocolname.string, tmp, sizeof(tmp), false)); Q_snprintfz (data, sizeof(data), "%c%c%c%cgetchallenge %i %s\n", 255, 255, 255, 255, connectinfo.clchallenge, COM_QuotedString(com_protocolname.string, tmp, sizeof(tmp), false));
switch(NET_SendPacket (cls.sockets, strlen(data), data, to)) switch(NET_SendPacket (cls.sockets, strlen(data), data, to))
{ {
@ -1511,7 +1524,7 @@ void CL_CheckForResend (void)
if (*e) if (*e)
pwd = CalcHashInt(&hash_md4, password.string, strlen(password.string)); pwd = CalcHashInt(&hash_md4, password.string, strlen(password.string));
} }
MSG_WriteByte(&sb, 1); /*'mod'*/ MSG_WriteByte(&sb, MOD_PROQUAKE); /*'mod'*/
MSG_WriteByte(&sb, 34); /*'mod' version*/ MSG_WriteByte(&sb, 34); /*'mod' version*/
MSG_WriteByte(&sb, 0); /*flags*/ MSG_WriteByte(&sb, 0); /*flags*/
MSG_WriteLong(&sb, pwd); /*password*/ MSG_WriteLong(&sb, pwd); /*password*/
@ -1584,9 +1597,9 @@ static void CL_BeginServerConnect(char *host, int port, qboolean noproxy, enum c
//the scheme is either a network scheme in which case we use it directly, or a game-specific scheme. //the scheme is either a network scheme in which case we use it directly, or a game-specific scheme.
scheme = NET_IsURIScheme(schemestart); scheme = NET_IsURIScheme(schemestart);
if (scheme->prot == NP_INVALID) if (scheme && scheme->prot == NP_INVALID)
scheme = NULL; //qw:// or q3:// something that's just noise here. scheme = NULL; //qw:// or q3:// something that's just noise here.
if (scheme->flags&URISCHEME_NEEDSRESOURCE) if (scheme && scheme->flags&URISCHEME_NEEDSRESOURCE)
{ {
Q_strncpyz (cls.servername, schemestart, sizeof(cls.servername)); //oh. will probably be okay then Q_strncpyz (cls.servername, schemestart, sizeof(cls.servername)); //oh. will probably be okay then
arglist = NULL; arglist = NULL;
@ -1612,6 +1625,13 @@ static void CL_BeginServerConnect(char *host, int port, qboolean noproxy, enum c
Con_Printf("Ignoring 'join'\n"); Con_Printf("Ignoring 'join'\n");
memmove(sl, sl+5, strlen(sl+5)+1); memmove(sl, sl+5, strlen(sl+5)+1);
} }
else if (!strncmp(sl, "/qtvplay", 5))
{
char buf[256];
*sl = 0;
Cmd_ExecuteString(va("qtvplay %s\n", COM_QuotedString(schemeend+3, buf,sizeof(buf), false)), RESTRICT_LOCAL);
return;
}
else if (!strncmp(sl, "/", 1) && (sl[1] == 0 || sl[1]=='?')) else if (!strncmp(sl, "/", 1) && (sl[1] == 0 || sl[1]=='?'))
{ {
//current spectator mode //current spectator mode
@ -1649,6 +1669,7 @@ static void CL_BeginServerConnect(char *host, int port, qboolean noproxy, enum c
connectinfo.protocol = CP_UNKNOWN; connectinfo.protocol = CP_UNKNOWN;
connectinfo.mode = mode; connectinfo.mode = mode;
connectinfo.spec = spec; connectinfo.spec = spec;
connectinfo.clchallenge = rand()^(rand()<<16);
connectinfo.peercred.name = cls.servername; connectinfo.peercred.name = cls.servername;
if (arglist) if (arglist)
@ -1716,6 +1737,7 @@ void CL_BeginServerReconnect(void)
connectinfo.time = 0; connectinfo.time = 0;
connectinfo.tries = 0; //re-ensure routes. connectinfo.tries = 0; //re-ensure routes.
connectinfo.nextadr = 0; //should at least be consistent, other than packetloss. yay. connectinfo.nextadr = 0; //should at least be consistent, other than packetloss. yay.
connectinfo.clchallenge = rand()^(rand()<<16);
NET_InitClient(false); NET_InitClient(false);
} }
@ -1785,11 +1807,11 @@ static void CL_Connect_f (void)
server = Cmd_Argv (1); server = Cmd_Argv (1);
server = strcpy(alloca(strlen(server)+1), server); server = strcpy(alloca(strlen(server)+1), server);
#ifdef HAVE_SERVER /*#ifdef HAVE_SERVER
if (sv.state == ss_clustermode) if (sv.state == ss_clustermode)
CL_Disconnect (NULL); CL_Disconnect (NULL);
else else
#endif #endif*/
CL_Disconnect_f (); CL_Disconnect_f ();
CL_BeginServerConnect(server, 0, false, CIM_DEFAULT, CIS_DEFAULT); CL_BeginServerConnect(server, 0, false, CIM_DEFAULT, CIS_DEFAULT);
@ -1821,11 +1843,11 @@ static void CL_ConnectBestRoute_f (void)
else else
Con_TPrintf ("Routing table favours chaining through %i proxies (%ims vs %ims)\n", proxies, chainedcost, directcost); Con_TPrintf ("Routing table favours chaining through %i proxies (%ims vs %ims)\n", proxies, chainedcost, directcost);
#ifdef HAVE_SERVER /*#ifdef HAVE_SERVER
if (sv.state == ss_clustermode) if (sv.state == ss_clustermode)
CL_Disconnect (NULL); CL_Disconnect (NULL);
else else
#endif #endif*/
CL_Disconnect_f (); CL_Disconnect_f ();
CL_BeginServerConnect(server, 0, true, CIM_DEFAULT, CIS_DEFAULT); CL_BeginServerConnect(server, 0, true, CIM_DEFAULT, CIS_DEFAULT);
} }
@ -2265,6 +2287,17 @@ void CL_ClearState (qboolean gamestart)
if (cl.particle_csname[i]) if (cl.particle_csname[i])
free(cl.particle_csname[i]); free(cl.particle_csname[i]);
} }
for (i = 0; i < countof(cl.model_name); i++)
if (cl.model_name[i])
BZ_Free(cl.model_name[i]);
#ifdef HAVE_LEGACY
for (i = 0; i < countof(cl.model_name_vwep); i++)
if (cl.model_name_vwep[i])
BZ_Free(cl.model_name_vwep[i]);
#endif
for (i = 0; i < countof(cl.sound_name); i++)
if (cl.sound_name[i])
BZ_Free(cl.sound_name[i]);
#ifdef Q2CLIENT #ifdef Q2CLIENT
for (i = 0; i < Q2MAX_IMAGES; i++) for (i = 0; i < Q2MAX_IMAGES; i++)
if (cl.image_name[i]) if (cl.image_name[i])
@ -2521,6 +2554,13 @@ void CL_Disconnect (const char *reason)
cls.findtrack = false; cls.findtrack = false;
cls.realserverip.type = NA_INVALID; cls.realserverip.type = NA_INVALID;
while (cls.qtvviewers)
{
struct qtvviewers_s *v = cls.qtvviewers;
cls.qtvviewers = v->next;
Z_Free(v);
}
#ifdef TCPCONNECT #ifdef TCPCONNECT
//disconnects it, without disconnecting the others. //disconnects it, without disconnecting the others.
FTENET_AddToCollection(cls.sockets, "conn", NULL, NA_INVALID, NP_DGRAM); FTENET_AddToCollection(cls.sockets, "conn", NULL, NA_INVALID, NP_DGRAM);
@ -2618,6 +2658,7 @@ void CL_Users_f (void)
{ {
int i; int i;
int c; int c;
struct qtvviewers_s *v;
c = 0; c = 0;
Con_TPrintf ("userid frags name\n"); Con_TPrintf ("userid frags name\n");
@ -2631,6 +2672,11 @@ void CL_Users_f (void)
} }
} }
for (v = cls.qtvviewers; v; v = v->next)
{
Con_Printf ("%6s %4s ^[%s^]\n", "", "-", v->name);
}
Con_TPrintf ("%i total users\n", c); Con_TPrintf ("%i total users\n", c);
} }
@ -2927,7 +2973,7 @@ void CL_PakDownloads(int mode)
mode&4 download even packages that are not referenced. mode&4 download even packages that are not referenced.
*/ */
char local[256]; char local[256];
char *pname; char *pname, *sep;
char *s = cl.serverpackhashes; char *s = cl.serverpackhashes;
int i; int i;
@ -2946,6 +2992,10 @@ void CL_PakDownloads(int mode)
else if (!(mode & 4)) else if (!(mode & 4))
continue; continue;
sep = strchr(pname, '/');
if (!sep || strchr(sep+1, '/'))
continue; //don't try downloading weird ones here... paks inside paks is screwy stuff!
if ((mode&3) != 2) if ((mode&3) != 2)
{ {
/*if we already have such a file, this is a no-op*/ /*if we already have such a file, this is a no-op*/
@ -3773,6 +3823,7 @@ void CL_Reconnect_f (void)
static void CL_ConnectionlessPacket_Connection(char *tokens) static void CL_ConnectionlessPacket_Connection(char *tokens)
{ {
unsigned int ncflags;
int qportsize = -1; int qportsize = -1;
if (net_from.type == NA_INVALID) if (net_from.type == NA_INVALID)
return; //I've found a qizmo demo that contains one of these. its best left ignored. return; //I've found a qizmo demo that contains one of these. its best left ignored.
@ -3848,19 +3899,16 @@ static void CL_ConnectionlessPacket_Connection(char *tokens)
cls.fteprotocolextensions2 = connectinfo.ext.fte2; cls.fteprotocolextensions2 = connectinfo.ext.fte2;
cls.ezprotocolextensions1 = connectinfo.ext.ez1; cls.ezprotocolextensions1 = connectinfo.ext.ez1;
cls.challenge = connectinfo.challenge; cls.challenge = connectinfo.challenge;
Netchan_Setup (NS_CLIENT, &cls.netchan, &net_from, connectinfo.qport); ncflags = NCF_CLIENT;
if (connectinfo.ext.mtu)
ncflags |= NCF_FRAGABLE;
if (connectinfo.ext.fte2&PEXT2_STUNAWARE)
ncflags |= NCF_STUNAWARE;
Netchan_Setup (ncflags, &cls.netchan, &net_from, connectinfo.qport, connectinfo.ext.mtu);
cls.protocol_q2 = (cls.protocol == CP_QUAKE2)?connectinfo.subprotocol:0; cls.protocol_q2 = (cls.protocol == CP_QUAKE2)?connectinfo.subprotocol:0;
if (qportsize>=0) if (qportsize>=0)
cls.netchan.qportsize = qportsize; cls.netchan.qportsize = qportsize;
cls.netchan.pext_fragmentation = connectinfo.ext.mtu?true:false;
cls.netchan.pext_stunaware = !!(connectinfo.ext.fte2&PEXT2_STUNAWARE);
if (connectinfo.ext.mtu >= 64)
{
cls.netchan.mtu = connectinfo.ext.mtu;
cls.netchan.message.maxsize = sizeof(cls.netchan.message_buf);
}
else
cls.netchan.mtu = MAX_QWMSGLEN;
#ifdef HUFFNETWORK #ifdef HUFFNETWORK
cls.netchan.compresstable = Huff_CompressionCRC(connectinfo.ext.compresscrc); cls.netchan.compresstable = Huff_CompressionCRC(connectinfo.ext.compresscrc);
#else #else
@ -4069,7 +4117,7 @@ void CL_ConnectionlessPacket (void)
if (!strcmp(com_token, "hallengeResponse")) if (!strcmp(com_token, "hallengeResponse"))
{ {
/*Quake3*/ /*Quake3 - "\xff\xff\xff\xffchallengeResponse challenge [clchallenge protover]" (no \n)*/
#ifdef Q3CLIENT #ifdef Q3CLIENT
if (connectinfo.protocol == CP_QUAKE3 || connectinfo.protocol == CP_UNKNOWN) if (connectinfo.protocol == CP_QUAKE3 || connectinfo.protocol == CP_UNKNOWN)
{ {
@ -4262,12 +4310,12 @@ void CL_ConnectionlessPacket (void)
#ifdef HAVE_DTLS #ifdef HAVE_DTLS
if ((candtls && net_enable_dtls.ival) && net_from.prot == NP_DGRAM && (net_enable_dtls.ival>1 || candtls > 1) && !NET_IsEncrypted(&net_from)) if ((candtls && net_enable_dtls.ival) && net_from.prot == NP_DGRAM && (net_enable_dtls.ival>1 || candtls > 1) && !NET_IsEncrypted(&net_from))
{ {
//c2s getchallenge <no client details //c2s getchallenge <no client details, only leaks that its quakelike, something you can maybe guess from port numbers>
//s2c c%u\0DTLS=$candtls <may leak server details> //s2c c%u\0DTLS=$candtls <may leak server details>
//<<YOU ARE HERE>> //<<YOU ARE HERE>>
//c2s dtlsconnect %u [REALTARGET] <FIXME: target server is plain text, not entirely unlike tls1.2, but still worse than a vpn and could be improved> //c2s dtlsconnect %u [REALTARGET] <FIXME: target server is plain text, not entirely unlike tls1.2, but still worse than a vpn and could be improved>
//s2c dtlsopened <no details at all, other than that the server is now willing to accept dtls handshakes etc> //s2c dtlsopened <no details at all, other than that the server is now willing to accept dtls handshakes etc>
//c2s DTLS(getchallenge) //c2s DTLS(getchallenge) <start here if you're using dtls:// scheme>
//DTLS(etc) //DTLS(etc)
//NOTE: the dtlsconnect/dtlsopened parts are redundant and the non-dtls parts are now entirely optional (and should be skipped if the client requries/knows the server supports dtls) //NOTE: the dtlsconnect/dtlsopened parts are redundant and the non-dtls parts are now entirely optional (and should be skipped if the client requries/knows the server supports dtls)
@ -4284,7 +4332,7 @@ void CL_ConnectionlessPacket (void)
char *pkt; char *pkt;
//qwfwd proxy routing. it doesn't support it yet, but hey, if its willing to forward the dtls packets its all good. //qwfwd proxy routing. it doesn't support it yet, but hey, if its willing to forward the dtls packets its all good.
char *at; char *at;
if ((at = strrchr(cls.servername, '@'))) if ((at = strrchr(cls.servername, '@')) && !strchr(cls.servername, '/'))
{ {
*at = 0; *at = 0;
pkt = va("%c%c%c%c""dtlsconnect %i %s", 255, 255, 255, 255, connectinfo.challenge, cls.servername); pkt = va("%c%c%c%c""dtlsconnect %i %s", 255, 255, 255, 255, connectinfo.challenge, cls.servername);
@ -4391,7 +4439,7 @@ void CL_ConnectionlessPacket (void)
} }
Validation_Apply_Ruleset(); Validation_Apply_Ruleset();
Netchan_Setup(NS_CLIENT, &cls.netchan, &net_from, connectinfo.qport); Netchan_Setup(NCF_CLIENT, &cls.netchan, &net_from, connectinfo.qport, 0);
CL_ParseEstablished(); CL_ParseEstablished();
cls.netchan.isnqprotocol = true; cls.netchan.isnqprotocol = true;
@ -4674,7 +4722,7 @@ void CLNQ_ConnectionlessPacket(void)
cls.fteprotocolextensions = connectinfo.ext.fte1; cls.fteprotocolextensions = connectinfo.ext.fte1;
cls.fteprotocolextensions2 = connectinfo.ext.fte2; cls.fteprotocolextensions2 = connectinfo.ext.fte2;
cls.ezprotocolextensions1 = connectinfo.ext.ez1; cls.ezprotocolextensions1 = connectinfo.ext.ez1;
Netchan_Setup (NS_CLIENT, &cls.netchan, &net_from, connectinfo.qport); Netchan_Setup (NCF_CLIENT, &cls.netchan, &net_from, connectinfo.qport, 0);
CL_ParseEstablished(); CL_ParseEstablished();
cls.netchan.isnqprotocol = true; cls.netchan.isnqprotocol = true;
cls.netchan.compresstable = NULL; cls.netchan.compresstable = NULL;
@ -4767,7 +4815,7 @@ void CL_ReadPacket(void)
return; //ignore it. We arn't connected. return; //ignore it. We arn't connected.
} }
if (net_message.cursize < 6 && (cls.demoplayback != DPB_MVD && cls.demoplayback != DPB_EZTV)) //MVDs don't have the whole sequence header thing going on if (net_message.cursize < 6 && cls.demoplayback != DPB_MVD) //MVDs don't have the whole sequence header thing going on
{ {
char adr[MAX_ADR_SIZE]; char adr[MAX_ADR_SIZE];
if (net_message.cursize == 1 && net_message.data[0] == A2A_ACK) if (net_message.cursize == 1 && net_message.data[0] == A2A_ACK)
@ -4791,7 +4839,7 @@ void CL_ReadPacket(void)
return; return;
} }
if (cls.netchan.pext_stunaware) //should be safe to do this here. if (cls.netchan.flags&NCF_STUNAWARE) //should be safe to do this here.
if (NET_WasSpecialPacket(cls.sockets)) if (NET_WasSpecialPacket(cls.sockets))
return; return;
@ -4836,7 +4884,7 @@ void CL_ReadPacket(void)
#endif #endif
break; break;
case CP_QUAKEWORLD: case CP_QUAKEWORLD:
if (cls.demoplayback == DPB_MVD || cls.demoplayback == DPB_EZTV) if (cls.demoplayback == DPB_MVD)
{ {
MSG_BeginReading(&net_message, cls.netchan.netprim); MSG_BeginReading(&net_message, cls.netchan.netprim);
cls.netchan.last_received = realtime; cls.netchan.last_received = realtime;
@ -4891,7 +4939,7 @@ void CL_ReadPackets (void)
} }
} }
if (cls.demoplayback == DPB_MVD || cls.demoplayback == DPB_EZTV) if (cls.demoplayback == DPB_MVD)
{ {
CL_MVDUpdateSpectator(); CL_MVDUpdateSpectator();
} }
@ -4908,7 +4956,7 @@ qboolean CL_AllowArbitaryDownload(const char *oldname, const char *localfile)
strstr(localfile, "\\") || strstr(localfile, "..") || strstr(localfile, "./") || strstr(localfile, ":") || strstr(localfile, "//") || //certain path patterns are just bad strstr(localfile, "\\") || strstr(localfile, "..") || strstr(localfile, "./") || strstr(localfile, ":") || strstr(localfile, "//") || //certain path patterns are just bad
Q_strcasestr(localfile, ".qvm") || Q_strcasestr(localfile, ".dll") || Q_strcasestr(localfile, ".so") || Q_strcasestr(localfile, ".dylib")) //disallow any native code Q_strcasestr(localfile, ".qvm") || Q_strcasestr(localfile, ".dll") || Q_strcasestr(localfile, ".so") || Q_strcasestr(localfile, ".dylib")) //disallow any native code
{ //yes, I know the user can use a different progs from the one that is specified. If you leave it blank there will be no problem. (server isn't allowed to stuff progs cvar) { //yes, I know the user can use a different progs from the one that is specified. If you leave it blank there will be no problem. (server isn't allowed to stuff progs cvar)
Con_Printf("Ignoring arbitary download to \"%s\" due to possible security risk\n", localfile); Con_Printf("Ignoring arbitrary download to \"%s\" due to possible security risk\n", localfile);
return false; return false;
} }
allow = cl_download_redirection.ival; allow = cl_download_redirection.ival;
@ -4941,10 +4989,12 @@ static void CL_Curl_f(void)
int i, argc = Cmd_Argc(); int i, argc = Cmd_Argc();
const char *arg, *gamedir, *localterse/*no dlcache*/= NULL; const char *arg, *gamedir, *localterse/*no dlcache*/= NULL;
char localname[MAX_QPATH]; char localname[MAX_QPATH];
char localnametmp[MAX_QPATH];
int usage = 0; int usage = 0;
qboolean alreadyhave = false; qboolean alreadyhave = false;
extern char *cl_dp_packagenames; extern char *cl_dp_packagenames;
unsigned int dlflags = DLLF_VERBOSE|DLLF_ALLOWWEB; unsigned int dlflags = DLLF_VERBOSE|DLLF_ALLOWWEB;
const char *ext;
if (argc < 2) if (argc < 2)
{ {
Con_Printf("%s: No args\n", Cmd_Argv(0)); Con_Printf("%s: No args\n", Cmd_Argv(0));
@ -5015,12 +5065,29 @@ static void CL_Curl_f(void)
} }
arg = Cmd_Argv(argc-1); arg = Cmd_Argv(argc-1);
if (!localterse) if (!localterse)
{
char *t;
localterse = strrchr(arg, '/');
if (!localterse)
localterse = arg;
t = strchr(localterse, '?');
if (t)
*t = 0;
if (t-localterse < countof(localnametmp))
{
memcpy(localnametmp, localterse, t-localterse);
localnametmp[t-localterse] = 0;
localterse = localnametmp;
}
}
if (!localterse)
{ {
//for compat, we should look for the last / and truncate on a ?. //for compat, we should look for the last / and truncate on a ?.
Con_Printf("%s: skipping download of %s, as the local name was not explicitly given\n", Cmd_Argv(0), arg); Con_Printf("%s: skipping download of %s, as the local name was not explicitly given\n", Cmd_Argv(0), arg);
return; return;
} }
if (usage == 1) ext = COM_GetFileExtension(localterse, NULL);
if (usage == 1 && (!strcmp(ext, ".pk3") || !strcmp(ext, ".pak")))
{ {
dlflags |= DLLF_NONGAME; dlflags |= DLLF_NONGAME;
gamedir = FS_GetGamedir(true); gamedir = FS_GetGamedir(true);
@ -5084,7 +5151,7 @@ void CL_Download_f (void)
if (!*localname) if (!*localname)
localname = url; localname = url;
if ((cls.state == ca_disconnected || cls.demoplayback) && cls.demoplayback != DPB_EZTV) if ((cls.state == ca_disconnected || cls.demoplayback) && !(cls.demoplayback == DPB_MVD && (cls.demoeztv_ext&EZTV_DOWNLOAD)))
{ {
Con_TPrintf ("Must be connected.\n"); Con_TPrintf ("Must be connected.\n");
return; return;
@ -5134,14 +5201,14 @@ void CL_DownloadSize_f(void)
size = Cmd_Argv(2); size = Cmd_Argv(2);
if (!strcmp(size, "e")) if (!strcmp(size, "e"))
{ {
Con_Printf("Download of \"%s\" failed. Not found.\n", rname); Con_Printf(CON_ERROR"Download of \"%s\" failed. Not found.\n", rname);
CL_DownloadFailed(rname, NULL, DLFAIL_SERVERFILE); CL_DownloadFailed(rname, NULL, DLFAIL_SERVERFILE);
} }
else if (!strcmp(size, "p")) else if (!strcmp(size, "p"))
{ {
if (cls.download && stricmp(cls.download->remotename, rname)) if (cls.download && stricmp(cls.download->remotename, rname))
{ {
Con_Printf("Download of \"%s\" failed. Not allowed.\n", rname); Con_Printf(CON_ERROR"Download of \"%s\" failed. Not allowed.\n", rname);
CL_DownloadFailed(rname, NULL, DLFAIL_SERVERCVAR); CL_DownloadFailed(rname, NULL, DLFAIL_SERVERCVAR);
} }
} }
@ -5359,21 +5426,11 @@ void CL_Fog_f(void)
#ifdef _DEBUG #ifdef _DEBUG
void CL_FreeSpace_f(void) void CL_FreeSpace_f(void)
{ {
char buf[32];
quint64_t freespace; quint64_t freespace;
const char *freepath = Cmd_Argv(1); const char *freepath = Cmd_Argv(1);
if (Sys_GetFreeDiskSpace(freepath, &freespace)) if (Sys_GetFreeDiskSpace(freepath, &freespace))
{ Con_Printf("%s: %s available\n", freepath, FS_AbbreviateSize(buf,sizeof(buf),freespace));
if (freespace > 512.0*1024*1024*1024)
Con_Printf("%s: %g tb available\n", freepath, freespace/(1024.0*1024*1024*1024));
else if (freespace > 512.0*1024*1024)
Con_Printf("%s: %g gb available\n", freepath, freespace/(1024.0*1024*1024));
else if (freespace > 512.0*1024)
Con_Printf("%s: %g mb available\n", freepath, freespace/(1024.0*1024));
else if (freespace > 512.0)
Con_Printf("%s: %g kb available\n", freepath, freespace/1024.0);
else
Con_Printf("%s: %"PRIu64" bytes available\n", freepath, freespace);
}
else else
Con_Printf("%s: disk free not queryable\n", freepath); Con_Printf("%s: disk free not queryable\n", freepath);
} }
@ -5434,7 +5491,24 @@ void CL_Status_f(void)
if (cls.state) if (cls.state)
{ {
char cert[8192];
qbyte fp[DIGEST_MAXSIZE+1];
char b64[(DIGEST_MAXSIZE*4)/3+1];
if (NET_GetConnectionCertificate(cls.sockets, &cls.netchan.remote_address, QCERT_ISENCRYPTED, NULL, 0))
Q_strncpyz(b64, "<UNENCRYPTED>", sizeof(b64));
else
{
int sz = NET_GetConnectionCertificate(cls.sockets, &cls.netchan.remote_address, QCERT_PEERCERTIFICATE, cert, sizeof(cert));
if (sz<0)
Q_strncpyz(b64, "<UNAVAILABLE>", sizeof(b64));
else
{
sz = Base64_EncodeBlockURI(fp, CalcHash(&hash_certfp, fp,sizeof(fp), cert, sz), b64, sizeof(b64));
b64[sz] = 0;
}
}
Con_Printf("Server address : %s\n", NET_AdrToString(adr, sizeof(adr), &cls.netchan.remote_address)); //not relevent as a limit. Con_Printf("Server address : %s\n", NET_AdrToString(adr, sizeof(adr), &cls.netchan.remote_address)); //not relevent as a limit.
Con_Printf("Server cert fp : %s\n", b64); //not relevent as a limit.
switch(cls.protocol) switch(cls.protocol)
{ {
default: default:
@ -5466,6 +5540,9 @@ void CL_Status_f(void)
case CPNQ_BJP3: case CPNQ_BJP3:
Con_Printf("Network Protocol : BJP3\n"); Con_Printf("Network Protocol : BJP3\n");
break; break;
case CPNQ_H2MP:
Con_Printf("Network Protocol : H2MP\n");
break;
case CPNQ_FITZ666: case CPNQ_FITZ666:
Con_Printf("Network Protocol : FitzQuake\n"); Con_Printf("Network Protocol : FitzQuake\n");
break; break;
@ -5555,10 +5632,10 @@ void CL_Status_f(void)
count++; count++;
} }
Con_Printf("csqc entities : %i/%i/%i (mem: %.1f%%)\n", count, csqc_world.num_edicts, csqc_world.max_edicts, 100*(float)(csqc_world.progs->stringtablesize/(double)csqc_world.progs->stringtablemaxsize)); Con_Printf("csqc entities : %i/%i/%i (mem: %.1f%%)\n", count, csqc_world.num_edicts, csqc_world.max_edicts, 100*(float)(csqc_world.progs->stringtablesize/(double)csqc_world.progs->stringtablemaxsize));
for (count = 1; count < MAX_PRECACHE_MODELS; count++) for (count = 1; count < MAX_CSMODELS; count++)
if (!*cl.model_csqcname[count]) if (!*cl.model_csqcname[count])
break; break;
Con_Printf("csqc models : %i/%i\n", count, MAX_PRECACHE_MODELS); Con_Printf("csqc models : %i/%i\n", count, MAX_CSMODELS);
Con_Printf("client sounds : %i\n", num_sfx); //there is a limit, its just private. :( Con_Printf("client sounds : %i\n", num_sfx); //there is a limit, its just private. :(
for (count = 1; count < MAX_SSPARTICLESPRE; count++) for (count = 1; count < MAX_SSPARTICLESPRE; count++)
@ -5678,7 +5755,8 @@ void CL_Init (void)
Cvar_Register (&cl_idlefps, cl_screengroup); Cvar_Register (&cl_idlefps, cl_screengroup);
Cvar_Register (&cl_yieldcpu, cl_screengroup); Cvar_Register (&cl_yieldcpu, cl_screengroup);
Cvar_Register (&cl_timeout, cl_controlgroup); Cvar_Register (&cl_timeout, cl_controlgroup);
Cvar_Register (&cl_forcevrui, cl_controlgroup); Cvar_Register (&cl_vrui_force, cl_controlgroup);
Cvar_Register (&cl_vrui_lock, cl_controlgroup);
Cvar_Register (&lookspring, cl_inputgroup); Cvar_Register (&lookspring, cl_inputgroup);
Cvar_Register (&lookstrafe, cl_inputgroup); Cvar_Register (&lookstrafe, cl_inputgroup);
Cvar_Register (&sensitivity, cl_inputgroup); Cvar_Register (&sensitivity, cl_inputgroup);
@ -5794,7 +5872,6 @@ void CL_Init (void)
Cvar_Register (&cl_threadedphysics, cl_controlgroup); Cvar_Register (&cl_threadedphysics, cl_controlgroup);
hud_tracking_show = Cvar_Get("hud_tracking_show", "1", 0, "statusbar"); hud_tracking_show = Cvar_Get("hud_tracking_show", "1", 0, "statusbar");
hud_miniscores_show = Cvar_Get("hud_miniscores_show", "1", 0, "statusbar"); hud_miniscores_show = Cvar_Get("hud_miniscores_show", "1", 0, "statusbar");
Cvar_Register (&cl_download_mapsrc, cl_controlgroup);
Cvar_Register (&cl_dlemptyterminate, cl_controlgroup); Cvar_Register (&cl_dlemptyterminate, cl_controlgroup);
@ -5863,7 +5940,6 @@ void CL_Init (void)
Cmd_AddCommandAD ("connectbr", CL_ConnectBestRoute_f, CL_Connect_c, "connect address:port\nConnect to a qw server using the best route we can detect."); Cmd_AddCommandAD ("connectbr", CL_ConnectBestRoute_f, CL_Connect_c, "connect address:port\nConnect to a qw server using the best route we can detect.");
#endif #endif
Cmd_AddCommandAD("connect", CL_Connect_f, CL_Connect_c, "connect scheme://address:port\nConnect to a server. " Cmd_AddCommandAD("connect", CL_Connect_f, CL_Connect_c, "connect scheme://address:port\nConnect to a server. "
#if defined(FTE_TARGET_WEB) #if defined(FTE_TARGET_WEB)
"Use a scheme of rtc[s]://broker/gamename to connect via a webrtc broker." "Use a scheme of rtc[s]://broker/gamename to connect via a webrtc broker."
"Use a scheme of ws[s]://server to connect via websockets." "Use a scheme of ws[s]://server to connect via websockets."
@ -5896,16 +5972,22 @@ void CL_Init (void)
Cmd_AddCommandD ("cl_transfer", CL_Transfer_f, "Connect to a different server, disconnecting from the current server only when the new server replies."); Cmd_AddCommandD ("cl_transfer", CL_Transfer_f, "Connect to a different server, disconnecting from the current server only when the new server replies.");
#ifdef TCPCONNECT #ifdef TCPCONNECT
Cmd_AddCommandAD ("connecttcp", CL_TCPConnect_f, CL_Connect_c, "Connect to a server using the tcp:// prefix"); Cmd_AddCommandAD ("connecttcp", CL_TCPConnect_f, CL_Connect_c, "Connect to a server using the tcp:// prefix");
Cmd_AddCommandAD ("tcpconnect", CL_TCPConnect_f, CL_Connect_c, "Connect to a server using the tcp:// prefix");
#endif #endif
#ifdef IRCCONNECT #ifdef IRCCONNECT
Cmd_AddCommand ("connectirc", CL_IRCConnect_f); Cmd_AddCommand ("connectirc", CL_IRCConnect_f);
#endif #endif
#ifdef NQPROT #ifdef NQPROT
Cmd_AddCommandD ("connectnq", CLNQ_Connect_f, "Connects to the specified server, defaulting to port "STRINGIFY(PORT_NQSERVER)". Also disables QW/Q2/Q3/DP handshakes preventing them from being favoured, so should only be used when you actually want NQ protocols specifically."); Cmd_AddCommandD ("connectnq", CLNQ_Connect_f, "Connects to the specified server, defaulting to port "STRINGIFY(PORT_NQSERVER)". Also disables QW/Q2/Q3/DP handshakes preventing them from being favoured, so should only be used when you actually want NQ protocols specifically.");
#ifdef HAVE_DTLS
Cmd_AddCommandD ("connectqe", CLNQ_Connect_f, "Connects to the specified server, defaulting to port "STRINGIFY(PORT_NQSERVER)". Also forces the use of DTLS and QE-specific handshakes. You will also need to ensure the dtls_psk_* cvars are set properly or the server will refuse the connection."); Cmd_AddCommandD ("connectqe", CLNQ_Connect_f, "Connects to the specified server, defaulting to port "STRINGIFY(PORT_NQSERVER)". Also forces the use of DTLS and QE-specific handshakes. You will also need to ensure the dtls_psk_* cvars are set properly or the server will refuse the connection.");
#endif #endif
#endif
#ifdef Q2CLIENT #ifdef Q2CLIENT
Cmd_AddCommandD ("connectq2e", CLQ2E_Connect_f, "Connects to the specified server, defaulting to port "STRINGIFY(PORT_Q2ESERVER)"."); Cmd_AddCommandD ("connectq2e", CLQ2E_Connect_f, "Connects to the specified server, defaulting to port "STRINGIFY(PORT_Q2EXSERVER)".");
#endif
#ifdef HAVE_LEGACY
Cmd_AddCommandAD("qwurl", CL_Connect_f, CL_Connect_c, "For compat with ezquake.");
#endif #endif
Cmd_AddCommand ("reconnect", CL_Reconnect_f); Cmd_AddCommand ("reconnect", CL_Reconnect_f);
Cmd_AddCommandAD ("join", CL_Join_f, CL_Connect_c, "Switches away from spectator mode, optionally connecting to a different server."); Cmd_AddCommandAD ("join", CL_Join_f, CL_Connect_c, "Switches away from spectator mode, optionally connecting to a different server.");
@ -5924,7 +6006,7 @@ void CL_Init (void)
Cmd_AddCommandAD ("color", CL_Color_f, CL_Color_c, NULL); Cmd_AddCommandAD ("color", CL_Color_f, CL_Color_c, NULL);
#if defined(NQPROT) && defined(HAVE_LEGACY) #if defined(NQPROT) && defined(HAVE_LEGACY)
Cmd_AddCommand ("curl", CL_Curl_f); Cmd_AddCommandD ("curl", CL_Curl_f, "For use by xonotic.");
#endif #endif
Cmd_AddCommand ("download", CL_Download_f); Cmd_AddCommand ("download", CL_Download_f);
Cmd_AddCommandD ("dlsize", CL_DownloadSize_f, "For internal use"); Cmd_AddCommandD ("dlsize", CL_DownloadSize_f, "For internal use");
@ -6074,7 +6156,7 @@ void Host_WriteConfiguration (void)
f = FS_OpenVFS(savename, "wb", FS_GAMEONLY); f = FS_OpenVFS(savename, "wb", FS_GAMEONLY);
if (!f) if (!f)
{ {
FS_NativePath(savename, FS_GAMEONLY, sysname, sizeof(sysname)); FS_DisplayPath(savename, FS_GAMEONLY, sysname, sizeof(sysname));
Con_TPrintf (CON_ERROR "Couldn't write %s.\n", sysname); Con_TPrintf (CON_ERROR "Couldn't write %s.\n", sysname);
return; return;
} }
@ -6084,7 +6166,7 @@ void Host_WriteConfiguration (void)
VFS_CLOSE (f); VFS_CLOSE (f);
FS_NativePath(savename, FS_GAMEONLY, sysname, sizeof(sysname)); FS_DisplayPath(savename, FS_GAMEONLY, sysname, sizeof(sysname));
Con_Printf("Wrote %s\n", savename); Con_Printf("Wrote %s\n", savename);
} }
} }
@ -6118,15 +6200,6 @@ qboolean Host_SimulationTime(float time)
} }
#endif #endif
void Host_RunFileNotify(struct dl_download *dl)
{
if (dl->file)
{
Host_RunFile(dl->url, strlen(dl->url), dl->file);
dl->file = NULL;
}
}
#include "fs.h" #include "fs.h"
#define HRF_OVERWRITE (1<<0) #define HRF_OVERWRITE (1<<0)
#define HRF_NOOVERWRITE (1<<1) #define HRF_NOOVERWRITE (1<<1)
@ -6136,7 +6209,7 @@ void Host_RunFileNotify(struct dl_download *dl)
#define HRF_OPENED (1<<4) #define HRF_OPENED (1<<4)
#define HRF_DOWNLOADED (1<<5) //file was actually downloaded, and not from the local system #define HRF_DOWNLOADED (1<<5) //file was actually downloaded, and not from the local system
#define HRF_WAITING (1<<6) //file looks important enough that we should wait for it to start to download or something before we try doing other stuff. #define HRF_WAITING (1<<6) //file looks important enough that we should wait for it to start to download or something before we try doing other stuff.
// (1<<7) #define HRF_DECOMPRESS (1<<7) //need to degzip it, which prevents streaming.
#define HRF_DEMO_MVD (1<<8) #define HRF_DEMO_MVD (1<<8)
#define HRF_DEMO_QWD (1<<9) #define HRF_DEMO_QWD (1<<9)
@ -6165,7 +6238,7 @@ typedef struct {
extern int waitingformanifest; extern int waitingformanifest;
void Host_DoRunFile(hrf_t *f); void Host_DoRunFile(hrf_t *f);
void CL_PlayDemoStream(vfsfile_t *file, char *filename, qboolean issyspath, int demotype, float bufferdelay); void CL_PlayDemoStream(vfsfile_t *file, char *filename, qboolean issyspath, int demotype, float bufferdelay, unsigned int eztv_ext);
void CL_ParseQTVDescriptor(vfsfile_t *f, const char *name); void CL_ParseQTVDescriptor(vfsfile_t *f, const char *name);
//guesses the file type based upon its file extension. mdl/md3/iqm distinctions are not important, so we can usually get away with this in the context of quake. //guesses the file type based upon its file extension. mdl/md3/iqm distinctions are not important, so we can usually get away with this in the context of quake.
@ -6201,13 +6274,13 @@ unsigned int Host_GuessFileType(const char *mimetype, const char *filename)
{ {
//demo formats //demo formats
{HRF_DEMO_QWD, "qwd"}, {HRF_DEMO_QWD, "qwd"},
{HRF_DEMO_QWD, "qwd.gz"}, {HRF_DEMO_QWD|HRF_DECOMPRESS, "qwd.gz"},
{HRF_DEMO_MVD, "mvd"}, {HRF_DEMO_MVD, "mvd"},
{HRF_DEMO_MVD, "mvd.gz"}, {HRF_DEMO_MVD|HRF_DECOMPRESS, "mvd.gz"},
{HRF_DEMO_DM2, "dm2"}, {HRF_DEMO_DM2, "dm2"},
{HRF_DEMO_DM2, "dm2.gz"}, {HRF_DEMO_DM2|HRF_DECOMPRESS, "dm2.gz"},
{HRF_DEMO_DEM, "dem"}, {HRF_DEMO_DEM, "dem"},
{HRF_DEMO_DEM, "dem.gz"}, {HRF_DEMO_DEM|HRF_DECOMPRESS, "dem.gz"},
{HRF_QTVINFO, "qtv"}, {HRF_QTVINFO, "qtv"},
//other stuff //other stuff
{HRF_MANIFEST, "fmf"}, {HRF_MANIFEST, "fmf"},
@ -6215,6 +6288,7 @@ unsigned int Host_GuessFileType(const char *mimetype, const char *filename)
{HRF_BSP, "map"}, {HRF_BSP, "map"},
{HRF_CONFIG, "cfg"}, {HRF_CONFIG, "cfg"},
{HRF_CONFIG, "rc"}, {HRF_CONFIG, "rc"},
{HRF_PACKAGE, "kpf"},
{HRF_PACKAGE, "pak"}, {HRF_PACKAGE, "pak"},
{HRF_PACKAGE, "pk3"}, {HRF_PACKAGE, "pk3"},
{HRF_PACKAGE, "pk4"}, {HRF_PACKAGE, "pk4"},
@ -6319,20 +6393,29 @@ qboolean Host_BeginFileDownload(struct dl_download *dl, char *mimetype)
} }
} }
#ifdef AVAIL_GZDEC
//seeking means we can rewind //seeking means we can rewind
if (f->flags & HRF_DECOMPRESS)
{ //if its a gzip, we'll probably need to decompress it ourselves... in case the server doesn't use content-encoding:gzip
//our demo playback should decompress it when its fin ally available.
dl->file = VFSPIPE_Open(1, true);
return true;
}
else
#endif
if (f->flags & HRF_DEMO_QWD) if (f->flags & HRF_DEMO_QWD)
CL_PlayDemoStream((dl->file = VFSPIPE_Open(2, true)), f->fname, true, DPB_QUAKEWORLD, 0); CL_PlayDemoStream((dl->file = VFSPIPE_Open(2, true)), f->fname, true, DPB_QUAKEWORLD, 0, 0);
else if (f->flags & HRF_DEMO_MVD) else if (f->flags & HRF_DEMO_MVD)
CL_PlayDemoStream((dl->file = VFSPIPE_Open(2, true)), f->fname, true, DPB_MVD, 0); CL_PlayDemoStream((dl->file = VFSPIPE_Open(2, true)), f->fname, true, DPB_MVD, 0, 0);
#ifdef Q2CLIENT #ifdef Q2CLIENT
else if (f->flags & HRF_DEMO_DM2) else if (f->flags & HRF_DEMO_DM2)
CL_PlayDemoStream((dl->file = VFSPIPE_Open(2, true)), f->fname, true, DPB_QUAKE2, 0); CL_PlayDemoStream((dl->file = VFSPIPE_Open(2, true)), f->fname, true, DPB_QUAKE2, 0, 0);
#endif #endif
#ifdef NQPROT #ifdef NQPROT
else if (f->flags & HRF_DEMO_DEM) else if (f->flags & HRF_DEMO_DEM)
{ //fixme: the demo code can't handle the cd track with streamed/missing-so-far writes. { //fixme: the demo code can't handle the cd track with streamed/missing-so-far writes.
dl->file = VFSPIPE_Open(1, true); //make sure the reader will be seekable, so we can rewind. dl->file = VFSPIPE_Open(1, true); //make sure the reader will be seekable, so we can rewind.
// CL_PlayDemoStream((dl->file = VFSPIPE_Open(2, true)), f->fname, DPB_NETQUAKE, 0); // CL_PlayDemoStream((dl->file = VFSPIPE_Open(2, true)), f->fname, DPB_NETQUAKE, 0, 0);
} }
#endif #endif
else if (f->flags & (HRF_MANIFEST | HRF_QTVINFO)) else if (f->flags & (HRF_MANIFEST | HRF_QTVINFO))
@ -6402,6 +6485,7 @@ static qboolean isurl(char *url)
#endif #endif
qboolean FS_FixupGamedirForExternalFile(char *input, char *filename, size_t fnamelen); qboolean FS_FixupGamedirForExternalFile(char *input, char *filename, size_t fnamelen);
void CL_PlayDemoFile(vfsfile_t *f, char *demoname, qboolean issyspath);
void Host_DoRunFile(hrf_t *f) void Host_DoRunFile(hrf_t *f)
{ {
@ -6466,7 +6550,7 @@ done:
//if we still don't know what it is, give up. //if we still don't know what it is, give up.
if (!(f->flags & HRF_FILETYPES)) if (!(f->flags & HRF_FILETYPES))
{ {
Con_Printf("Host_DoRunFile: unknown filetype\n"); Con_Printf("Host_DoRunFile: unknown filetype for \"%s\"\n", f->fname);
goto done; goto done;
} }
@ -6485,18 +6569,22 @@ done:
if (f->srcfile) if (f->srcfile)
{ {
VFS_SEEK(f->srcfile, 0); VFS_SEEK(f->srcfile, 0);
#ifdef AVAIL_GZDEC
f->srcfile = FS_DecompressGZip(f->srcfile, NULL);
#endif
if (f->flags & HRF_DEMO_QWD) if (f->flags & HRF_DEMO_QWD)
CL_PlayDemoStream(f->srcfile, f->fname, true, DPB_QUAKEWORLD, 0); CL_PlayDemoStream(f->srcfile, f->fname, true, DPB_QUAKEWORLD, 0, 0);
#ifdef Q2CLIENT #ifdef Q2CLIENT
else if (f->flags & HRF_DEMO_DM2) else if (f->flags & HRF_DEMO_DM2)
CL_PlayDemoStream(f->srcfile, f->fname, true, DPB_QUAKE2, 0); CL_PlayDemoStream(f->srcfile, f->fname, true, DPB_QUAKE2, 0, 0);
#endif #endif
#ifdef NQPROT #ifdef NQPROT
else if (f->flags & HRF_DEMO_DEM) else if (f->flags & HRF_DEMO_DEM)
CL_PlayDemoStream(f->srcfile, f->fname, true, DPB_NETQUAKE, 0); CL_PlayDemoFile(f->srcfile, f->fname, true); //should be able to handle the cd-track header.
#endif #endif
else //if (f->flags & HRF_DEMO_MVD) else //if (f->flags & HRF_DEMO_MVD)
CL_PlayDemoStream(f->srcfile, f->fname, true, DPB_MVD, 0); CL_PlayDemoStream(f->srcfile, f->fname, true, DPB_MVD, 0, 0);
f->srcfile = NULL; f->srcfile = NULL;
} }
else else
@ -6657,8 +6745,12 @@ done:
if (f->flags & HRF_PACKAGE) if (f->flags & HRF_PACKAGE)
{ {
#ifdef PACKAGEMANAGER #ifdef PACKAGEMANAGER
Z_Free(f->packageinfo); if (f->packageinfo)
Z_Free(f->packageinfo); //sucks that we have to do this again, to recompute the proper qname+qroot
Q_strncpyz(qname, COM_SkipPath(f->fname), sizeof(qname));
f->packageinfo = PM_GeneratePackageFromMeta(f->srcfile, qname,sizeof(qname), &qroot); f->packageinfo = PM_GeneratePackageFromMeta(f->srcfile, qname,sizeof(qname), &qroot);
if (!f->packageinfo)
goto done;
#endif #endif
} }
else if (f->flags & HRF_MANIFEST) else if (f->flags & HRF_MANIFEST)
@ -6718,6 +6810,9 @@ done:
} }
else if (isnew) else if (isnew)
{ {
if (f->packageinfo && strstr(f->packageinfo, "\nguessed"))
Menu_Prompt(Host_RunFilePrompted, f, va(localtext("File appears new.\nWould you like to install\n%s\n"CON_ERROR"File contains no metadata so will be installed to\n%s"), displayname, qname), "Install!", "", "Cancel", true);
else
Menu_Prompt(Host_RunFilePrompted, f, va(localtext("File appears new.\nWould you like to install\n%s\n"), displayname), "Install!", "", "Cancel", true); Menu_Prompt(Host_RunFilePrompted, f, va(localtext("File appears new.\nWould you like to install\n%s\n"), displayname), "Install!", "", "Cancel", true);
return; return;
} }
@ -6729,9 +6824,9 @@ done:
} }
else if (f->flags & HRF_OVERWRITE) else if (f->flags & HRF_OVERWRITE)
{ {
char buffer[8192]; char buffer[65536];
int len; int len;
f->dstfile = FS_OpenVFS(qname, "wb", qroot); f->dstfile = FS_OpenVFS(qname, (f->flags & HRF_PACKAGE)?"wbp":"wb", qroot);
if (f->dstfile) if (f->dstfile)
{ {
#ifdef FTE_TARGET_WEB #ifdef FTE_TARGET_WEB
@ -6753,9 +6848,12 @@ done:
#ifdef PACKAGEMANAGER #ifdef PACKAGEMANAGER
if (f->flags & HRF_PACKAGE) if (f->flags & HRF_PACKAGE)
PM_FileInstalled(COM_SkipPath(f->fname), qroot, f->packageinfo, true); PM_FileInstalled(qname, qroot, f->packageinfo, true);
#endif #endif
if (!strcmp(loadcommand, "fs_restart\n"))
FS_ReloadPackFiles();
else
Cbuf_AddText(loadcommand, RESTRICT_LOCAL); Cbuf_AddText(loadcommand, RESTRICT_LOCAL);
} }
@ -6779,6 +6877,8 @@ qboolean Host_RunFile(const char *fname, int nlen, vfsfile_t *file)
if (!Sys_ResolveFileURL(fname, nlen, utf8, sizeof(utf8))) if (!Sys_ResolveFileURL(fname, nlen, utf8, sizeof(utf8)))
{ {
Con_Printf("Cannot resolve file url\n"); Con_Printf("Cannot resolve file url\n");
if(file)
VFS_CLOSE(file);
return false; return false;
} }
fname = utf8; fname = utf8;
@ -6892,7 +6992,11 @@ qboolean Host_RunFile(const char *fname, int nlen, vfsfile_t *file)
if (file) if (file)
f->flags |= HRF_OPENED; f->flags |= HRF_OPENED;
Con_TPrintf("Opening external file: %s\n", f->fname); {
char dpath[MAX_OSPATH];
FS_DisplayPath(f->fname, FS_SYSTEM, dpath,sizeof(dpath));
Con_TPrintf("Opening external file: %s\n", dpath);
}
Host_DoRunFile(f); Host_DoRunFile(f);
return true; return true;
@ -6924,7 +7028,7 @@ double Host_Frame (double time)
qboolean idle; qboolean idle;
extern int r_blockvidrestart; extern int r_blockvidrestart;
static qboolean hadwork; static qboolean hadwork;
qboolean vrsync; unsigned int vrflags;
qboolean mustrenderbeforeread; qboolean mustrenderbeforeread;
RSpeedLocals(); RSpeedLocals();
@ -6934,7 +7038,7 @@ double Host_Frame (double time)
return 0; // something bad happened, or the server disconnected return 0; // something bad happened, or the server disconnected
} }
vrsync = vid.vr?vid.vr->SyncFrame(&time):false; //fiddle with frame timings vrflags = vid.vr?vid.vr->SyncFrame(&time):0; //fiddle with frame timings
newrealtime = Media_TweekCaptureFrameTime(realtime, time); //fiddle with time some more newrealtime = Media_TweekCaptureFrameTime(realtime, time); //fiddle with time some more
time = newrealtime - realtime; time = newrealtime - realtime;
@ -6978,7 +7082,7 @@ double Host_Frame (double time)
if (!cls.timedemo) if (!cls.timedemo)
CL_ReadPackets (); CL_ReadPackets ();
if (idle && cl_idlefps.value > 0 && !vrsync) if (idle && cl_idlefps.value > 0 && !(vrflags&VRF_OVERRIDEFRAMETIME))
{ {
double idlesec = 1.0 / cl_idlefps.value; double idlesec = 1.0 / cl_idlefps.value;
if (idlesec > 0.1) if (idlesec > 0.1)
@ -7053,7 +7157,7 @@ double Host_Frame (double time)
#ifdef HAVE_MEDIA_ENCODER #ifdef HAVE_MEDIA_ENCODER
&& Media_Capturing() != 2 && Media_Capturing() != 2
#endif #endif
&& !vrsync) && !(vrflags&VRF_OVERRIDEFRAMETIME))
{ {
spare = CL_FilterTime((realtime - oldrealtime)*1000, maxfps, 1.5, maxfpsignoreserver); spare = CL_FilterTime((realtime - oldrealtime)*1000, maxfps, 1.5, maxfpsignoreserver);
if (!spare) if (!spare)
@ -7128,7 +7232,7 @@ double Host_Frame (double time)
CL_UseIndepPhysics(cls.state != ca_disconnected && !!cl_threadedphysics.ival); //starts/stops the input frame thread. CL_UseIndepPhysics(cls.state != ca_disconnected && !!cl_threadedphysics.ival); //starts/stops the input frame thread.
cl.do_lerp_players = cl_lerp_players.ival || (cls.demoplayback==DPB_MVD || cls.demoplayback == DPB_EZTV) || (cls.demoplayback && !cl_nolerp.ival && !cls.timedemo); cl.do_lerp_players = cl_lerp_players.ival || cls.demoplayback==DPB_MVD || (cls.demoplayback && !cl_nolerp.ival && !cls.timedemo);
CL_AllowIndependantSendCmd(false); CL_AllowIndependantSendCmd(false);
mustrenderbeforeread = cls.protocol == CP_QUAKE2; //FIXME: quake2 MUST render a frame (or a later one) before it can read any acks from the server, otherwise its prediction screws up. I'm too lazy to rewrite that right now. mustrenderbeforeread = cls.protocol == CP_QUAKE2; //FIXME: quake2 MUST render a frame (or a later one) before it can read any acks from the server, otherwise its prediction screws up. I'm too lazy to rewrite that right now.
@ -7213,6 +7317,8 @@ double Host_Frame (double time)
Con_Printf("R2D_Flush was set outside of SCR_UpdateScreen\n"); Con_Printf("R2D_Flush was set outside of SCR_UpdateScreen\n");
} }
cl.mouseplayerview = NULL;
cl.mousenewtrackplayer = -1;
for (i = 0; i < MAX_SPLITS; i++) for (i = 0; i < MAX_SPLITS; i++)
{ {
cl.playerview[i].audio.defaulted = true; cl.playerview[i].audio.defaulted = true;
@ -7235,7 +7341,7 @@ double Host_Frame (double time)
{ {
RSpeedMark(); RSpeedMark();
vid.ime_allow = false; vid.ime_allow = false;
vrui.enabled = cl_forcevrui.ival; vrui.enabled |= cl_vrui_force.ival || (vrflags&VRF_UIACTIVE);
if (SCR_UpdateScreen()) if (SCR_UpdateScreen())
fps_count++; fps_count++;
if (R2D_Flush) if (R2D_Flush)
@ -7350,6 +7456,7 @@ void CL_StartCinematicOrMenu(void)
startuppending = true; startuppending = true;
return; return;
} }
Cmd_StuffCmds();
if (startuppending) if (startuppending)
{ {
if (startuppending == 2) //installer finished. if (startuppending == 2) //installer finished.
@ -7379,7 +7486,7 @@ void CL_StartCinematicOrMenu(void)
} }
if (!sv_state && !cls.demoinfile && !cls.state && !*cls.servername) if (!sv_state && !cls.demoinfile && !cls.state && !*cls.servername)
{ { //this is so default.cfg can define startup commands to exec if the engine starts up with no +connect / +map etc arg
TP_ExecTrigger("f_startup", true); TP_ExecTrigger("f_startup", true);
Cbuf_Execute (); Cbuf_Execute ();
} }
@ -7590,6 +7697,7 @@ static void Host_URIPrompt(void *ctx, promptbutton_t btn)
void Host_FinishLoading(void) void Host_FinishLoading(void)
{ {
int i;
extern qboolean r_forceheadless; extern qboolean r_forceheadless;
extern int r_blockvidrestart; extern int r_blockvidrestart;
if (r_blockvidrestart == true) if (r_blockvidrestart == true)
@ -7615,8 +7723,7 @@ void Host_FinishLoading(void)
Con_History_Load(); Con_History_Load();
Cmd_StuffCmds(); r_blockvidrestart = 2;
Cbuf_Execute ();
CL_ArgumentOverrides(); CL_ArgumentOverrides();
#ifdef HAVE_SERVER #ifdef HAVE_SERVER
@ -7641,14 +7748,15 @@ void Host_FinishLoading(void)
Sys_Quit(); Sys_Quit();
#endif #endif
r_blockvidrestart = 2;
Menu_Download_Update(); Menu_Download_Update();
#ifdef IPLOG #ifdef IPLOG
IPLog_Merge_File("iplog.txt"); IPLog_Merge_File("iplog.txt");
IPLog_Merge_File("iplog.dat"); //legacy crap, for compat with proquake IPLog_Merge_File("iplog.dat"); //legacy crap, for compat with proquake
#endif #endif
if (!PM_IsApplying())
Cmd_StuffCmds();
} }
if (PM_IsApplying() == 1) if (PM_IsApplying() == 1)
@ -7659,6 +7767,16 @@ void Host_FinishLoading(void)
return; return;
} }
//open any files specified on the commandline (urls, paks, models, I dunno).
for (i = 1; i < com_argc; i++)
{
if (!com_argv[i])
continue;
if (*com_argv[i] == '+' || *com_argv[i] == '-')
break;
Host_RunFile(com_argv[i], strlen(com_argv[i]), NULL);
}
//android may find that it has no renderer at various points. //android may find that it has no renderer at various points.
if (r_forceheadless) if (r_forceheadless)
return; return;

File diff suppressed because it is too large Load diff

View file

@ -638,7 +638,6 @@ static void QDECL Plug_GetServerInfoRaw(char *outptr, size_t outlen)
case DPB_NONE: case DPB_NONE:
break; break;
case DPB_MVD: case DPB_MVD:
case DPB_EZTV:
Q_strncatz(outptr, "\\demotype\\mvd", outlen); Q_strncatz(outptr, "\\demotype\\mvd", outlen);
break; break;
case DPB_QUAKEWORLD: case DPB_QUAKEWORLD:
@ -692,7 +691,6 @@ static size_t QDECL Plug_GetServerInfoBlob(const char *key, void *outptr, size_t
case DPB_NONE: case DPB_NONE:
break; break;
case DPB_MVD: case DPB_MVD:
case DPB_EZTV:
blob = "mvd"; blob = "mvd";
break; break;
case DPB_QUAKEWORLD: case DPB_QUAKEWORLD:
@ -888,7 +886,7 @@ static size_t QDECL Plug_GetTeamInfo(teamplayerinfo_t *players, size_t maxplayer
players->health = cl.playerview[seat].statsf[STAT_HEALTH]; players->health = cl.playerview[seat].statsf[STAT_HEALTH];
Q_strncpyz(players->nick, "", sizeof(players->nick)); Q_strncpyz(players->nick, "", sizeof(players->nick));
} }
else if (cls.demoplayback == DPB_MVD || cls.demoplayback == DPB_EZTV) else if (cls.demoplayback == DPB_MVD)
{ //scrape it from the mvd (assuming there is one... { //scrape it from the mvd (assuming there is one...
players->items = cl.players[i].stats[STAT_ITEMS]; players->items = cl.players[i].stats[STAT_ITEMS];
players->armor = cl.players[i].statsf[STAT_ARMOR]; players->armor = cl.players[i].statsf[STAT_ARMOR];

View file

@ -1018,7 +1018,7 @@ void CL_PredictMovePNum (int seat)
} }
#endif #endif
if (cl.paused && !(cls.demoplayback!=DPB_MVD && cls.demoplayback!=DPB_EZTV) && pv->cam_state == CAM_FREECAM) if (cl.paused && !(cls.demoplayback!=DPB_MVD) && pv->cam_state == CAM_FREECAM)
return; return;
if (!cl.validsequence) if (!cl.validsequence)
@ -1086,7 +1086,7 @@ void CL_PredictMovePNum (int seat)
nopred = true; nopred = true;
//these things also force-disable prediction //these things also force-disable prediction
if ((cls.demoplayback==DPB_MVD || cls.demoplayback == DPB_EZTV) || if (cls.demoplayback==DPB_MVD ||
cl.intermissionmode != IM_NONE || cl.paused || pv->pmovetype == PM_NONE || pv->pmovetype == PM_FREEZE || CAM_ISLOCKED(pv)) cl.intermissionmode != IM_NONE || cl.paused || pv->pmovetype == PM_NONE || pv->pmovetype == PM_FREEZE || CAM_ISLOCKED(pv))
{ {
nopred = true; nopred = true;
@ -1169,7 +1169,7 @@ void CL_PredictMovePNum (int seat)
} }
else else
{ {
if (cls.demoplayback==DPB_MVD || cls.demoplayback == DPB_EZTV) if (cls.demoplayback==DPB_MVD)
{ {
pv->nolocalplayer = false; pv->nolocalplayer = false;
from.state = &cl.inframes[cl.ackedmovesequence & UPDATE_MASK].playerstate[pv->playernum]; from.state = &cl.inframes[cl.ackedmovesequence & UPDATE_MASK].playerstate[pv->playernum];

View file

@ -2445,7 +2445,7 @@ void SCR_ImageName (const char *mapname)
strcpy(levelshotname, "levelshots/"); strcpy(levelshotname, "levelshots/");
COM_FileBase(mapname, levelshotname + strlen(levelshotname), sizeof(levelshotname)-strlen(levelshotname)); COM_FileBase(mapname, levelshotname + strlen(levelshotname), sizeof(levelshotname)-strlen(levelshotname));
if (qrenderer && scr_loadingscreen_aspect.ival >= 0) if (qrenderer && scr_loadingscreen_aspect.ival >= 0 && *mapname)
{ {
R_LoadHiResTexture(levelshotname, NULL, IF_NOWORKER|IF_UIPIC|IF_NOPICMIP|IF_NOMIPMAP|IF_CLAMP); R_LoadHiResTexture(levelshotname, NULL, IF_NOWORKER|IF_UIPIC|IF_NOPICMIP|IF_NOMIPMAP|IF_CLAMP);
@ -2624,7 +2624,7 @@ SCR_ScreenShot_f
*/ */
static void SCR_ScreenShot_f (void) static void SCR_ScreenShot_f (void)
{ {
char sysname[1024]; char displayname[1024];
char pcxname[MAX_QPATH]; char pcxname[MAX_QPATH];
int i; int i;
vfsfile_t *vfs; vfsfile_t *vfs;
@ -2672,7 +2672,7 @@ static void SCR_ScreenShot_f (void)
} }
} }
FS_NativePath(pcxname, FS_GAMEONLY, sysname, sizeof(sysname)); FS_DisplayPath(pcxname, FS_GAMEONLY, displayname, sizeof(displayname));
rgbbuffer = VID_GetRGBInfo(&stride, &width, &height, &fmt); rgbbuffer = VID_GetRGBInfo(&stride, &width, &height, &fmt);
if (rgbbuffer) if (rgbbuffer)
@ -2680,12 +2680,12 @@ static void SCR_ScreenShot_f (void)
//regarding metadata - we don't really know what's on the screen, so don't write something that may be wrong (eg: if there's only a console, don't claim that its a 360 image) //regarding metadata - we don't really know what's on the screen, so don't write something that may be wrong (eg: if there's only a console, don't claim that its a 360 image)
if (SCR_ScreenShot(pcxname, FS_GAMEONLY, &rgbbuffer, 1, stride, width, height, fmt, false)) if (SCR_ScreenShot(pcxname, FS_GAMEONLY, &rgbbuffer, 1, stride, width, height, fmt, false))
{ {
Con_Printf ("Wrote %s\n", sysname); Con_Printf ("Wrote %s\n", displayname);
BZ_Free(rgbbuffer); BZ_Free(rgbbuffer);
return; return;
} }
BZ_Free(rgbbuffer); BZ_Free(rgbbuffer);
Con_Printf (CON_ERROR "Couldn't write %s\n", sysname); Con_Printf (CON_ERROR "Couldn't write %s\n", displayname);
} }
else else
Con_Printf (CON_ERROR "Couldn't get colour buffer for screenshot\n"); Con_Printf (CON_ERROR "Couldn't get colour buffer for screenshot\n");
@ -2881,9 +2881,9 @@ static void SCR_ScreenShot_Mega_f(void)
{ {
if (SCR_ScreenShot(filename, FS_GAMEONLY, buffers, numbuffers, stride[0], width[0], height[0], fmt[0], true)) if (SCR_ScreenShot(filename, FS_GAMEONLY, buffers, numbuffers, stride[0], width[0], height[0], fmt[0], true))
{ {
char sysname[1024]; char displayname[1024];
FS_NativePath(filename, FS_GAMEONLY, sysname, sizeof(sysname)); FS_DisplayPath(filename, FS_GAMEONLY, displayname, sizeof(displayname));
Con_Printf ("Wrote %s\n", sysname); Con_Printf ("Wrote %s\n", displayname);
} }
} }
else else
@ -3040,9 +3040,9 @@ static void SCR_ScreenShot_VR_f(void)
Con_Printf ("Unable to capture suitable screen image\n"); Con_Printf ("Unable to capture suitable screen image\n");
else if (SCR_ScreenShot(filename, FS_GAMEONLY, buffer, (stereo?2:1), stride, width, height*(stereo?1:2), TF_BGRX32, true)) else if (SCR_ScreenShot(filename, FS_GAMEONLY, buffer, (stereo?2:1), stride, width, height*(stereo?1:2), TF_BGRX32, true))
{ {
char sysname[1024]; char displayname[1024];
FS_NativePath(filename, FS_GAMEONLY, sysname, sizeof(sysname)); FS_DisplayPath(filename, FS_GAMEONLY, displayname, sizeof(displayname));
Con_Printf ("Wrote %s\n", sysname); Con_Printf ("Wrote %s\n", displayname);
} }
BZ_Free(buffer[0]); BZ_Free(buffer[0]);
@ -3058,7 +3058,7 @@ void SCR_ScreenShot_Cubemap_f(void)
int stride, fbwidth, fbheight; int stride, fbwidth, fbheight;
uploadfmt_t fmt; uploadfmt_t fmt;
char filename[MAX_QPATH]; char filename[MAX_QPATH];
char sysname[1024]; char displayname[1024];
char *fname = Cmd_Argv(1); char *fname = Cmd_Argv(1);
int i, firstside; int i, firstside;
char olddrawviewmodel[64]; //hack, so we can set r_drawviewmodel to 0 so that it doesn't appear in screenshots even if the csqc is generating new data. char olddrawviewmodel[64]; //hack, so we can set r_drawviewmodel to 0 so that it doesn't appear in screenshots even if the csqc is generating new data.
@ -3189,8 +3189,8 @@ void SCR_ScreenShot_Cubemap_f(void)
{ {
if (Image_WriteDDSFile(filename, FS_GAMEONLY, &mips)) if (Image_WriteDDSFile(filename, FS_GAMEONLY, &mips))
{ {
FS_NativePath(filename, FS_GAMEONLY, sysname, sizeof(sysname)); FS_DisplayPath(filename, FS_GAMEONLY, displayname, sizeof(displayname));
Con_Printf ("Wrote %s\n", sysname); Con_Printf ("Wrote %s\n", displayname);
} }
} }
#endif #endif
@ -3199,8 +3199,8 @@ void SCR_ScreenShot_Cubemap_f(void)
{ {
if (Image_WriteKTXFile(filename, FS_GAMEONLY, &mips)) if (Image_WriteKTXFile(filename, FS_GAMEONLY, &mips))
{ {
FS_NativePath(filename, FS_GAMEONLY, sysname, sizeof(sysname)); FS_DisplayPath(filename, FS_GAMEONLY, displayname, sizeof(displayname));
Con_Printf ("Wrote %s\n", sysname); Con_Printf ("Wrote %s\n", displayname);
} }
} }
#endif #endif
@ -3249,13 +3249,13 @@ void SCR_ScreenShot_Cubemap_f(void)
if (SCR_ScreenShot(filename, FS_GAMEONLY, &buffer, 1, stride, fbwidth, fbheight, fmt, false)) if (SCR_ScreenShot(filename, FS_GAMEONLY, &buffer, 1, stride, fbwidth, fbheight, fmt, false))
{ {
FS_NativePath(filename, FS_GAMEONLY, sysname, sizeof(sysname)); FS_DisplayPath(filename, FS_GAMEONLY, displayname, sizeof(displayname));
Con_Printf ("Wrote %s\n", sysname); Con_Printf ("Wrote %s\n", displayname);
} }
else else
{ {
FS_NativePath(filename, FS_GAMEONLY, sysname, sizeof(sysname)); FS_DisplayPath(filename, FS_GAMEONLY, displayname, sizeof(displayname));
Con_Printf ("Failed to write %s\n", sysname); Con_Printf ("Failed to write %s\n", displayname);
} }
BZ_Free(buffer); BZ_Free(buffer);
} }

View file

@ -475,6 +475,7 @@ typedef struct
CPNQ_BJP1, //16bit models, strict 8bit sounds (otherwise based on nehahra) CPNQ_BJP1, //16bit models, strict 8bit sounds (otherwise based on nehahra)
CPNQ_BJP2, //16bit models, strict 16bit sounds CPNQ_BJP2, //16bit models, strict 16bit sounds
CPNQ_BJP3, //16bit models, flagged 16bit sounds, 8bit static sounds. CPNQ_BJP3, //16bit models, flagged 16bit sounds, 8bit static sounds.
CPNQ_H2MP, //urgh
CPNQ_FITZ666, /*and rmqe999 protocol, which is a strict superset*/ CPNQ_FITZ666, /*and rmqe999 protocol, which is a strict superset*/
CPNQ_DP5, CPNQ_DP5,
CPNQ_DP6, CPNQ_DP6,
@ -519,7 +520,7 @@ typedef struct
// entering a map (and clearing client_state_t) // entering a map (and clearing client_state_t)
vfsfile_t *demooutfile; vfsfile_t *demooutfile;
enum{DPB_NONE,DPB_QUAKEWORLD,DPB_MVD,DPB_EZTV, enum{DPB_NONE,DPB_QUAKEWORLD,DPB_MVD,
#ifdef NQPROT #ifdef NQPROT
DPB_NETQUAKE, DPB_NETQUAKE,
#endif #endif
@ -527,12 +528,16 @@ typedef struct
DPB_QUAKE2 DPB_QUAKE2
#endif #endif
} demoplayback, demorecording; } demoplayback, demorecording;
unsigned int demoeztv_ext;
#define EZTV_DOWNLOAD (1u<<0) //also changes modellist/soundlist stuff to keep things synced
#define EZTV_SETINFO (1u<<1) //proxy wants setinfo + ptrack commands
#define EZTV_QTVUSERLIST (1u<<2) //'//qul cmd id [name]' commands from proxy.
qboolean demohadkeyframe; //q2 needs to wait for a packet with a key frame, supposedly. qboolean demohadkeyframe; //q2 needs to wait for a packet with a key frame, supposedly.
qboolean demoseeking; qboolean demoseeking;
float demoseektime; float demoseektime;
int demotrack; int demotrack;
qboolean timedemo; qboolean timedemo;
char lastdemoname[MAX_OSPATH]; char lastdemoname[MAX_OSPATH]; //empty if is a qtv stream
qboolean lastdemowassystempath; qboolean lastdemowassystempath;
vfsfile_t *demoinfile; vfsfile_t *demoinfile;
float td_lastframe; // to meter out one message a frame float td_lastframe; // to meter out one message a frame
@ -540,6 +545,13 @@ typedef struct
float td_starttime; // realtime at second frame of timedemo float td_starttime; // realtime at second frame of timedemo
float demostarttime; // the time of the first frame, so we don't get weird results with qw demos float demostarttime; // the time of the first frame, so we don't get weird results with qw demos
struct qtvviewers_s
{ //(other) people on a qtv. in case people give a damn.
struct qtvviewers_s *next;
int userid;
char name[128];
} *qtvviewers;
int challenge; int challenge;
float latency; // rolling average float latency; // rolling average
@ -904,12 +916,12 @@ typedef struct
// information that is static for the entire time connected to a server // information that is static for the entire time connected to a server
// //
#ifdef HAVE_LEGACY #ifdef HAVE_LEGACY
char model_name_vwep[MAX_VWEP_MODELS][MAX_QPATH]; char *model_name_vwep[MAX_VWEP_MODELS];
struct model_s *model_precache_vwep[MAX_VWEP_MODELS]; struct model_s *model_precache_vwep[MAX_VWEP_MODELS];
#endif #endif
char model_name[MAX_PRECACHE_MODELS][MAX_QPATH]; char *model_name[MAX_PRECACHE_MODELS];
struct model_s *model_precache[MAX_PRECACHE_MODELS]; struct model_s *model_precache[MAX_PRECACHE_MODELS];
char sound_name[MAX_PRECACHE_SOUNDS][MAX_QPATH]; char *sound_name[MAX_PRECACHE_SOUNDS];
struct sfx_s *sound_precache[MAX_PRECACHE_SOUNDS]; struct sfx_s *sound_precache[MAX_PRECACHE_SOUNDS];
char *particle_ssname[MAX_SSPARTICLESPRE]; char *particle_ssname[MAX_SSPARTICLESPRE];
int particle_ssprecache[MAX_SSPARTICLESPRE]; //these are actually 1-based, so 0 can be used to lazy-init them. I cheat. int particle_ssprecache[MAX_SSPARTICLESPRE]; //these are actually 1-based, so 0 can be used to lazy-init them. I cheat.
@ -994,6 +1006,8 @@ typedef struct
float currentpacktime; float currentpacktime;
qboolean do_lerp_players; qboolean do_lerp_players;
playerview_t *mouseplayerview; //for mouse/scoreboard interaction when playing mvds.
int mousenewtrackplayer;
int teamplay; int teamplay;
int deathmatch; int deathmatch;
@ -1363,6 +1377,7 @@ void CL_Parse_Disconnected(void);
void CL_DumpPacket(void); void CL_DumpPacket(void);
void CL_ParseEstablished(void); void CL_ParseEstablished(void);
void CLQW_ParseServerMessage (void); void CLQW_ParseServerMessage (void);
void CLEZ_ParseHiddenDemoMessage (void);
void CLNQ_ParseServerMessage (void); void CLNQ_ParseServerMessage (void);
#ifdef Q2CLIENT #ifdef Q2CLIENT
void CLQ2_ParseServerMessage (void); void CLQ2_ParseServerMessage (void);

View file

@ -1956,7 +1956,8 @@ static int Con_DrawProgress(int left, int right, int y)
sprintf(progresspercenttext, " (%ukB/s)", CL_DownloadRate()/1000); sprintf(progresspercenttext, " (%ukB/s)", CL_DownloadRate()/1000);
else else
{ {
sprintf(progresspercenttext, " (%u%sKiB)", (int)(total/1024), extra?"+":""); char tmp[64];
sprintf(progresspercenttext, " (%s%s)", FS_AbbreviateSize(tmp,sizeof(tmp), total), extra?"+":"");
} }
//do some marquee thing, so the user gets the impression that SOMETHING is happening. //do some marquee thing, so the user gets the impression that SOMETHING is happening.

View file

@ -1792,7 +1792,7 @@ error:
int Image_WritePNG (const char *filename, enum fs_relative fsroot, int compression, void **buffers, int numbuffers, qintptr_t bufferstride, int width, int height, enum uploadfmt fmt, qboolean writemetadata) int Image_WritePNG (const char *filename, enum fs_relative fsroot, int compression, void **buffers, int numbuffers, qintptr_t bufferstride, int width, int height, enum uploadfmt fmt, qboolean writemetadata)
{ {
char name[MAX_OSPATH]; char systemname[MAX_OSPATH]; //FIXME: replace with png_set_write_fn
int i; int i;
FILE *fp; FILE *fp;
png_structp png_ptr; png_structp png_ptr;
@ -1882,7 +1882,7 @@ int Image_WritePNG (const char *filename, enum fs_relative fsroot, int compressi
} }
Image_BlockSizeForEncoding(fmt, &pxsize, &bw, &bh, &bd); Image_BlockSizeForEncoding(fmt, &pxsize, &bw, &bh, &bd);
if (!FS_NativePath(filename, fsroot, name, sizeof(name))) if (!FS_SystemPath(filename, fsroot, systemname, sizeof(systemname)))
return false; return false;
if (numbuffers == 2) if (numbuffers == 2)
@ -1898,10 +1898,10 @@ int Image_WritePNG (const char *filename, enum fs_relative fsroot, int compressi
if (!LibPNG_Init()) if (!LibPNG_Init())
return false; return false;
if (!(fp = fopen (name, "wb"))) if (!(fp = fopen (systemname, "wb")))
{ {
FS_CreatePath (filename, FS_GAMEONLY); FS_CreatePath (systemname, FS_SYSTEM);
if (!(fp = fopen (name, "wb"))) if (!(fp = fopen (systemname, "wb")))
return false; return false;
} }
@ -7176,6 +7176,7 @@ static struct pendingtextureinfo *Image_ReadBLPFile(unsigned int flags, const ch
//This is for the version command //This is for the version command
void Image_PrintInputFormatVersions(void) void Image_PrintInputFormatVersions(void)
{ {
int i;
#ifndef S_COLOR_YELLOW #ifndef S_COLOR_YELLOW
#define S_COLOR_YELLOW "" #define S_COLOR_YELLOW ""
#define S_COLOR_WHITE "" #define S_COLOR_WHITE ""
@ -7185,6 +7186,9 @@ void Image_PrintInputFormatVersions(void)
#ifdef IMAGEFMT_DDS #ifdef IMAGEFMT_DDS
Con_Printf(" dds"); Con_Printf(" dds");
#ifndef DECOMPRESS_S3TC
Con_Printf("(hw-only)");
#endif
#endif #endif
#ifdef IMAGEFMT_KTX #ifdef IMAGEFMT_KTX
Con_Printf(" ktx"); Con_Printf(" ktx");
@ -7231,6 +7235,9 @@ void Image_PrintInputFormatVersions(void)
#endif #endif
#ifdef IMAGEFMT_ASTC #ifdef IMAGEFMT_ASTC
Con_Printf(" astc"); Con_Printf(" astc");
#ifndef DECOMPRESS_ASTC
Con_Printf("(hw-only)");
#endif
#endif #endif
#ifdef IMAGEFMT_PKM #ifdef IMAGEFMT_PKM
Con_Printf(" pkm"); Con_Printf(" pkm");
@ -7278,6 +7285,10 @@ void Image_PrintInputFormatVersions(void)
Con_Printf(" lmp"); Con_Printf(" lmp");
#endif #endif
//now properly registered ones.
for (i = 0; i < imageloader_count; i++)
Con_Printf(" ^[%s^]", imageloader[i].funcs->loadername);
Con_Printf("\n"); Con_Printf("\n");
} }
@ -13757,10 +13768,10 @@ qboolean Image_LocateHighResTexture(image_t *tex, flocation_t *bestloc, char *be
{ {
COM_FileExtension(altname, nicename, sizeof(nicename)); COM_FileExtension(altname, nicename, sizeof(nicename));
e = 0; e = 0;
if (strcmp(nicename, "lmp") && strcmp(nicename, "wal")) if (Q_strcasecmp(nicename, "lmp") && Q_strcasecmp(nicename, "wal"))
for (; e < tex_extensions_count; e++) for (; e < tex_extensions_count; e++)
{ {
if (!strcmp(nicename, (*tex_extensions[e].name=='.')?tex_extensions[e].name+1:tex_extensions[e].name)) if (!Q_strcasecmp(nicename, (*tex_extensions[e].name=='.')?tex_extensions[e].name+1:tex_extensions[e].name))
break; break;
} }
} }
@ -13844,7 +13855,7 @@ qboolean Image_LocateHighResTexture(image_t *tex, flocation_t *bestloc, char *be
for (e = firstex; e < tex_extensions_count; e++) for (e = firstex; e < tex_extensions_count; e++)
{ {
if (tex->flags & IF_NOPCX) if (tex->flags & IF_NOPCX)
if (!strcmp(tex_extensions[e].name, ".pcx")) if (!Q_strcasecmp(tex_extensions[e].name, ".pcx"))
continue; continue;
Q_snprintfz(fname, sizeof(fname), tex_path[i].path, subpath, basename, tex_extensions[e].name); Q_snprintfz(fname, sizeof(fname), tex_path[i].path, subpath, basename, tex_extensions[e].name);
depth = FS_FLocateFile(fname, locflags, &loc); depth = FS_FLocateFile(fname, locflags, &loc);
@ -13863,7 +13874,7 @@ qboolean Image_LocateHighResTexture(image_t *tex, flocation_t *bestloc, char *be
for (e = firstex; e < tex_extensions_count; e++) for (e = firstex; e < tex_extensions_count; e++)
{ {
if (tex->flags & IF_NOPCX) if (tex->flags & IF_NOPCX)
if (!strcmp(tex_extensions[e].name, ".pcx")) if (!Q_strcasecmp(tex_extensions[e].name, ".pcx"))
continue; continue;
Q_snprintfz(fname, sizeof(fname), tex_path[i].path, nicename, tex_extensions[e].name); Q_snprintfz(fname, sizeof(fname), tex_path[i].path, nicename, tex_extensions[e].name);
depth = FS_FLocateFile(fname, locflags, &loc); depth = FS_FLocateFile(fname, locflags, &loc);
@ -13906,7 +13917,7 @@ qboolean Image_LocateHighResTexture(image_t *tex, flocation_t *bestloc, char *be
*b = 0; *b = 0;
for (e = firstex; e < tex_extensions_count; e++) for (e = firstex; e < tex_extensions_count; e++)
{ {
if (!strcmp(tex_extensions[e].name, ".tga")) if (!Q_strcasecmp(tex_extensions[e].name, ".tga"))
{ {
Q_snprintfz(fname, sizeof(fname), tex_path[i].path, bumpname, tex_extensions[e].name); Q_snprintfz(fname, sizeof(fname), tex_path[i].path, bumpname, tex_extensions[e].name);
depth = FS_FLocateFile(fname, locflags, &loc); depth = FS_FLocateFile(fname, locflags, &loc);
@ -14747,7 +14758,10 @@ void Image_Formats_f(void)
} }
Image_BlockSizeForEncoding(i, &blockbytes, &blockwidth, &blockheight, &blockdepth); Image_BlockSizeForEncoding(i, &blockbytes, &blockwidth, &blockheight, &blockdepth);
bpp = blockbytes*8.0/(blockwidth*blockheight*blockdepth); bpp = blockbytes*8.0/(blockwidth*blockheight*blockdepth);
if (blockbytes)
Con_Printf("%20s: %s"S_COLOR_GRAY" (%s%.3g-bpp)\n", Image_FormatName(i), sh_config.texfmt[i]?S_COLOR_GREEN"Enabled":S_COLOR_RED"Disabled", (blockdepth!=1)?"3d, ":"", bpp); Con_Printf("%20s: %s"S_COLOR_GRAY" (%s%.3g-bpp)\n", Image_FormatName(i), sh_config.texfmt[i]?S_COLOR_GREEN"Enabled":S_COLOR_RED"Disabled", (blockdepth!=1)?"3d, ":"", bpp);
else
Con_Printf("%20s: %s\n", Image_FormatName(i), sh_config.texfmt[i]?S_COLOR_GREEN"Enabled":S_COLOR_RED"Disabled");
} }
} }

View file

@ -491,7 +491,7 @@ void IN_Commands(void)
Key_Event(ev->devid, ev->keyboard.scancode, ev->keyboard.unicode, true); Key_Event(ev->devid, ev->keyboard.scancode, ev->keyboard.unicode, true);
break; break;
case IEV_JOYAXIS: case IEV_JOYAXIS:
if (ev->devid < MAXJOYSTICKS && ev->joy.axis < MAXJOYAXIS) if (ev->devid < MAXJOYSTICKS && ev->joy.axis>=0 && ev->joy.axis<MAXJOYAXIS)
{ {
if (topmenu && topmenu->joyaxis && topmenu->joyaxis(topmenu, ev->devid, ev->joy.axis, ev->joy.value)) if (topmenu && topmenu->joyaxis && topmenu->joyaxis(topmenu, ev->devid, ev->joy.axis, ev->joy.value))
joy[ev->devid].axis[ev->joy.axis] = 0; joy[ev->devid].axis[ev->joy.axis] = 0;
@ -884,6 +884,9 @@ void IN_MoveMouse(struct mouse_s *mouse, float *movements, int pnum, float frame
return; return;
} }
if (r_xflip.ival)
mouse_x *= -1;
// add mouse X/Y movement to cmd // add mouse X/Y movement to cmd
if (strafe_x) if (strafe_x)
movements[1] += m_side.value * mouse_x; movements[1] += m_side.value * mouse_x;
@ -1040,6 +1043,8 @@ void IN_MoveJoystick(struct joy_s *joy, float *movements, int pnum, float framet
VectorClear(jlook); VectorClear(jlook);
VectorClear(jstrafe); VectorClear(jstrafe);
} }
if (r_xflip.ival)
jlook[0] *= -1, jstrafe[0] *= -1;
if (in_speed.state[pnum] & 1) if (in_speed.state[pnum] & 1)
{ {

View file

@ -394,6 +394,44 @@ static void J_JoystickButton(SDL_JoystickID jid, int button, qboolean pressed)
} }
} }
int INS_GetControllerType(int id)
{
#if SDL_VERSION_ATLEAST(2,0,12)
int i;
for (i = 0; i < MAX_JOYSTICKS; i++)
{
if (sdljoy[i].qdevid == id)
{
switch(SDL_GameControllerTypeForIndex(sdljoy[i].id))
{
default: //for the future...
#if SDL_VERSION_ATLEAST(2,0,14)
case SDL_CONTROLLER_TYPE_VIRTUAL: //don't really know... assume steaminput and thus steamdeck and thus xbox-like.
#endif
return 1;
case SDL_CONTROLLER_TYPE_UNKNOWN:
return 0;
case SDL_CONTROLLER_TYPE_XBOX360:
case SDL_CONTROLLER_TYPE_XBOXONE:
#if SDL_VERSION_ATLEAST(2,0,16)
case SDL_CONTROLLER_TYPE_GOOGLE_STADIA: //close enough
case SDL_CONTROLLER_TYPE_AMAZON_LUNA: //it'll do. I guess we're starting to see a standard here.
#endif
return 1; //a on bottom, b('cancel') to right
case SDL_CONTROLLER_TYPE_PS3:
case SDL_CONTROLLER_TYPE_PS4:
#if SDL_VERSION_ATLEAST(2,0,14)
case SDL_CONTROLLER_TYPE_PS5:
#endif
return 2; //weird indecipherable shapes.
case SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_PRO:
return 3; //b on bottom, a('cancel') to right
}
}
}
#endif
return 0;
}
void INS_Rumble(int id, quint16_t amp_low, quint16_t amp_high, quint32_t duration) void INS_Rumble(int id, quint16_t amp_low, quint16_t amp_high, quint32_t duration)
{ {
#if SDL_VERSION_ATLEAST(2,0,9) #if SDL_VERSION_ATLEAST(2,0,9)
@ -459,7 +497,8 @@ void INS_SetLEDColor(int id, vec3_t color)
void INS_SetTriggerFX(int id, const void *data, size_t size) void INS_SetTriggerFX(int id, const void *data, size_t size)
{ {
#if SDL_VERSION_ATLEAST(2,0,15) #if SDL_VERSION_ATLEAST(2,0,15)
for (int i = 0; i < MAX_JOYSTICKS; i++) int i;
for (i = 0; i < MAX_JOYSTICKS; i++)
{ {
if (sdljoy[i].qdevid == id) if (sdljoy[i].qdevid == id)
{ {

View file

@ -34,8 +34,6 @@ void INS_Accumulate (void);
#define AVAIL_XINPUT #define AVAIL_XINPUT
#ifdef AVAIL_XINPUT #ifdef AVAIL_XINPUT
//#define AVAIL_XINPUT_DLL "xinput9_1_0.dll"
#define AVAIL_XINPUT_DLL "xinput1_3.dll"
typedef struct _XINPUT_GAMEPAD { typedef struct _XINPUT_GAMEPAD {
WORD wButtons; WORD wButtons;
BYTE bLeftTrigger; BYTE bLeftTrigger;
@ -55,7 +53,9 @@ typedef struct _XINPUT_VIBRATION {
} XINPUT_VIBRATION, *PXINPUT_VIBRATION; } XINPUT_VIBRATION, *PXINPUT_VIBRATION;
DWORD (WINAPI *pXInputGetState)(DWORD dwUserIndex, XINPUT_STATE *pState); DWORD (WINAPI *pXInputGetState)(DWORD dwUserIndex, XINPUT_STATE *pState);
DWORD (WINAPI *pXInputSetState)(DWORD dwUserIndex, XINPUT_VIBRATION *pState); DWORD (WINAPI *pXInputSetState)(DWORD dwUserIndex, XINPUT_VIBRATION *pState);
DWORD (WINAPI *pXInputGetDSoundAudioDeviceGuids)(DWORD dwUserIndex, GUID* pDSoundRenderGuid, GUID* pDSoundCaptureGuid); DWORD (WINAPI *pXInputGetDSoundAudioDeviceGuids)(DWORD dwUserIndex, GUID* pDSoundRenderGuid, GUID* pDSoundCaptureGuid); //xi 1.3
DWORD (WINAPI *pXInputGetAudioDeviceIds)(DWORD dwUserIndex, LPWSTR pRenderDeviceId, UINT *pRenderCount, LPWSTR pCaptureDeviceId, UINT *pCaptureCount); //xi 1.4
enum enum
{ {
XINPUT_GAMEPAD_DPAD_UP = 0x0001, XINPUT_GAMEPAD_DPAD_UP = 0x0001,
@ -382,6 +382,51 @@ static const int mmjbuttons[32] =
K_JOY8 K_JOY8
}; };
static HANDLE powercontext = INVALID_HANDLE_VALUE;
static qboolean powersaveblocked = false;
static HANDLE (WINAPI *pPowerCreateRequest) (REASON_CONTEXT *Context);
static BOOL (WINAPI *pPowerSetRequest) (HANDLE Context, POWER_REQUEST_TYPE RequestType);
static BOOL (WINAPI *pPowerClearRequest) (HANDLE Context, POWER_REQUEST_TYPE RequestType);
static void INS_ScreenSaver_Init(void)
{
dllfunction_t functable[] =
{
{(void*)&pPowerCreateRequest, "PowerCreateRequest"},
{(void*)&pPowerSetRequest, "PowerSetRequest"},
{(void*)&pPowerClearRequest, "PowerClearRequest"},
{NULL}
};
if (Sys_LoadLibrary("kernel32.dll", functable))
{ //we don't do microsoft's interpretation of localisation, so this is lame.
REASON_CONTEXT reason = {POWER_REQUEST_CONTEXT_VERSION, POWER_REQUEST_CONTEXT_SIMPLE_STRING};
reason.Reason.SimpleReasonString = L"Demo Playback";
powercontext = pPowerCreateRequest(&reason);
//FIXME: be prepared to regenerate the reason when our lang changes...
}
}
static void INS_ScreenSaver_UpdateBlock(qboolean block)
{
if (powercontext != INVALID_HANDLE_VALUE && block != powersaveblocked)
{
powersaveblocked = block;
if (block)
{
pPowerSetRequest(powercontext, PowerRequestDisplayRequired); //keep the screen on...
pPowerSetRequest(powercontext, PowerRequestSystemRequired); //and don't go to sleep mid-video, too...
}
else
{
pPowerClearRequest(powercontext, PowerRequestSystemRequired);
pPowerClearRequest(powercontext, PowerRequestDisplayRequired);
}
}
}
// forward-referenced functions // forward-referenced functions
void INS_StartupJoystick (void); void INS_StartupJoystick (void);
void INS_JoyMove (void); void INS_JoyMove (void);
@ -706,6 +751,8 @@ void INS_UpdateGrabs(int fullscreen, int activeapp)
{ {
int grabmouse; int grabmouse;
INS_ScreenSaver_UpdateBlock(cls.demoplayback && activeapp);
if (!activeapp) if (!activeapp)
grabmouse = false; grabmouse = false;
else if (fullscreen || in_simulatemultitouch.ival || in_windowed_mouse.value) else if (fullscreen || in_simulatemultitouch.ival || in_windowed_mouse.value)
@ -1376,6 +1423,8 @@ void INS_Init (void)
Cvar_Register (&in_rawinput_keyboard, "Input Controls"); Cvar_Register (&in_rawinput_keyboard, "Input Controls");
Cvar_Register (&in_rawinput_rdp, "Input Controls"); Cvar_Register (&in_rawinput_rdp, "Input Controls");
#endif #endif
INS_ScreenSaver_Init();
} }
/* /*
@ -1854,6 +1903,8 @@ static void IN_XInput_SetupAudio(struct wjoy_s *joy)
if (joy->devid == DEVID_UNSET) if (joy->devid == DEVID_UNSET)
return; return;
if (pXInputGetDSoundAudioDeviceGuids)
{
if (pXInputGetDSoundAudioDeviceGuids(joy->id, &gplayback, &gcapture) != ERROR_SUCCESS) if (pXInputGetDSoundAudioDeviceGuids(joy->id, &gplayback, &gcapture) != ERROR_SUCCESS)
return; //probably not plugged in return; //probably not plugged in
@ -1862,8 +1913,19 @@ static void IN_XInput_SetupAudio(struct wjoy_s *joy)
StringFromGUID2(&gplayback, mssuck, sizeof(mssuck)/sizeof(mssuck[0])); StringFromGUID2(&gplayback, mssuck, sizeof(mssuck)/sizeof(mssuck[0]));
narrowen(audiodevicename, sizeof(audiodevicename), mssuck); narrowen(audiodevicename, sizeof(audiodevicename), mssuck);
Con_Printf("Controller %i uses audio device %s\n", joy->id, audiodevicename); Con_Printf("Controller %i uses directsound device %s\n", joy->id, audiodevicename);
joy->audiodev = S_SetupDeviceSeat("DirectSound", audiodevicename, joy->devid); joy->audiodev = S_SetupDeviceSeat("DirectSound", audiodevicename, joy->devid);
}
else if (pXInputGetAudioDeviceIds)
{
UINT wccount = countof(mssuck);
if (!FAILED(pXInputGetAudioDeviceIds(joy->id, mssuck, &wccount, NULL,NULL/*we don't have separate mics, sadly, which also makes config awkward*/)))
{
narrowen(audiodevicename, sizeof(audiodevicename), mssuck);
Con_Printf("Controller %i uses xaudio2 device %s\n", joy->id, audiodevicename);
joy->audiodev = S_SetupDeviceSeat("XAudio2", audiodevicename, joy->devid);
}
}
#endif #endif
} }
void INS_SetupControllerAudioDevices(qboolean enabled) void INS_SetupControllerAudioDevices(qboolean enabled)
@ -1871,9 +1933,6 @@ void INS_SetupControllerAudioDevices(qboolean enabled)
#ifdef AVAIL_XINPUT #ifdef AVAIL_XINPUT
int i; int i;
if (!pXInputGetDSoundAudioDeviceGuids)
return;
xinput_useaudio = enabled; xinput_useaudio = enabled;
for (i = 0; i < joy_count; i++) for (i = 0; i < joy_count; i++)
IN_XInput_SetupAudio(&wjoy[i]); IN_XInput_SetupAudio(&wjoy[i]);
@ -1891,6 +1950,12 @@ void INS_StartupJoystick (void)
if (in_xinput.ival) if (in_xinput.ival)
{ {
static dllhandle_t *xinput; static dllhandle_t *xinput;
static const char *dllnames[] =
{
"xinput1_4.dll", //win8+ only. does xaudio2 instead of dsound.
"xinput1_3.dll", //dxsdk (vista+). does dsound stuff.
"xinput9_1_0.dll" //vista+. doesn't do audio stuff.
};
if (!xinput) if (!xinput)
{ {
dllfunction_t funcs[] = dllfunction_t funcs[] =
@ -1899,10 +1964,17 @@ void INS_StartupJoystick (void)
{(void**)&pXInputSetState, "XInputSetState"}, {(void**)&pXInputSetState, "XInputSetState"},
{NULL} {NULL}
}; };
xinput = Sys_LoadLibrary(AVAIL_XINPUT_DLL, funcs); pXInputGetDSoundAudioDeviceGuids = NULL;
pXInputGetAudioDeviceIds = NULL;
for (id = 0; id < countof(dllnames); id++)
{
xinput = Sys_LoadLibrary(dllnames[id], funcs);
if (xinput) if (xinput)
pXInputGetDSoundAudioDeviceGuids = Sys_GetAddressForName(xinput, "XInputGetDSoundAudioDeviceGuids"); break;
}
pXInputGetDSoundAudioDeviceGuids = xinput?Sys_GetAddressForName(xinput, "XInputGetDSoundAudioDeviceGuids"):NULL;
pXInputGetAudioDeviceIds = xinput?Sys_GetAddressForName(xinput, "XInputGetAudioDeviceIds"):NULL;
} }
if (pXInputGetState) if (pXInputGetState)
{ {
@ -1925,7 +1997,7 @@ void INS_StartupJoystick (void)
Con_DPrintf("XInput is enabled (%i controllers found)\n", numdevs); Con_DPrintf("XInput is enabled (%i controllers found)\n", numdevs);
} }
else else
Con_Printf("XInput not installed\n"); Con_Printf("XInput (%s) not installed\n", dllnames[1]);
} }
#endif #endif

View file

@ -944,7 +944,7 @@ void Key_DefaultLinkClicked(console_t *con, char *text, char *info)
if (*cl.players[player].ip) if (*cl.players[player].ip)
Con_Footerf(con, true, "\n%s", cl.players[player].ip); Con_Footerf(con, true, "\n%s", cl.players[player].ip);
if (cl.playerview[0].spectator || cls.demoplayback==DPB_MVD||cls.demoplayback==DPB_EZTV) if (cl.playerview[0].spectator || cls.demoplayback==DPB_MVD)
{ {
//we're spectating, or an mvd //we're spectating, or an mvd
Con_Footerf(con, true, " ^[Spectate\\player\\%i\\action\\spec^]", player); Con_Footerf(con, true, " ^[Spectate\\player\\%i\\action\\spec^]", player);
@ -3079,7 +3079,7 @@ void Key_Event (unsigned int devid, int key, unsigned int unicode, qboolean down
// //
// during demo playback, most keys bring up the main menu // during demo playback, most keys bring up the main menu
// //
if (cls.demoplayback && cls.demoplayback != DPB_MVD && cls.demoplayback != DPB_EZTV && conkey && !Key_Dest_Has(~kdm_game)) if (cls.demoplayback && cls.demoplayback != DPB_MVD && conkey && !Key_Dest_Has(~kdm_game))
{ {
switch (key) switch (key)
{ //these keys don't force the menu to appear while playing the demo reel { //these keys don't force the menu to appear while playing the demo reel
@ -3243,6 +3243,8 @@ defaultedbind:
if (key == K_TOUCH || (key == K_MOUSE1 && IN_Touch_MouseIsAbs(devid))) if (key == K_TOUCH || (key == K_MOUSE1 && IN_Touch_MouseIsAbs(devid)))
{ {
const char *button = SCR_ShowPics_ClickCommand(mousecursor_x, mousecursor_y, key == K_TOUCH); const char *button = SCR_ShowPics_ClickCommand(mousecursor_x, mousecursor_y, key == K_TOUCH);
if (!button && cl.mouseplayerview && cl.mousenewtrackplayer>=0)
Cam_Lock(cl.mouseplayerview, cl.mousenewtrackplayer);
if (button) if (button)
{ {
dc = button; dc = button;

File diff suppressed because it is too large Load diff

View file

@ -480,7 +480,7 @@ static qboolean M_MouseMoved(emenu_t *menu)
if (opt2->common.posy + opt2->common.height > maxy) if (opt2->common.posy + opt2->common.height > maxy)
maxy = opt2->common.posy + opt2->common.height; maxy = opt2->common.posy + opt2->common.height;
} }
maxy -= vid.height-8; maxy -= vid.height;
framescroll += option->frame.frac * maxy; framescroll += option->frame.frac * maxy;
ypos -= option->frame.frac * maxy; ypos -= option->frame.frac * maxy;
} }
@ -682,16 +682,16 @@ static void MenuDrawItems(int xpos, int ypos, menuoption_t *option, emenu_t *men
int maxy = option->frame.common.posy; int maxy = option->frame.common.posy;
option->frame.common.width = 16; option->frame.common.width = 16;
option->frame.common.posx = vid.width - option->frame.common.width - xpos; option->frame.common.posx = vid.width - option->frame.common.width - xpos;
option->frame.common.height = vid.height-8-maxy - ypos; option->frame.common.height = vid.height-maxy - ypos;
for (opt2 = option->common.next; opt2; opt2 = opt2->common.next) for (opt2 = option->common.next; opt2; opt2 = opt2->common.next)
{ {
if (opt2->common.posy + opt2->common.height > maxy) if (opt2->common.posy + opt2->common.height > maxy)
maxy = opt2->common.posy + opt2->common.height; maxy = opt2->common.posy + opt2->common.height;
} }
maxy -= vid.height-8; maxy -= vid.height;
framescrollheight = maxy; framescrollheight = maxy;
if (maxy < 0) if (maxy <= 0)
{ {
option->frame.mousedown = false; option->frame.mousedown = false;
option->frame.frac = 0; option->frame.frac = 0;
@ -892,7 +892,10 @@ static void MenuDrawItems(int xpos, int ypos, menuoption_t *option, emenu_t *men
static void MenuDraw(emenu_t *menu) static void MenuDraw(emenu_t *menu)
{ {
if (!menu->dontexpand) if (!menu->dontexpand)
menu->xpos = ((vid.width - 320)>>1); {
menu->width = min(vid.width,320);
menu->xpos = ((vid.width - menu->width)>>1);
}
if (menu->predraw) if (menu->predraw)
menu->predraw(menu); menu->predraw(menu);
if (menu->selecteditem && menu->selecteditem->common.type == mt_text) if (menu->selecteditem && menu->selecteditem->common.type == mt_text)
@ -1771,8 +1774,8 @@ void MC_CheckBox_Key(menucheck_t *option, emenu_t *menu, int key)
else else
Cvar_SetValue(option->var, !option->var->value); Cvar_SetValue(option->var, !option->var->value);
} }
S_LocalSound ("misc/menu2.wav");
} }
S_LocalSound ("misc/menu2.wav");
} }
void MC_EditBox_Key(menuedit_t *edit, int key, unsigned int unicode) void MC_EditBox_Key(menuedit_t *edit, int key, unsigned int unicode)
@ -2401,10 +2404,15 @@ static int M_Main_AddExtraOptions(emenu_t *mainm, int y)
#endif #endif
} }
if (Cmd_Exists("menu_mods")) if (Cmd_Exists("menu_mods"))
{ {MC_AddConsoleCommandQBigFont(mainm, 72, y, localtext("Mods "), "menu_mods\n"); y += 20;}
MC_AddConsoleCommandQBigFont(mainm, 72, y, localtext("Mods "), "menu_mods\n"); y += 20;
y += 20; if (Cmd_Exists("sys_openfile"))
} {MC_AddConsoleCommandQBigFont(mainm, 72, y, localtext("Open File "), "sys_openfile\n"); y += 20;}
#ifdef FTE_TARGET_WEB
if (Cmd_Exists("xr_toggle"))
{MC_AddConsoleCommandQBigFont(mainm, 72, y, localtext("Toggle WebXR "), "xr_toggle\n"); y += 20;}
#endif
return y; return y;
} }
@ -2716,8 +2724,10 @@ void M_Menu_Main_f (void)
b = NULL; b = NULL;
if (!b && !m_preset_chosen.ival) if (!b && !m_preset_chosen.ival)
b = M_FindButton(mainm, "menu_options\n"); b = M_FindButton(mainm, "menu_options\n");
#ifdef PACKAGEMANAGER
if (!b && PM_AreSourcesNew(false)) if (!b && PM_AreSourcesNew(false))
b = M_FindButton(mainm, "menu_download\n"); b = M_FindButton(mainm, "menu_download\n");
#endif
if (b) if (b)
{ {
mainm->selecteditem = (menuoption_t*)b; mainm->selecteditem = (menuoption_t*)b;

View file

@ -2958,7 +2958,7 @@ static void *QDECL capture_raw_begin (char *streamname, int videorate, int width
else else
Q_strncpyz(ctx->videonameextension, "tga", sizeof(ctx->videonameextension)); Q_strncpyz(ctx->videonameextension, "tga", sizeof(ctx->videonameextension));
if (!FS_NativePath(va("%s", streamname), FS_GAMEONLY, ctx->videonameprefix, sizeof(ctx->videonameprefix))) if (!FS_SystemPath(va("%s", streamname), FS_GAMEONLY, ctx->videonameprefix, sizeof(ctx->videonameprefix)))
{ {
Z_Free(ctx); Z_Free(ctx);
return NULL; return NULL;
@ -2970,8 +2970,7 @@ static void *QDECL capture_raw_begin (char *streamname, int videorate, int width
} }
ctx->fsroot = FS_SYSTEM; ctx->fsroot = FS_SYSTEM;
if (FS_NativePath(ctx->videonameprefix, ctx->fsroot, filename, sizeof(filename))) FS_CreatePath(ctx->videonameprefix, ctx->fsroot);
FS_CreatePath(filename, ctx->fsroot);
ctx->audio = NULL; ctx->audio = NULL;
if (*sndkhz) if (*sndkhz)
@ -3012,7 +3011,7 @@ static void QDECL capture_raw_video (void *vctx, int frame, void *data, int stri
{ {
char base[MAX_QPATH]; char base[MAX_QPATH];
Q_strncpyz(base, ctx->videonameprefix, sizeof(base)); Q_strncpyz(base, ctx->videonameprefix, sizeof(base));
if (FS_NativePath(base, ctx->fsroot, filename, sizeof(filename))) if (FS_SystemPath(base, ctx->fsroot, filename, sizeof(filename)))
{ {
quint64_t diskfree = 0; quint64_t diskfree = 0;
if (Sys_GetFreeDiskSpace(filename, &diskfree)) if (Sys_GetFreeDiskSpace(filename, &diskfree))
@ -3111,7 +3110,7 @@ static void *QDECL capture_avi_begin (char *streamname, int videorate, int width
COM_StripExtension(streamname, aviname, sizeof(aviname)); COM_StripExtension(streamname, aviname, sizeof(aviname));
COM_DefaultExtension (aviname, ".avi", sizeof(aviname)); COM_DefaultExtension (aviname, ".avi", sizeof(aviname));
/*find the system location of that*/ /*find the system location of that*/
FS_NativePath(aviname, FS_GAMEONLY, nativepath, sizeof(nativepath)); FS_SystemPath(aviname, FS_GAMEONLY, nativepath, sizeof(nativepath));
//wipe it. //wipe it.
f = fopen(nativepath, "rb"); f = fopen(nativepath, "rb");

View file

@ -407,7 +407,7 @@ qboolean MN_Init(void)
VFS_GETS, VFS_GETS,
VFS_PRINTF, VFS_PRINTF,
COM_EnumerateFiles, COM_EnumerateFiles,
FS_NativePath, FS_SystemPath,
// Drawing stuff // Drawing stuff
MN_DrawSetClipArea, MN_DrawSetClipArea,

View file

@ -1376,7 +1376,10 @@ void M_Menu_Preset_f (void)
emenu_t *menu; emenu_t *menu;
int y; int y;
menuoption_t *presetoption[7]; menuoption_t *presetoption[7];
extern cvar_t r_nolerp, sv_nqplayerphysics, r_loadlits; extern cvar_t r_nolerp, r_loadlits;
#ifdef HAVE_SERVER
extern cvar_t sv_nqplayerphysics;
#endif
#if defined(RTLIGHTS) && (defined(GLQUAKE) || defined(VKQUAKE)) #if defined(RTLIGHTS) && (defined(GLQUAKE) || defined(VKQUAKE))
extern cvar_t r_bloom, r_shadow_realtime_world_importlightentitiesfrommap; extern cvar_t r_bloom, r_shadow_realtime_world_importlightentitiesfrommap;
#endif #endif
@ -2608,7 +2611,9 @@ static const char *mapoptions_h2[] =
qboolean M_Apply_SP_Cheats_H2 (union menuoption_s *op,struct emenu_s *menu,int key) qboolean M_Apply_SP_Cheats_H2 (union menuoption_s *op,struct emenu_s *menu,int key)
{ {
#ifdef HAVE_SERVER
singleplayerh2info_t *info = menu->data; singleplayerh2info_t *info = menu->data;
#endif
if (key != K_ENTER && key != K_KP_ENTER && key != K_GP_DIAMOND_CONFIRM && key != K_MOUSE1 && key != K_TOUCHTAP) if (key != K_ENTER && key != K_KP_ENTER && key != K_GP_DIAMOND_CONFIRM && key != K_MOUSE1 && key != K_TOUCHTAP)
return false; return false;
@ -2642,6 +2647,11 @@ qboolean M_Apply_SP_Cheats_H2 (union menuoption_s *op,struct emenu_s *menu,int k
void M_Menu_Singleplayer_Cheats_Hexen2 (void) void M_Menu_Singleplayer_Cheats_Hexen2 (void)
{ {
singleplayerh2info_t *info;
int cursorpositionY;
#ifdef HAVE_SERVER
int currentmap;
int currentskill;
static const char *skilloptions[] = static const char *skilloptions[] =
{ {
"Easy", "Easy",
@ -2651,12 +2661,6 @@ void M_Menu_Singleplayer_Cheats_Hexen2 (void)
"None Set", "None Set",
NULL NULL
}; };
singleplayerh2info_t *info;
int cursorpositionY;
int currentmap;
#ifdef HAVE_SERVER
int currentskill;
extern cvar_t sv_gravity, sv_cheats, sv_maxspeed, skill; extern cvar_t sv_gravity, sv_cheats, sv_maxspeed, skill;
#endif #endif
int y; int y;
@ -3382,6 +3386,7 @@ typedef struct
char modelname[MAX_QPATH]; char modelname[MAX_QPATH];
char skinname[MAX_QPATH]; char skinname[MAX_QPATH];
char animname[MAX_QPATH];
char shaderfile[MAX_QPATH]; char shaderfile[MAX_QPATH];
char *shadertext; char *shadertext;
@ -3498,12 +3503,14 @@ static void M_ModelViewerDraw(int x, int y, struct menucustom_s *c, struct emenu
skinfile_t *skin; skinfile_t *skin;
texnums_t *texnums; texnums_t *texnums;
qboolean boneanimsonly; qboolean boneanimsonly;
model_t *animmodel = NULL;
if (R2D_Flush) if (R2D_Flush)
R2D_Flush(); R2D_Flush();
memset(&pv, 0, sizeof(pv)); memset(&pv, 0, sizeof(pv));
Alias_FlushCache(); //doesn't like us using stack...
CL_DecayLights (); CL_DecayLights ();
CL_ClearEntityLists(); CL_ClearEntityLists();
V_ClearRefdef(&pv); V_ClearRefdef(&pv);
@ -3571,7 +3578,12 @@ static void M_ModelViewerDraw(int x, int y, struct menucustom_s *c, struct emenu
return; //panic! return; //panic!
if (ent.model->type == mod_alias) //should we even bother with this here? if (ent.model->type == mod_alias) //should we even bother with this here?
{
if (*mods->animname)
animmodel = Mod_ForName(mods->animname, MLV_WARN);
AngleVectorsMesh(ent.angles, ent.axis[0], ent.axis[1], ent.axis[2]); AngleVectorsMesh(ent.angles, ent.axis[0], ent.axis[1], ent.axis[2]);
}
else else
AngleVectors(ent.angles, ent.axis[0], ent.axis[1], ent.axis[2]); AngleVectors(ent.angles, ent.axis[0], ent.axis[1], ent.axis[2]);
VectorInverse(ent.axis[1]); VectorInverse(ent.axis[1]);
@ -3608,7 +3620,14 @@ static void M_ModelViewerDraw(int x, int y, struct menucustom_s *c, struct emenu
ent.framestate.g[FS_REG].frametime[0] = ent.framestate.g[FS_REG].frametime[1] = realtime - mods->framechangetime; 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.framestate.g[FS_REG].endbone = 0x7fffffff;
if (*mods->skinname) if (*mods->skinname)
{
ent.customskin = Mod_RegisterSkinFile(mods->skinname); //explicit .skin file to use ent.customskin = Mod_RegisterSkinFile(mods->skinname); //explicit .skin file to use
if (!ent.customskin)
{
Con_Printf(CON_WARNING"Named skinfile not loaded\n");
*mods->skinname = 0; //don't spam.
}
}
else else
{ {
ent.customskin = Mod_RegisterSkinFile(va("%s_%i.skin", mods->modelname, ent.skinnum)); ent.customskin = Mod_RegisterSkinFile(va("%s_%i.skin", mods->modelname, ent.skinnum));
@ -3700,6 +3719,18 @@ static void M_ModelViewerDraw(int x, int y, struct menucustom_s *c, struct emenu
} }
#endif #endif
if (animmodel)// && Mod_GetNumBones(ent.model, false)==Mod_GetNumBones(animmodel, false))
{
int numbones = Mod_GetNumBones(ent.model, false);
galiasbone_t *boneinfo = Mod_GetBoneInfo(ent.model, &numbones);
float *bonematrix = alloca(numbones*sizeof(*bonematrix)*12);
ent.framestate.bonecount = Mod_GetBoneRelations(animmodel, 0, numbones, boneinfo, &ent.framestate, bonematrix);
ent.framestate.bonestate = bonematrix;
ent.framestate.skeltype = SKEL_RELATIVE;
}
else
animmodel = ent.model; //not using it. sorry. warn?
if (mods->mode == MV_NORMALS) if (mods->mode == MV_NORMALS)
{ {
@ -3898,8 +3929,10 @@ static void M_ModelViewerDraw(int x, int y, struct menucustom_s *c, struct emenu
float duration = 0; float duration = 0;
qboolean loop = false; qboolean loop = false;
int act = -1; int act = -1;
if (!Mod_FrameInfoForNum(ent.model, mods->surfaceidx, mods->framegroup, &fname, &numframes, &duration, &loop, &act)) if (!Mod_FrameInfoForNum(animmodel, mods->surfaceidx, mods->framegroup, &fname, &numframes, &duration, &loop, &act))
fname = "Unknown Sequence"; fname = "Unknown Sequence";
if (animmodel != ent.model)
fname = va("^[%s^] %s", animmodel->name, fname); //tag it properly if its from our animmodel
if (act != -1) if (act != -1)
Draw_FunString(0, y, va("Frame%i[%i]: %s (%i poses, %f of %f secs, %s)", mods->framegroup, act, fname, numframes, ent.framestate.g[FS_REG].frametime[0], duration, loop?"looped":"unlooped")); Draw_FunString(0, y, va("Frame%i[%i]: %s (%i poses, %f of %f secs, %s)", mods->framegroup, act, fname, numframes, ent.framestate.g[FS_REG].frametime[0], duration, loop?"looped":"unlooped"));
else else
@ -4032,17 +4065,18 @@ static void M_ModelViewerDraw(int x, int y, struct menucustom_s *c, struct emenu
char *data = NULL; char *data = NULL;
Draw_FunString(0, y, va("Events: ")); Draw_FunString(0, y, va("Events: "));
y+=8; y+=8;
for (i = 0; Mod_GetModelEvent(ent.model, mods->framegroup, i, &timestamp, &code, &data); y+=8, i++) for (i = 0; Mod_GetModelEvent(animmodel, mods->framegroup, i, &timestamp, &code, &data); y+=8, i++)
{ {
Draw_FunString(0, y, va("%i %f: %i %s", i, timestamp, code, data)); Draw_FunString(0, y, va("%i %f: %i %s", i, timestamp, code, data));
} }
Draw_FunString(0, y, va("%f: <end of animation>", Mod_GetFrameDuration(ent.model, 0, mods->framegroup))); Draw_FunString(0, y, va("%f: <end of animation>", Mod_GetFrameDuration(animmodel, 0, mods->framegroup)));
} }
break; break;
case MV_SHADER: case MV_SHADER:
{ {
if (!mods->shadertext) if (!mods->shadertext)
{ {
char *cr;
char *body = Shader_GetShaderBody(Mod_ShaderForSkin(ent.model, mods->surfaceidx, mods->skingroup, r_refdef.time, &texnums), mods->shaderfile, sizeof(mods->shaderfile)); char *body = Shader_GetShaderBody(Mod_ShaderForSkin(ent.model, mods->surfaceidx, mods->skingroup, r_refdef.time, &texnums), mods->shaderfile, sizeof(mods->shaderfile));
if (!body) if (!body)
{ {
@ -4053,8 +4087,11 @@ static void M_ModelViewerDraw(int x, int y, struct menucustom_s *c, struct emenu
mods->shadertext = Z_StrDupf("\n\nPress space to view+edit the shader\n\n%s", body); mods->shadertext = Z_StrDupf("\n\nPress space to view+edit the shader\n\n%s", body);
else else
mods->shadertext = Z_StrDupf("{ %s",body); mods->shadertext = Z_StrDupf("{ %s",body);
while ((cr = strchr(mods->shadertext, '\r')))
*cr = ' ';
} }
R_DrawTextField(r_refdef.grect.x, r_refdef.grect.y+16, r_refdef.grect.width, r_refdef.grect.height-16, mods->shadertext, CON_WHITEMASK, CPRINT_TALIGN|CPRINT_LALIGN, font_default, fs); R_DrawTextField(r_refdef.grect.x, r_refdef.grect.y+24, r_refdef.grect.width, r_refdef.grect.height-16, mods->shadertext, CON_WHITEMASK, CPRINT_TALIGN|CPRINT_LALIGN, font_default, fs);
//fixme: draw the shader's textures. //fixme: draw the shader's textures.
} }
@ -4333,6 +4370,12 @@ void M_Menu_ModelViewer_f(void)
menucustom_t *c; menucustom_t *c;
emenu_t *menu; emenu_t *menu;
if (!*Cmd_Argv(1))
{
Con_Printf("modelviewer <MODELNAME> [SKINFILE] [ANIMATIONFILE]\n");
return;
}
menu = M_CreateMenu(sizeof(*mv)); menu = M_CreateMenu(sizeof(*mv));
menu->menu.persist = true; menu->menu.persist = true;
mv = menu->data; mv = menu->data;
@ -4345,6 +4388,7 @@ void M_Menu_ModelViewer_f(void)
mv->dist = 150; mv->dist = 150;
Q_strncpyz(mv->modelname, Cmd_Argv(1), sizeof(mv->modelname)); Q_strncpyz(mv->modelname, Cmd_Argv(1), sizeof(mv->modelname));
Q_strncpyz(mv->skinname, Cmd_Argv(2), sizeof(mv->skinname)); Q_strncpyz(mv->skinname, Cmd_Argv(2), sizeof(mv->skinname));
Q_strncpyz(mv->animname, Cmd_Argv(3), sizeof(mv->animname));
mv->framechangetime = realtime; mv->framechangetime = realtime;
mv->skinchangetime = realtime; mv->skinchangetime = realtime;
@ -4406,42 +4450,57 @@ static void Mods_Draw(int x, int y, struct menucustom_s *c, struct emenu_s *m)
{ {
int i = c->dint; int i = c->dint;
struct modlist_s *mod = Mods_GetMod(i); struct modlist_s *mod = Mods_GetMod(i);
c->common.width = vid.width - x - 16;
if (!mod && !i) if (!mod && !i)
{ {
float scale[] = {8,8}; float scale[] = {8,8};
R_DrawTextField(0, y, vid.width, vid.height - y,
m->height = vid.height;
if (y==0)
{ //just take the full screen.
y = m->ypos;
c->common.posy = 0;
c->common.height = m->height;
m->dontexpand = true;
m->xpos = x = 0;
m->width = vid.width;
}
else
{ //at least expand it.
c->common.height = m->height - c->common.posy;
}
//take the full width of the menu
x = m->xpos;
c->common.posx = 0;
c->common.width = m->width;
R_DrawTextField(x, y, c->common.width, c->common.height,
va( va(
"No games or mods known.\n" "No games or mods known.\n"
#if defined(FTE_TARGET_WEB) #ifdef FTE_TARGET_WEB
"Connection issue or bad server config.\n" "Try providing packages/gamedirs via drag+drop.\n"
"%s", Cmd_Exists("sys_openfile")?"Or click to add a package\n":""
#else #else
#ifndef ANDROID #ifndef ANDROID
"You may need to use -basedir $PATHTOGAME on the commandline.\n" "You may need to use -basedir $PATHTOGAME on the commandline.\n"
#endif #endif
"\nExpected data path:\n^a%s", com_gamepath "\nExpected data path:\n^a%s", com_gamepath
#endif #endif
), CON_WHITEMASK, 0, font_console, scale); ), CON_WHITEMASK, 0, font_default, scale);
return; return;
} }
c->common.height = 8;
c->common.width = vid.width - x - 16;
if (!mod) if (!mod)
return; return;
if (mod->manifest) if (mod->manifest)
{ Draw_FunStringWidth(x, y, mod->manifest->formalname, c->common.width, 0, m->selecteditem == (menuoption_t*)c);
if (m->selecteditem == (menuoption_t*)c)
Draw_AltFunString(x, y, mod->manifest->formalname);
else else
Draw_FunString(x, y, mod->manifest->formalname); Draw_FunStringWidth(x, y, mod->gamedir, c->common.width, 0, m->selecteditem == (menuoption_t*)c);
}
else
{
if (m->selecteditem == (menuoption_t*)c)
Draw_AltFunString(x, y, mod->gamedir);
else
Draw_FunString(x, y, mod->gamedir);
}
} }
static qboolean Mods_Key(struct menucustom_s *c, struct emenu_s *m, int key, unsigned int unicode) static qboolean Mods_Key(struct menucustom_s *c, struct emenu_s *m, int key, unsigned int unicode)
{ {
@ -4450,7 +4509,11 @@ static qboolean Mods_Key(struct menucustom_s *c, struct emenu_s *m, int key, uns
{ {
qboolean wasgameless = !*FS_GetGamedir(false); qboolean wasgameless = !*FS_GetGamedir(false);
if (!Mods_GetMod(c->dint)) if (!Mods_GetMod(c->dint))
{
if (Cmd_Exists("sys_openfile"))
Cbuf_AddText("sys_openfile\n", RESTRICT_LOCAL);
return false; return false;
}
M_RemoveMenu(m); M_RemoveMenu(m);
Cbuf_AddText(va("\nfs_changegame %u\n", gameidx+1), RESTRICT_LOCAL); Cbuf_AddText(va("\nfs_changegame %u\n", gameidx+1), RESTRICT_LOCAL);
@ -4471,6 +4534,7 @@ void M_Menu_Mods_f (void)
menucustom_t *c; menucustom_t *c;
emenu_t *menu; emenu_t *menu;
size_t i; size_t i;
int y;
//FIXME: sort by mtime? //FIXME: sort by mtime?
@ -4479,20 +4543,23 @@ void M_Menu_Mods_f (void)
{ {
MC_AddPicture(menu, 16, 4, 32, 144, "gfx/qplaque.lmp"); MC_AddPicture(menu, 16, 4, 32, 144, "gfx/qplaque.lmp");
MC_AddCenterPicture(menu, 0, 24, "gfx/p_option.lmp"); MC_AddCenterPicture(menu, 0, 24, "gfx/p_option.lmp");
y = 32;
} }
else
y = 0;
MC_AddFrameStart(menu, 32); MC_AddFrameStart(menu, y);
for (i = 0; i<1 || Mods_GetMod(i); i++) for (i = 0; i<1 || Mods_GetMod(i); i++)
{ {
struct modlist_s *mod = Mods_GetMod(i); struct modlist_s *mod = Mods_GetMod(i);
c = MC_AddCustom(menu, 64, 32+i*8, menu->data, i, (mod&&mod->manifest)?mod->manifest->basedir:NULL); c = MC_AddCustom(menu, 64, y+i*8, menu->data, i, (mod&&mod->manifest)?mod->manifest->basedir:NULL);
// if (!menu->selecteditem) // if (!menu->selecteditem)
// menu->selecteditem = (menuoption_t*)c; // menu->selecteditem = (menuoption_t*)c;
c->common.height = 8; c->common.height = 8;
c->draw = Mods_Draw; c->draw = Mods_Draw;
c->key = Mods_Key; c->key = Mods_Key;
} }
MC_AddFrameEnd(menu, 32); MC_AddFrameEnd(menu, y);
} }
#if 0 #if 0
@ -4532,7 +4599,7 @@ static qboolean Installer_Go(menuoption_t *opt, menu_t *menu, int key)
#ifdef _WIN32 #ifdef _WIN32
GetModuleFileNameW(NULL, exepath, sizeof(exepath)); GetModuleFileNameW(NULL, exepath, sizeof(exepath));
FS_NativePath(va("%s.exe", fs_manifest->installation), FS_ROOT, newexepath, sizeof(newexepath)); FS_SystemPath(va("%s.exe", fs_manifest->installation), FS_ROOT, newexepath, sizeof(newexepath));
CopyFileW(exepath, newexepath, FALSE); CopyFileW(exepath, newexepath, FALSE);
// SetHookState(false); // SetHookState(false);

View file

@ -20,7 +20,7 @@ void M_Script_Option (emenu_t *menu, char *optionvalue, qboolean isexplicit)
Cbuf_AddText("wait\n", execlevel); Cbuf_AddText("wait\n", execlevel);
if (!*scriptname) if (!scriptname || !*scriptname)
{ {
if (isexplicit) if (isexplicit)
Cbuf_AddText(va("%s\n", optionvalue), execlevel); Cbuf_AddText(va("%s\n", optionvalue), execlevel);

View file

@ -319,11 +319,10 @@ void M_Menu_Load_f (void)
void M_Menu_SinglePlayer_f (void) void M_Menu_SinglePlayer_f (void)
{ {
emenu_t *menu; emenu_t *menu;
#ifndef CLIENTONLY #ifdef HAVE_SERVER
menubutton_t *b; menubutton_t *b;
mpic_t *p; mpic_t *p;
static menuresel_t resel; static menuresel_t resel;
#endif
#if MAX_SPLITS > 1 #if MAX_SPLITS > 1
static const char *splitopts[] = static const char *splitopts[] =
@ -344,15 +343,6 @@ void M_Menu_SinglePlayer_f (void)
}; };
#endif #endif
#ifdef CLIENTONLY
menu = M_CreateMenu(0);
MC_AddWhiteText(menu, 84, 0, 12*8, "This build is unable", false);
MC_AddWhiteText(menu, 84, 0, 13*8, "to start a local game", false);
MC_AddBox (menu, 60, 11*8, 25*8, 4*8);
#else
switch(M_GameType()) switch(M_GameType())
{ {
#ifdef Q2CLIENT #ifdef Q2CLIENT
@ -580,6 +570,14 @@ void M_Menu_SinglePlayer_f (void)
menu->cursoritem = (menuoption_t*)MC_AddCursor(menu, &resel, 54, 32); menu->cursoritem = (menuoption_t*)MC_AddCursor(menu, &resel, 54, 32);
} }
#else
menu = M_CreateMenu(0);
MC_AddWhiteText(menu, 84, 0, 12*8, "This build is unable", false);
MC_AddWhiteText(menu, 84, 0, 13*8, "to start a local game", false);
MC_AddBox (menu, 60, 11*8, 25*8, 4*8);
#endif #endif
} }
@ -626,9 +624,9 @@ static void M_DemoDraw(int x, int y, menucustom_t *control, emenu_t *menu)
demoitem_t *item, *lostit; demoitem_t *item, *lostit;
int ty; int ty;
char syspath[MAX_OSPATH]; char displaypath[MAX_OSPATH];
if (FS_NativePath(info->fs->path, (info->fs->fsroot==FS_GAME)?FS_GAMEONLY:info->fs->fsroot, syspath, sizeof(syspath))) if (FS_DisplayPath(info->fs->path, (info->fs->fsroot==FS_GAME)?FS_GAMEONLY:info->fs->fsroot, displaypath, sizeof(displaypath)))
Draw_FunString(x, y-16, syspath); Draw_FunString(x, y-16, displaypath);
ty = vid.height-24; ty = vid.height-24;
item = info->selected; item = info->selected;
@ -1021,7 +1019,7 @@ static void ShowDemoMenu (emenu_t *menu, const char *path)
{ {
if (!strcmp(path, "../")) if (!strcmp(path, "../"))
{ {
FS_NativePath("", FS_ROOT, info->fs->path, sizeof(info->fs->path)); FS_SystemPath("", FS_ROOT, info->fs->path, sizeof(info->fs->path));
Q_strncatz(info->fs->path, "../", sizeof(info->fs->path)); Q_strncatz(info->fs->path, "../", sizeof(info->fs->path));
info->fs->fsroot = FS_SYSTEM; info->fs->fsroot = FS_SYSTEM;
while((s = strchr(info->fs->path, '\\'))) while((s = strchr(info->fs->path, '\\')))

View file

@ -21,6 +21,9 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "winquake.h" #include "winquake.h"
#include "shader.h" #include "shader.h"
#include "cl_master.h" #include "cl_master.h"
#ifdef FTE_TARGET_WEB
#include <emscripten/emscripten.h>
#endif
menu_t *topmenu; menu_t *topmenu;
menu_t *promptmenu; menu_t *promptmenu;
@ -1302,10 +1305,8 @@ void M_Menu_Quit_f (void)
switch(mode) switch(mode)
{ {
case 0: case 0:
#ifndef FTE_TARGET_WEB
CL_Disconnect (NULL); CL_Disconnect (NULL);
Sys_Quit (); Sys_Quit ();
#endif
break; break;
case 2: case 2:
Menu_Prompt (M_Menu_DoQuitSave, NULL, localtext("You have unsaved settings\nWould you like to\nsave them now?"), "Yes", "No", "Cancel", true); Menu_Prompt (M_Menu_DoQuitSave, NULL, localtext("You have unsaved settings\nWould you like to\nsave them now?"), "Yes", "No", "Cancel", true);

View file

@ -131,7 +131,12 @@ typedef enum
PROMPT_NO = 1, PROMPT_NO = 1,
PROMPT_CANCEL = -1, PROMPT_CANCEL = -1,
} promptbutton_t; } promptbutton_t;
#ifdef HAVE_CLIENT
void Menu_Prompt (void (*callback)(void *, promptbutton_t), void *ctx, const char *messages, const char *optionyes, const char *optionno, const char *optioncancel, qboolean highpri); void Menu_Prompt (void (*callback)(void *, promptbutton_t), void *ctx, const char *messages, const char *optionyes, const char *optionno, const char *optioncancel, qboolean highpri);
#define Menu_PromptOrPrint(messages,optioncancel,highpri) Menu_Prompt(NULL, NULL, messages, NULL, NULL, optioncancel, highpri)
#else
#define Menu_PromptOrPrint(messages,optioncancel,highpri) Con_Printf("%s", messages)
#endif
#ifndef NOBUILTINMENUS #ifndef NOBUILTINMENUS

View file

@ -209,7 +209,7 @@ extern int Mod_TagNumForName (struct model_s *model, const char *name, int f
void Mod_AddSingleSurface(struct entity_s *ent, int surfaceidx, shader_t *shader, int mode); void Mod_AddSingleSurface(struct entity_s *ent, int surfaceidx, shader_t *shader, int mode);
int Mod_GetNumBones(struct model_s *model, qboolean allowtags); int Mod_GetNumBones(struct model_s *model, qboolean allowtags);
int Mod_GetBoneRelations(struct model_s *model, int firstbone, int lastbone, framestate_t *fstate, float *result); int Mod_GetBoneRelations(struct model_s *model, int firstbone, int lastbone, const struct galiasbone_s *boneinfo, const framestate_t *fstate, float *result);
int Mod_GetBoneParent(struct model_s *model, int bonenum); int Mod_GetBoneParent(struct model_s *model, int bonenum);
struct galiasbone_s *Mod_GetBoneInfo(struct model_s *model, int *numbones); struct galiasbone_s *Mod_GetBoneInfo(struct model_s *model, int *numbones);
const char *Mod_GetBoneName(struct model_s *model, int bonenum); const char *Mod_GetBoneName(struct model_s *model, int bonenum);
@ -222,11 +222,6 @@ void Draw_FunStringWidthFont(struct font_s *font, float x, float y, const void *
extern int r_regsequence; extern int r_regsequence;
#ifdef SERVERONLY
#define Mod_Q1LeafPVS Mod_LeafPVS
// qbyte *Mod_LeafPVS (struct mleaf_s *leaf, struct model_s *model, qbyte *buffer);
#endif
enum enum
{ {
TEX_NOTLOADED, TEX_NOTLOADED,
@ -314,13 +309,13 @@ struct pendingtextureinfo
uploadfmt_t encoding; //PTI_* formats uploadfmt_t encoding; //PTI_* formats
void *extrafree; //avoids some memcpys void *extrafree; //avoids some memcpys
int mipcount; unsigned int mipcount;
struct struct
{ {
void *data; void *data;
size_t datasize; //ceil(width/blockwidth)*ceil(height/blockheight)*ceil(depth/blockdepth)*blocksize - except that blockdepth is always considered 1 for now. size_t datasize; //ceil(width/blockwidth)*ceil(height/blockheight)*ceil(depth/blockdepth)*blocksize - except that blockdepth is always considered 1 for now.
int width; unsigned int width;
int height; unsigned int height;
int depth; int depth;
qboolean needfree; qboolean needfree;
} mip[72]; //enough for a 4096 cubemap. or a really smegging big 2d texture... } mip[72]; //enough for a 4096 cubemap. or a really smegging big 2d texture...

View file

@ -53,7 +53,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
typedef enum {ST_SYNC=0, ST_RAND } synctype_t; typedef enum {ST_SYNC=0, ST_RAND } synctype_t;
#endif #endif
typedef enum { ALIAS_SINGLE=0, ALIAS_GROUP, ALIAS_GROUP_SWAPPED=16777216 } aliasframetype_t; typedef enum { ALIAS_SINGLE=0, ALIAS_GROUP, ALIAS_GROUP_SWAPPED=0x01000000 } aliasframetype_t;
typedef enum { ALIAS_SKIN_SINGLE=0, ALIAS_SKIN_GROUP } aliasskintype_t; typedef enum { ALIAS_SKIN_SINGLE=0, ALIAS_SKIN_GROUP } aliasskintype_t;

View file

@ -169,10 +169,10 @@ static net_masterlist_t net_masterlist[] = {
// {MP_QUAKEWORLD, CVARFC("net_qwmasterextraHistoric", "master.teamdamage.com:27000", CVAR_NOSAVE, Net_Masterlist_Callback), "master.teamdamage.com"}, // {MP_QUAKEWORLD, CVARFC("net_qwmasterextraHistoric", "master.teamdamage.com:27000", CVAR_NOSAVE, Net_Masterlist_Callback), "master.teamdamage.com"},
//Total conversions will need to define their own in defaults.cfg or whatever. //Total conversions will need to define their own in defaults.cfg or whatever.
{MP_DPMASTER, CVARFC("net_masterextra1", "master.frag-net.com:27950 198.58.111.37:27950", CVAR_NOSAVE, Net_Masterlist_Callback)}, //admin: Eukara {MP_DPMASTER, CVARFC("net_masterextra1", "master.frag-net.com:27950", CVAR_NOSAVE, Net_Masterlist_Callback)}, //admin: Eukara
// {MP_DPMASTER, CVARFC("net_masterextra1", ""/*"ghdigital.com:27950 207.55.114.154:27950"*/, CVAR_NOSAVE, Net_Masterlist_Callback)}, //(was 69.59.212.88) admin: LordHavoc // {MP_DPMASTER, CVARFC("net_masterextra1", ""/*"ghdigital.com:27950"*/, CVAR_NOSAVE, Net_Masterlist_Callback)}, //(was 69.59.212.88) admin: LordHavoc
{MP_DPMASTER, CVARFC("net_masterextra2", "dpmaster.deathmask.net:27950 107.161.23.68:27950 [2604:180::4ac:98c1]:27950", CVAR_NOSAVE, Net_Masterlist_Callback)}, //admin: Willis {MP_DPMASTER, CVARFC("net_masterextra2", "dpmaster.deathmask.net:27950", CVAR_NOSAVE, Net_Masterlist_Callback)}, //admin: Willis
{MP_DPMASTER, CVARFC("net_masterextra3", "dpmaster.tchr.no:27950 92.62.40.73:27950", CVAR_NOSAVE, Net_Masterlist_Callback)}, //admin: tChr {MP_DPMASTER, CVARFC("net_masterextra3", "dpmaster.tchr.no:27950", CVAR_NOSAVE, Net_Masterlist_Callback)}, //admin: tChr
#else #else
{MP_DPMASTER, CVARFC("net_masterextra1", "", CVAR_NOSAVE, Net_Masterlist_Callback)}, {MP_DPMASTER, CVARFC("net_masterextra1", "", CVAR_NOSAVE, Net_Masterlist_Callback)},
{MP_DPMASTER, CVARFC("net_masterextra2", "", CVAR_NOSAVE, Net_Masterlist_Callback)}, {MP_DPMASTER, CVARFC("net_masterextra2", "", CVAR_NOSAVE, Net_Masterlist_Callback)},
@ -376,9 +376,9 @@ static void SV_Master_SingleHeartbeat(net_masterlist_t *master)
{ {
COM_Parse(master->cv.string); COM_Parse(master->cv.string);
Con_TPrintf (S_COLOR_GRAY"Sending heartbeat to %s (%s)\n", NET_AdrToString (adr, sizeof(adr), na), com_token); Con_TPrintf (S_COLOR_GRAY"Sending heartbeat to %s (%s)\n", NET_AdrToString (adr, sizeof(adr), na), com_token);
}
master->announced = true; master->announced = true;
} }
}
break; break;
case NETERR_NOROUTE: case NETERR_NOROUTE:
if (sv_reportheartbeats.value) if (sv_reportheartbeats.value)
@ -387,9 +387,9 @@ static void SV_Master_SingleHeartbeat(net_masterlist_t *master)
{ {
COM_Parse(master->cv.string); COM_Parse(master->cv.string);
Con_TPrintf (CON_WARNING"No route for heartbeat to %s (%s)\n", NET_AdrToString (adr, sizeof(adr), na), com_token); Con_TPrintf (CON_WARNING"No route for heartbeat to %s (%s)\n", NET_AdrToString (adr, sizeof(adr), na), com_token);
}
master->announced = true; master->announced = true;
} }
}
break; break;
default: default:
case NETERR_DISCONNECTED: case NETERR_DISCONNECTED:
@ -401,9 +401,9 @@ static void SV_Master_SingleHeartbeat(net_masterlist_t *master)
{ {
COM_Parse(master->cv.string); COM_Parse(master->cv.string);
Con_TPrintf (CON_ERROR"Failed to send heartbeat to %s (%s)\n", NET_AdrToString (adr, sizeof(adr), na), com_token); Con_TPrintf (CON_ERROR"Failed to send heartbeat to %s (%s)\n", NET_AdrToString (adr, sizeof(adr), na), com_token);
}
master->announced = true; master->announced = true;
} }
}
break; break;
} }
} }
@ -663,6 +663,17 @@ static void SV_Master_Add(int type, char *stringadr)
{ {
int i; int i;
//don't do dupes...
for (i = 0; net_masterlist[i].cv.name; i++)
{
if (net_masterlist[i].protocol == type)
if (!strcmp(net_masterlist[i].cv.string, stringadr))
{
svs.last_heartbeat = -99999;
return;
}
}
for (i = 0; net_masterlist[i].cv.name; i++) for (i = 0; net_masterlist[i].cv.name; i++)
{ {
if (net_masterlist[i].protocol != type) if (net_masterlist[i].protocol != type)
@ -680,6 +691,7 @@ static void SV_Master_Add(int type, char *stringadr)
} }
Cvar_Set(&net_masterlist[i].cv, stringadr); Cvar_Set(&net_masterlist[i].cv, stringadr);
Con_Printf(CON_WARNING"setting %s to \"%s\"\n", net_masterlist[i].cv.name, stringadr);
svs.last_heartbeat = -99999; svs.last_heartbeat = -99999;
} }
@ -693,6 +705,8 @@ static void SV_Master_ClearType(int type)
{ {
if (net_masterlist[i].cv.flags & CVAR_NOSAVE) if (net_masterlist[i].cv.flags & CVAR_NOSAVE)
continue; //ignore our extras continue; //ignore our extras
if (*net_masterlist[i].cv.string)
Con_Printf(CON_WARNING"clearing %s (was \"%s\")\n", net_masterlist[i].cv.name, net_masterlist[i].cv.string);
Cvar_Set(&net_masterlist[i].cv, ""); Cvar_Set(&net_masterlist[i].cv, "");
} }
} }
@ -733,7 +747,8 @@ static void SV_SetMaster_f (void)
return; return;
} }
Cvar_Set(&sv_public, "1"); //go public. if (sv_public.ival < 1)
Con_Printf(CON_WARNING"%s used on private server (sv_public is \"%s\")\n", Cmd_Argv(0), sv_public.string);
if (!strcmp(Cmd_Argv(1), "default")) if (!strcmp(Cmd_Argv(1), "default"))
{ {
for (i = 0; net_masterlist[i].cv.name; i++) for (i = 0; net_masterlist[i].cv.name; i++)
@ -741,8 +756,12 @@ static void SV_SetMaster_f (void)
return; return;
} }
i = 1;
if (!strcmp(Cmd_Argv(1), "add"))
i++;
else
SV_Master_ClearType(MP_QUAKEWORLD); SV_Master_ClearType(MP_QUAKEWORLD);
for (i=1 ; i<Cmd_Argc() ; i++) for ( ; i<Cmd_Argc() ; i++)
{ {
SV_Master_Add(MP_QUAKEWORLD, Cmd_Argv(i)); SV_Master_Add(MP_QUAKEWORLD, Cmd_Argv(i));
} }
@ -2738,7 +2757,7 @@ static void MasterInfo_ProcessHTTP(struct dl_download *dl)
infostring = NULL; infostring = NULL;
if (!strncmp(s, "ice:///", 7) || !strncmp(s, "ices:///", 8) || !strncmp(s, "rtc:///", 7) || !strncmp(s, "rtcs:///", 8)) if (!strncmp(s, "ice:///", 7) || !strncmp(s, "ices:///", 8) || !strncmp(s, "rtc:///", 7) || !strncmp(s, "rtcs:///", 8))
{ { //implicitly using the ip:port of the responder, instead of that being specified (giving a consistent route to it instead of it having to guess what hostname we used).
brokerid = s+((s[4]==':')?7:6); brokerid = s+((s[4]==':')?7:6);
adr = brokeradr; adr = brokeradr;
if (!*brokerid) if (!*brokerid)
@ -2749,6 +2768,13 @@ static void MasterInfo_ProcessHTTP(struct dl_download *dl)
brokerid = s; brokerid = s;
adr = brokeradr; adr = brokeradr;
} }
#ifndef HAVE_PACKET
else if ((*s=='[' || (*s >= '0' && *s <= '9')) && infostring)
{ //if we don't have support for udp packets here, convert any raw address to an rtc:///udp/ADDRESS one instead, via this master's brokering services... hopefully.
brokerid = va("/udp/%s", s);
adr = brokeradr;
}
#endif
else else
{ {
if (!NET_StringToAdr2(s, 80, &adr, 1, &brokerid)) if (!NET_StringToAdr2(s, 80, &adr, 1, &brokerid))
@ -3752,6 +3778,7 @@ void CL_MasterListParse(netadrtype_t adrtype, int type, qboolean slashpad)
firstserver = last; firstserver = last;
} }
#else #else
void Master_QueryServer(serverinfo_t *server){}
qboolean CL_QueryServers(void) qboolean CL_QueryServers(void)
{ {
master_t *mast; master_t *mast;

View file

@ -2651,7 +2651,7 @@ static void P_ExportAllEffects_f(void)
outf = FS_OpenVFS(fname, "wb", FS_GAMEONLY); outf = FS_OpenVFS(fname, "wb", FS_GAMEONLY);
if (!outf) if (!outf)
{ {
FS_NativePath(fname, FS_GAMEONLY, effect, sizeof(effect)); FS_DisplayPath(fname, FS_GAMEONLY, effect, sizeof(effect));
Con_TPrintf("Unable to open file %s\n", effect); Con_TPrintf("Unable to open file %s\n", effect);
return; return;
} }
@ -2679,7 +2679,7 @@ static void P_ExportAllEffects_f(void)
} }
VFS_CLOSE(outf); VFS_CLOSE(outf);
FS_NativePath(fname, FS_GAMEONLY, effect, sizeof(effect)); FS_DisplayPath(fname, FS_GAMEONLY, effect, sizeof(effect));
Con_Printf("Written %s\n", effect); Con_Printf("Written %s\n", effect);
} }
#endif #endif
@ -3398,7 +3398,7 @@ static void P_ConvertEffectInfo_f(void)
outf = FS_OpenVFS(fname, "wb", FS_GAMEONLY); outf = FS_OpenVFS(fname, "wb", FS_GAMEONLY);
if (!outf) if (!outf)
{ {
FS_NativePath(fname, FS_GAMEONLY, effect, sizeof(effect)); FS_DisplayPath(fname, FS_GAMEONLY, effect, sizeof(effect));
Con_TPrintf("Unable to open file %s\n", effect); Con_TPrintf("Unable to open file %s\n", effect);
return; return;
} }
@ -3435,7 +3435,7 @@ static void P_ConvertEffectInfo_f(void)
} }
VFS_CLOSE(outf); VFS_CLOSE(outf);
FS_NativePath(fname, FS_GAMEONLY, effect, sizeof(effect)); FS_DisplayPath(fname, FS_GAMEONLY, effect, sizeof(effect));
Con_Printf("Written %s\n", effect); Con_Printf("Written %s\n", effect);
} }
#endif #endif
@ -3534,10 +3534,10 @@ static void PScript_Shutdown (void)
Cmd_RemoveCommand("r_exportbuiltinparticles"); Cmd_RemoveCommand("r_exportbuiltinparticles");
Cmd_RemoveCommand("r_importeffectinfo"); Cmd_RemoveCommand("r_importeffectinfo");
#if _DEBUG //#if _DEBUG
Cmd_RemoveCommand("r_partinfo"); Cmd_RemoveCommand("r_partinfo");
Cmd_RemoveCommand("r_beaminfo"); Cmd_RemoveCommand("r_beaminfo");
#endif //#endif
pe_default = P_INVALID; pe_default = P_INVALID;
pe_size2 = P_INVALID; pe_size2 = P_INVALID;
@ -3809,7 +3809,7 @@ static void QDECL R_ParticleDesc_Callback(struct cvar_s *var, char *oldvalue)
if (failure) if (failure)
P_LoadParticleSet("high", true, true); P_LoadParticleSet("high", true, true);
if (cls.state) if (cls.state && cl.model_name[1])
{ {
//per-map configs. because we can. //per-map configs. because we can.
memcpy(token, "map_", 4); memcpy(token, "map_", 4);

View file

@ -542,7 +542,6 @@ void QCBUILTIN PF_cl_playingdemo (pubprogfuncs_t *prinst, struct globalvars_s *p
G_FLOAT(OFS_RETURN) = 0; G_FLOAT(OFS_RETURN) = 0;
break; break;
case DPB_MVD: case DPB_MVD:
case DPB_EZTV:
G_FLOAT(OFS_RETURN) = 2; G_FLOAT(OFS_RETURN) = 2;
break; break;
default: default:

View file

@ -221,15 +221,15 @@ static void CSQC_FindGlobals(qboolean nofuncs)
#undef globalstring #undef globalstring
#undef globalfunction #undef globalfunction
#define ensurefloat(name) if (!csqcg.name) csqcg.name = &junk._float; #define ensurefloat(name) do{if (!csqcg.name) csqcg.name = &junk._float;}while(0)
#define ensureint(name) if (!csqcg.name) csqcg.name = &junk._int; #define ensureint(name) do{if (!csqcg.name) csqcg.name = &junk._int; }while(0)
#define ensurevector(name) if (!csqcg.name) csqcg.name = junk._vector; #define ensurevector(name) do{if (!csqcg.name) csqcg.name = junk._vector;}while(0)
#define ensureentity(name) if (!csqcg.name) csqcg.name = &junk.edict; #define ensureentity(name) do{if (!csqcg.name) csqcg.name = &junk.edict; }while(0)
#define ensureprivfloat(name) if (!csqcg.name) {static pvec_t f; csqcg.name = &f;} #define ensureprivfloat(name) do{if (!csqcg.name) {static pvec_t f; csqcg.name = &f;}}while(0)
#define ensureprivint(name) if (!csqcg.name) {static pint_t i; csqcg.name = &i;} #define ensureprivint(name) do{if (!csqcg.name) {static pint_t i; csqcg.name = &i;}}while(0)
#define ensureprivvector(name) if (!csqcg.name) {static pvec3_t v; csqcg.name = v;} #define ensureprivvector(name) do{if (!csqcg.name) {static pvec3_t v; csqcg.name = v;}}while(0)
#define ensurepriventity(name) if (!csqcg.name) {static pint_t e; csqcg.name = &e;} #define ensurepriventity(name) do{if (!csqcg.name) {static pint_t e; csqcg.name = &e;}}while(0)
if (csqc_nogameaccess) if (csqc_nogameaccess)
{ {
@ -698,6 +698,8 @@ static int CS_FindModel(const char *name, int *free)
} }
for (i = 1; i < MAX_PRECACHE_MODELS; i++) for (i = 1; i < MAX_PRECACHE_MODELS; i++)
{ {
if (!cl.model_name[i])
break;
if (!strcmp(cl.model_name[i], name)) if (!strcmp(cl.model_name[i], name))
return i; return i;
} }
@ -2733,6 +2735,8 @@ static void QCBUILTIN PF_R_RenderScene(pubprogfuncs_t *prinst, struct globalvars
else else
scissored = false; scissored = false;
if (!vrui.enabled) //when we're using the vrui, this stuff needs to be part of the scene, drawn seperately for each eye
{
R_DrawNameTags(); R_DrawNameTags();
#ifdef RTLIGHTS #ifdef RTLIGHTS
R_EditLights_DrawInfo(); R_EditLights_DrawInfo();
@ -2770,6 +2774,7 @@ static void QCBUILTIN PF_R_RenderScene(pubprogfuncs_t *prinst, struct globalvars
if (r_refdef.drawcrosshair) if (r_refdef.drawcrosshair)
R2D_DrawCrosshair(); R2D_DrawCrosshair();
}
if (scissored) if (scissored)
{ {
@ -3100,7 +3105,7 @@ static model_t *csqc_setmodel(pubprogfuncs_t *prinst, csqcedict_t *ent, int mode
} }
else else
{ {
if (modelindex >= MAX_PRECACHE_MODELS) if (modelindex >= MAX_PRECACHE_MODELS || !cl.model_name[modelindex])
return NULL; return NULL;
prinst->SetStringField(prinst, (void*)ent, &ent->v->model, cl.model_name[modelindex], true); prinst->SetStringField(prinst, (void*)ent, &ent->v->model, cl.model_name[modelindex], true);
model = cl.model_precache[modelindex]; model = cl.model_precache[modelindex];
@ -3180,7 +3185,7 @@ static int PF_cs_PrecacheModel_Internal(pubprogfuncs_t *prinst, const char *mode
for (i = 1; i < MAX_PRECACHE_MODELS; i++) //Make sure that the server specified model is loaded.. for (i = 1; i < MAX_PRECACHE_MODELS; i++) //Make sure that the server specified model is loaded..
{ {
if (!*cl.model_name[i]) if (!cl.model_name[i])
break; break;
if (!strcmp(cl.model_name[i], modelname)) if (!strcmp(cl.model_name[i], modelname))
{ {
@ -3231,7 +3236,7 @@ static void QCBUILTIN PF_cs_getsoundindex (pubprogfuncs_t *prinst, struct global
//look for the server's names first... //look for the server's names first...
for (i = 1; i < MAX_PRECACHE_SOUNDS; i++) for (i = 1; i < MAX_PRECACHE_SOUNDS; i++)
{ {
if (!*cl.sound_name[i]) if (!cl.sound_name[i])
break; break;
if (!strcmp(cl.sound_name[i], s)) if (!strcmp(cl.sound_name[i], s))
{ {
@ -3265,7 +3270,7 @@ static void QCBUILTIN PF_cs_ModelnameForIndex(pubprogfuncs_t *prinst, struct glo
if (modelindex < 0 && (-modelindex) < MAX_CSMODELS) if (modelindex < 0 && (-modelindex) < MAX_CSMODELS)
G_INT(OFS_RETURN) = (int)PR_SetString(prinst, cl.model_csqcname[-modelindex]); G_INT(OFS_RETURN) = (int)PR_SetString(prinst, cl.model_csqcname[-modelindex]);
else if (modelindex >= 0 && modelindex < MAX_PRECACHE_MODELS) else if (modelindex >= 0 && modelindex < MAX_PRECACHE_MODELS && cl.model_name[modelindex])
G_INT(OFS_RETURN) = (int)PR_SetString(prinst, cl.model_name[modelindex]); G_INT(OFS_RETURN) = (int)PR_SetString(prinst, cl.model_name[modelindex]);
else else
G_INT(OFS_RETURN) = 0; G_INT(OFS_RETURN) = 0;
@ -3275,7 +3280,7 @@ static void QCBUILTIN PF_cs_SoundnameForIndex(pubprogfuncs_t *prinst, struct glo
int soundindex = G_FLOAT(OFS_PARM0); int soundindex = G_FLOAT(OFS_PARM0);
//FIXME: no private indexes. still useful for sending sound names from the ssqc via indexes. //FIXME: no private indexes. still useful for sending sound names from the ssqc via indexes.
if (soundindex >= 0 && soundindex < MAX_PRECACHE_SOUNDS) if (soundindex >= 0 && soundindex < MAX_PRECACHE_SOUNDS && cl.sound_name[soundindex])
G_INT(OFS_RETURN) = (int)PR_SetString(prinst, cl.sound_name[soundindex]); G_INT(OFS_RETURN) = (int)PR_SetString(prinst, cl.sound_name[soundindex]);
else else
G_INT(OFS_RETURN) = 0; G_INT(OFS_RETURN) = 0;
@ -5616,6 +5621,8 @@ static void QCBUILTIN PF_cs_registercommand (pubprogfuncs_t *prinst, struct glob
{ {
const char *str = PR_GetStringOfs(prinst, OFS_PARM0); const char *str = PR_GetStringOfs(prinst, OFS_PARM0);
const char *desc = (prinst->callargc>1)?PR_GetStringOfs(prinst, OFS_PARM1):NULL; const char *desc = (prinst->callargc>1)?PR_GetStringOfs(prinst, OFS_PARM1):NULL;
if (desc && !*desc)
desc = NULL;
if (!Cmd_Exists(str)) if (!Cmd_Exists(str))
Cmd_AddCommandD(str, CS_ConsoleCommand_f, desc); Cmd_AddCommandD(str, CS_ConsoleCommand_f, desc);
} }
@ -6026,7 +6033,7 @@ static void QCBUILTIN PF_DeltaListen(pubprogfuncs_t *prinst, struct globalvars_s
{ {
for (i = 1; i < MAX_PRECACHE_MODELS; i++) for (i = 1; i < MAX_PRECACHE_MODELS; i++)
{ {
if (!*cl.model_name[i]) if (!cl.model_name[i])
break; break;
if (!strcmp(cl.model_name[i], mname)) if (!strcmp(cl.model_name[i], mname))
{ {
@ -6648,13 +6655,13 @@ static void QCBUILTIN PF_resourcestatus(pubprogfuncs_t *prinst, struct globalvar
if (idx < 0) if (idx < 0)
{ {
mod = cl.model_csqcprecache[-idx]; mod = cl.model_csqcprecache[-idx];
if (!cl.model_csqcprecache[-idx] && doload) if (!cl.model_csqcprecache[-idx] && doload && cl.model_csqcname[-idx])
mod = cl.model_csqcprecache[-idx] = Mod_ForName(Mod_FixName(cl.model_csqcname[-idx], cl.model_name[1]), MLV_WARN); mod = cl.model_csqcprecache[-idx] = Mod_ForName(Mod_FixName(cl.model_csqcname[-idx], cl.model_name[1]), MLV_WARN);
} }
else if (idx > 0) else if (idx > 0)
{ {
mod = cl.model_precache[idx]; mod = cl.model_precache[idx];
if (!cl.model_precache[idx] && doload) if (!cl.model_precache[idx] && doload && cl.model_name[idx])
mod = cl.model_precache[idx] = Mod_ForName(Mod_FixName(cl.model_name[idx], cl.model_name[1]), MLV_WARN); mod = cl.model_precache[idx] = Mod_ForName(Mod_FixName(cl.model_name[idx], cl.model_name[1]), MLV_WARN);
} }
else else
@ -7119,8 +7126,8 @@ static struct {
{"processmodelevents", PF_processmodelevents, 0}, {"processmodelevents", PF_processmodelevents, 0},
{"getnextmodelevent", PF_getnextmodelevent, 0}, {"getnextmodelevent", PF_getnextmodelevent, 0},
{"getmodeleventidx", PF_getmodeleventidx, 0}, {"getmodeleventidx", PF_getmodeleventidx, 0},
{"getlocationname", PF_getlocationname, 0},
{"getlocationname", PF_getlocationname, 0},
{"crossproduct", PF_crossproduct, 0}, {"crossproduct", PF_crossproduct, 0},
{"pushmove", PF_pushmove, 0}, {"pushmove", PF_pushmove, 0},
#ifdef TERRAIN #ifdef TERRAIN
@ -7312,6 +7319,7 @@ static struct {
{"memalloc", PF_memalloc, 384}, {"memalloc", PF_memalloc, 384},
{"memfree", PF_memfree, 385}, {"memfree", PF_memfree, 385},
{"memcmp", PF_memcmp, 0},
{"memcpy", PF_memcpy, 386}, {"memcpy", PF_memcpy, 386},
{"memfill8", PF_memfill8, 387}, {"memfill8", PF_memfill8, 387},
{"memgetval", PF_memgetval, 388}, {"memgetval", PF_memgetval, 388},
@ -7854,6 +7862,24 @@ static void QDECL CSQC_World_GetFrameState(world_t *w, wedict_t *win, framestate
cs_getframestate(in, in->xv->renderflags, out); cs_getframestate(in, in->xv->renderflags, out);
} }
static qboolean CSQC_GenerateMaterial(struct shaderparsestate_s *ps, const char *materialname, void (*LoadMaterialString)(struct shaderparsestate_s *ps, const char *script))
{
COM_AssertMainThread("CSQC_GenerateMaterial");
if (csqcg.CSQC_GenerateMaterial)
{
void *pr_globals = PR_globals(csqcprogs, PR_CURRENT);
(((string_t *)pr_globals)[OFS_PARM0] = PR_TempString(csqcprogs, materialname));
PR_ExecuteProgram(csqcprogs, csqcg.CSQC_GenerateMaterial);
if (G_INT(OFS_RETURN))
{ //we got the script, now pass it to our material system to parse it.
LoadMaterialString(ps, PR_GetStringOfs(csqcprogs, OFS_RETURN));
return true;
}
}
return false;
}
static plugmaterialloaderfuncs_t csqcmaterialloader = {"csqc", CSQC_GenerateMaterial};
void CSQC_Shutdown(void) void CSQC_Shutdown(void)
{ {
int i; int i;
@ -7862,6 +7888,8 @@ void CSQC_Shutdown(void)
if (csqcg.CSQC_Shutdown) if (csqcg.CSQC_Shutdown)
PR_ExecuteProgram(csqcprogs, csqcg.CSQC_Shutdown); PR_ExecuteProgram(csqcprogs, csqcg.CSQC_Shutdown);
Material_RegisterLoader(&csqc_world, NULL);
key_dest_absolutemouse &= ~kdm_game; key_dest_absolutemouse &= ~kdm_game;
CSQC_ForgetThreads(); CSQC_ForgetThreads();
PR_ReleaseFonts(kdm_game); PR_ReleaseFonts(kdm_game);
@ -7949,11 +7977,11 @@ static void *CSQC_FindMainProgs(size_t *sz, const char *name, unsigned int check
if (!file) if (!file)
{ {
const char *progsname = InfoBuf_ValueForKey(&cl.serverinfo, "*csprogsname"); const char *progsname = cls.state?InfoBuf_ValueForKey(&cl.serverinfo, "*csprogsname"):"csprogs.dat";
flocation_t loc={0}; flocation_t loc={0};
vfsfile_t *f; vfsfile_t *f;
qboolean found = false; qboolean found = false;
if (!found && *progsname && cls.state) if (!found && *progsname)
found = FS_FLocateFile(progsname, FSLF_IGNOREPURE, &loc); found = FS_FLocateFile(progsname, FSLF_IGNOREPURE, &loc);
if (!found && strcmp(progsname, "csprogs.dat")) if (!found && strcmp(progsname, "csprogs.dat"))
{ {
@ -7971,8 +7999,12 @@ static void *CSQC_FindMainProgs(size_t *sz, const char *name, unsigned int check
{ {
if (checksum && !csprogs_promiscuous) if (checksum && !csprogs_promiscuous)
{ {
if (!CSQC_ValidateMainCSProgs(file, *sz, checksum, checksize))
{ //its not a match... maybe we can get a better one from the pure paths instead...
file = COM_LoadTempFile (progsname, 0, sz);
if (!CSQC_ValidateMainCSProgs(file, *sz, checksum, checksize)) if (!CSQC_ValidateMainCSProgs(file, *sz, checksum, checksize))
file = NULL; file = NULL;
}
//we write the csprogs into our archive if it was loaded from outside of there. //we write the csprogs into our archive if it was loaded from outside of there.
//this is to ensure that demos will play on the same machine later on... //this is to ensure that demos will play on the same machine later on...
@ -8429,6 +8461,9 @@ qboolean CSQC_Init (qboolean anycsqc, const char *csprogsname, unsigned int chec
csqcentsize = PR_InitEnts(csqcprogs, pr_csqc_maxedicts.value); csqcentsize = PR_InitEnts(csqcprogs, pr_csqc_maxedicts.value);
if (csqcg.CSQC_GenerateMaterial)
Material_RegisterLoader(&csqc_world, &csqcmaterialloader);
//world edict becomes readonly //world edict becomes readonly
worldent = (csqcedict_t *)EDICT_NUM_PB(csqcprogs, 0); worldent = (csqcedict_t *)EDICT_NUM_PB(csqcprogs, 0);
worldent->ereftype = ER_ENTITY; worldent->ereftype = ER_ENTITY;
@ -8455,7 +8490,7 @@ qboolean CSQC_Init (qboolean anycsqc, const char *csprogsname, unsigned int chec
char *s = InfoBuf_ValueForKey(&cl.serverinfo, "map"); char *s = InfoBuf_ValueForKey(&cl.serverinfo, "map");
if (!*s) if (!*s)
s = cl.model_name[1]; s = cl.model_name[1];
if (!*s) if (!s || !*s)
s = "unknown"; s = "unknown";
*str = PR_NewString(csqcprogs, s); *str = PR_NewString(csqcprogs, s);
} }

View file

@ -1351,6 +1351,7 @@ static struct
{ {
evalc_t chain; evalc_t chain;
evalc_t model; evalc_t model;
evalc_t modelindex;
evalc_t mins; evalc_t mins;
evalc_t maxs; evalc_t maxs;
evalc_t origin; evalc_t origin;
@ -1364,6 +1365,7 @@ static struct
evalc_t frame2time; evalc_t frame2time;
evalc_t renderflags; evalc_t renderflags;
evalc_t skinobject; evalc_t skinobject;
evalc_t skelobject;
evalc_t colourmod; evalc_t colourmod;
evalc_t alpha; evalc_t alpha;
} menuc_eval; } menuc_eval;
@ -2034,6 +2036,23 @@ static void QCBUILTIN PF_m_precache_model(pubprogfuncs_t *prinst, struct globalv
const char *modelname = PR_GetStringOfs(prinst, OFS_PARM0); const char *modelname = PR_GetStringOfs(prinst, OFS_PARM0);
Mod_ForName(modelname, MLV_WARN); Mod_ForName(modelname, MLV_WARN);
} }
static model_t *QDECL MP_GetCModel(struct world_s *w, int modelindex)
{
extern int mod_numknown;
modelindex--;
if (modelindex < 0 || modelindex >= mod_numknown)
return NULL;
return &mod_known[modelindex];
}
static void QCBUILTIN PF_m_getmodelindex(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
const char *modelname = PR_GetStringOfs(prinst, OFS_PARM0);
model_t *m = Mod_ForName(modelname, MLV_WARN);
if (m)
G_FLOAT(OFS_RETURN) = (m-mod_known)+1;
else
G_FLOAT(OFS_RETURN) = 0;
}
static void QCBUILTIN PF_m_setmodel(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) static void QCBUILTIN PF_m_setmodel(pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{ {
menuedict_t *ent = (void*)G_EDICT(prinst, OFS_PARM0); menuedict_t *ent = (void*)G_EDICT(prinst, OFS_PARM0);
@ -2041,6 +2060,7 @@ static void QCBUILTIN PF_m_setmodel(pubprogfuncs_t *prinst, struct globalvars_s
eval_t *modelval = prinst->GetEdictFieldValue(prinst, (void*)ent, "model", ev_string, &menuc_eval.model); eval_t *modelval = prinst->GetEdictFieldValue(prinst, (void*)ent, "model", ev_string, &menuc_eval.model);
eval_t *minsval = prinst->GetEdictFieldValue(prinst, (void*)ent, "mins", ev_vector, &menuc_eval.mins); eval_t *minsval = prinst->GetEdictFieldValue(prinst, (void*)ent, "mins", ev_vector, &menuc_eval.mins);
eval_t *maxsval = prinst->GetEdictFieldValue(prinst, (void*)ent, "maxs", ev_vector, &menuc_eval.maxs); eval_t *maxsval = prinst->GetEdictFieldValue(prinst, (void*)ent, "maxs", ev_vector, &menuc_eval.maxs);
eval_t *modelidxval = prinst->GetEdictFieldValue(prinst, (void*)ent, "modelindex", ev_float, &menuc_eval.modelindex);
model_t *mod = Mod_ForName(modelname, MLV_WARN); model_t *mod = Mod_ForName(modelname, MLV_WARN);
if (modelval) if (modelval)
modelval->string = G_INT(OFS_PARM1); //lets hope garbage collection is enough. modelval->string = G_INT(OFS_PARM1); //lets hope garbage collection is enough.
@ -2050,6 +2070,8 @@ static void QCBUILTIN PF_m_setmodel(pubprogfuncs_t *prinst, struct globalvars_s
if (mod) if (mod)
while(mod->loadstate == MLS_LOADING) while(mod->loadstate == MLS_LOADING)
COM_WorkerPartialSync(mod, &mod->loadstate, MLS_LOADING); COM_WorkerPartialSync(mod, &mod->loadstate, MLS_LOADING);
if (modelidxval)
modelidxval->_float = mod?(mod-mod_known)+1:0;
if (mod && minsval) if (mod && minsval)
VectorCopy(mod->mins, minsval->_vector); VectorCopy(mod->mins, minsval->_vector);
@ -2110,6 +2132,44 @@ static void QCBUILTIN PF_m_clearscene(pubprogfuncs_t *prinst, struct globalvars_
V_CalcRefdef(&menuview); //set up the defaults V_CalcRefdef(&menuview); //set up the defaults
r_refdef.flags |= RDF_NOWORLDMODEL; r_refdef.flags |= RDF_NOWORLDMODEL;
} }
static void QDECL MP_Read_FrameState(pubprogfuncs_t *prinst, wedict_t *ent, framestate_t *fstate)
{
eval_t *frame1val = prinst->GetEdictFieldValue(prinst, (void*)ent, "frame", ev_float, &menuc_eval.frame1);
eval_t *frame2val = prinst->GetEdictFieldValue(prinst, (void*)ent, "frame2", ev_float, &menuc_eval.frame2);
eval_t *lerpfracval = prinst->GetEdictFieldValue(prinst, (void*)ent, "lerpfrac", ev_float, &menuc_eval.lerpfrac);
eval_t *frame1timeval = prinst->GetEdictFieldValue(prinst, (void*)ent, "frame1time", ev_float, &menuc_eval.frame1time);
eval_t *frame2timeval = prinst->GetEdictFieldValue(prinst, (void*)ent, "frame2time", ev_float, &menuc_eval.frame2time);
eval_t *skelobjectval = prinst->GetEdictFieldValue(prinst, (void*)ent, "skeletonindex", ev_float, &menuc_eval.skelobject);
fstate->g[FST_BASE].endbone = 0;
fstate->g[FS_REG].endbone = 0x7fffffff;
fstate->g[FS_REG].frame[0] = frame1val?frame1val->_float:0;
fstate->g[FS_REG].frame[1] = frame2val?frame2val->_float:0;
fstate->g[FS_REG].lerpweight[1] = lerpfracval?lerpfracval->_float:0;
fstate->g[FS_REG].frametime[0] = frame1timeval?frame1timeval->_float:0;
fstate->g[FS_REG].frametime[1] = frame2timeval?frame2timeval->_float:0;
#if FRAME_BLENDS >= 4
fstate->g[FS_REG].frame[2] = fstate->g[FS_REG].frame[0];
fstate->g[FS_REG].lerpweight[2] = 0;
fstate->g[FS_REG].frame[3] = fstate->g[FS_REG].frame[0];
fstate->g[FS_REG].lerpweight[3] = 0;
fstate->g[FS_REG].lerpweight[0] = 1-(fstate->g[FS_REG].lerpweight[1]+fstate->g[FS_REG].lerpweight[2]+fstate->g[FS_REG].lerpweight[3]);
#else
fstate->g[FS_REG].lerpweight[0] = 1-fstate->g[FS_REG].lerpweight[1];
#endif
#if defined(SKELETALOBJECTS) || defined(RAGDOLL)
fstate->bonecount = 0;
fstate->bonestate = NULL;
if (skelobjectval && skelobjectval->_float)
skel_lookup(&menu_world, skelobjectval->_float, fstate);
#endif
}
static void QDECL MP_Get_FrameState(struct world_s *w, wedict_t *ent, framestate_t *fstate)
{
MP_Read_FrameState(w->progs, ent, fstate);
}
static qboolean CopyMenuEdictToEntity(pubprogfuncs_t *prinst, menuedict_t *in, entity_t *out) static qboolean CopyMenuEdictToEntity(pubprogfuncs_t *prinst, menuedict_t *in, entity_t *out)
{ {
eval_t *modelval = prinst->GetEdictFieldValue(prinst, (void*)in, "model", ev_string, &menuc_eval.model); eval_t *modelval = prinst->GetEdictFieldValue(prinst, (void*)in, "model", ev_string, &menuc_eval.model);
@ -2121,6 +2181,7 @@ static qboolean CopyMenuEdictToEntity(pubprogfuncs_t *prinst, menuedict_t *in, e
eval_t *lerpfracval = prinst->GetEdictFieldValue(prinst, (void*)in, "lerpfrac", ev_float, &menuc_eval.lerpfrac); eval_t *lerpfracval = prinst->GetEdictFieldValue(prinst, (void*)in, "lerpfrac", ev_float, &menuc_eval.lerpfrac);
eval_t *frame1timeval = prinst->GetEdictFieldValue(prinst, (void*)in, "frame1time", ev_float, &menuc_eval.frame1time); eval_t *frame1timeval = prinst->GetEdictFieldValue(prinst, (void*)in, "frame1time", ev_float, &menuc_eval.frame1time);
eval_t *frame2timeval = prinst->GetEdictFieldValue(prinst, (void*)in, "frame2time", ev_float, &menuc_eval.frame2time); eval_t *frame2timeval = prinst->GetEdictFieldValue(prinst, (void*)in, "frame2time", ev_float, &menuc_eval.frame2time);
eval_t *skelobjectval = prinst->GetEdictFieldValue(prinst, (void*)in, "skeletonindex", ev_float, &menuc_eval.skelobject);
eval_t *colormapval = prinst->GetEdictFieldValue(prinst, (void*)in, "colormap", ev_float, &menuc_eval.colormap); eval_t *colormapval = prinst->GetEdictFieldValue(prinst, (void*)in, "colormap", ev_float, &menuc_eval.colormap);
eval_t *renderflagsval = prinst->GetEdictFieldValue(prinst, (void*)in, "renderflags", ev_float, &menuc_eval.renderflags); eval_t *renderflagsval = prinst->GetEdictFieldValue(prinst, (void*)in, "renderflags", ev_float, &menuc_eval.renderflags);
eval_t *skinobjectval = prinst->GetEdictFieldValue(prinst, (void*)in, "skinobject", ev_float, &menuc_eval.skinobject); eval_t *skinobjectval = prinst->GetEdictFieldValue(prinst, (void*)in, "skinobject", ev_float, &menuc_eval.skinobject);
@ -2149,6 +2210,13 @@ static qboolean CopyMenuEdictToEntity(pubprogfuncs_t *prinst, menuedict_t *in, e
out->framestate.g[FS_REG].frametime[0] = frame1timeval?frame1timeval->_float:0; out->framestate.g[FS_REG].frametime[0] = frame1timeval?frame1timeval->_float:0;
out->framestate.g[FS_REG].frametime[1] = frame2timeval?frame2timeval->_float:0; out->framestate.g[FS_REG].frametime[1] = frame2timeval?frame2timeval->_float:0;
#if defined(SKELETALOBJECTS) || defined(RAGDOLL)
out->framestate.bonecount = 0;
out->framestate.bonestate = NULL;
if (skelobjectval && skelobjectval->_float)
skel_lookup(&menu_world, skelobjectval->_float, &out->framestate);
#endif
out->customskin = skinobjectval?skinobjectval->_float:0; out->customskin = skinobjectval?skinobjectval->_float:0;
//FIXME: colourmap //FIXME: colourmap
@ -2285,6 +2353,8 @@ static void QCBUILTIN PF_menu_registercommand (pubprogfuncs_t *prinst, struct gl
{ {
const char *str = PR_GetStringOfs(prinst, OFS_PARM0); const char *str = PR_GetStringOfs(prinst, OFS_PARM0);
const char *desc = (prinst->callargc>1)?PR_GetStringOfs(prinst, OFS_PARM1):NULL; const char *desc = (prinst->callargc>1)?PR_GetStringOfs(prinst, OFS_PARM1):NULL;
if (desc && !*desc)
desc = NULL;
if (!Cmd_Exists(str)) if (!Cmd_Exists(str))
Cmd_AddCommandD(str, MP_ConsoleCommand_f, desc); Cmd_AddCommandD(str, MP_ConsoleCommand_f, desc);
} }
@ -2466,6 +2536,8 @@ static struct {
{"precache_model", PF_m_precache_model, 91}, {"precache_model", PF_m_precache_model, 91},
{"setorigin", PF_m_setorigin, 92}, {"setorigin", PF_m_setorigin, 92},
//gap //gap
{"getmodelindex", PF_m_getmodelindex, 200},
//gap
{"abort", PF_Abort, 211}, {"abort", PF_Abort, 211},
//gap //gap
{"strstrofs", PF_strstrofs, 221}, {"strstrofs", PF_strstrofs, 221},
@ -2484,6 +2556,29 @@ static struct {
{"shaderforname", PF_shaderforname, 238}, {"shaderforname", PF_shaderforname, 238},
{"sendpacket", PF_cl_SendPacket, 242}, {"sendpacket", PF_cl_SendPacket, 242},
//gap //gap
{"skel_create", PF_skel_create, 263},//float(float modlindex) skel_create = #263; // (FTE_CSQC_SKELETONOBJECTS)
{"skel_build", PF_skel_build, 264},//float(float skel, entity ent, float modelindex, float retainfrac, float firstbone, float lastbone, optional float addition) skel_build = #264; // (FTE_CSQC_SKELETONOBJECTS)
{"skel_build_ptr", PF_skel_build_ptr, 0},//float(float skel, int numblends, __variant *blends, int blendsize) skel_build_ptr = #0;
{"skel_get_numbones", PF_skel_get_numbones, 265},//float(float skel) skel_get_numbones = #265; // (FTE_CSQC_SKELETONOBJECTS)
{"skel_get_bonename", PF_skel_get_bonename, 266},//string(float skel, float bonenum) skel_get_bonename = #266; // (FTE_CSQC_SKELETONOBJECTS) (returns tempstring)
{"skel_get_boneparent", PF_skel_get_boneparent, 267},//float(float skel, float bonenum) skel_get_boneparent = #267; // (FTE_CSQC_SKELETONOBJECTS)
{"skel_find_bone", PF_skel_find_bone, 268},//float(float skel, string tagname) skel_get_boneidx = #268; // (FTE_CSQC_SKELETONOBJECTS)
{"skel_get_bonerel", PF_skel_get_bonerel, 269},//vector(float skel, float bonenum) skel_get_bonerel = #269; // (FTE_CSQC_SKELETONOBJECTS) (sets v_forward etc)
{"skel_get_boneabs", PF_skel_get_boneabs, 270},//vector(float skel, float bonenum) skel_get_boneabs = #270; // (FTE_CSQC_SKELETONOBJECTS) (sets v_forward etc)
{"skel_set_bone", PF_skel_set_bone, 271},//void(float skel, float bonenum, vector org) skel_set_bone = #271; // (FTE_CSQC_SKELETONOBJECTS) (reads v_forward etc)
{"skel_premul_bone", PF_skel_premul_bone, 272},//void(float skel, float bonenum, vector org) skel_mul_bone = #272; // (FTE_CSQC_SKELETONOBJECTS) (reads v_forward etc)
{"skel_premul_bones", PF_skel_premul_bones, 273},//void(float skel, float startbone, float endbone, vector org) skel_mul_bone = #273; // (FTE_CSQC_SKELETONOBJECTS) (reads v_forward etc)
{"skel_postmul_bone", PF_skel_postmul_bone, 0},//void(float skel, float bonenum, vector org) skel_mul_bone = #272; // (FTE_CSQC_SKELETONOBJECTS) (reads v_forward etc)
// {"skel_postmul_bones", PF_skel_postmul_bones, 0},//void(float skel, float startbone, float endbone, vector org) skel_mul_bone = #273; // (FTE_CSQC_SKELETONOBJECTS) (reads v_forward etc)
{"skel_copybones", PF_skel_copybones, 274},//void(float skeldst, float skelsrc, float startbone, float entbone) skel_copybones = #274; // (FTE_CSQC_SKELETONOBJECTS)
{"skel_delete", PF_skel_delete, 275},//void(float skel) skel_delete = #275; // (FTE_CSQC_SKELETONOBJECTS)
{"frameforname", PF_frameforname, 276},//float(float modidx, string framename) frameforname = #276 (FTE_CSQC_SKELETONOBJECTS)
{"frameduration", PF_frameduration, 277},//float(float modidx, float framenum) frameduration = #277 (FTE_CSQC_SKELETONOBJECTS)
{"frameforaction", PF_frameforaction, 0},//float(float modidx, int actionid) frameforaction = #0
{"processmodelevents", PF_processmodelevents, 0},
{"getnextmodelevent", PF_getnextmodelevent, 0},
{"getmodeleventidx", PF_getmodeleventidx, 0},
//gap
{"hash_createtab", PF_hash_createtab, 287}, {"hash_createtab", PF_hash_createtab, 287},
{"hash_destroytab", PF_hash_destroytab, 288}, {"hash_destroytab", PF_hash_destroytab, 288},
{"hash_add", PF_hash_add, 289}, {"hash_add", PF_hash_add, 289},
@ -2555,6 +2650,7 @@ static struct {
//gap //gap
{"memalloc", PF_memalloc, 384}, {"memalloc", PF_memalloc, 384},
{"memfree", PF_memfree, 385}, {"memfree", PF_memfree, 385},
{"memcmp", PF_memcmp, 0},
{"memcpy", PF_memcpy, 386}, {"memcpy", PF_memcpy, 386},
{"memfill8", PF_memfill8, 387}, {"memfill8", PF_memfill8, 387},
{"memgetval", PF_memgetval, 388}, {"memgetval", PF_memgetval, 388},
@ -3163,8 +3259,12 @@ qboolean MP_Init (void)
menutime = Sys_DoubleTime(); menutime = Sys_DoubleTime();
if (!menu_world.progs) if (!menu_world.progs)
{ {
vec3_t fwd,rht,up;
int mprogs; int mprogs;
Con_DPrintf("Initializing menu.dat\n"); Con_DPrintf("Initializing menu.dat\n");
menu_world.Get_CModel = MP_GetCModel;
menu_world.Get_FrameState = MP_Get_FrameState;
menu_world.progs = InitProgs(&menuprogparms); menu_world.progs = InitProgs(&menuprogparms);
PR_Configure(menu_world.progs, PR_ReadBytesString(pr_menu_memsize.string), 1, pr_enable_profiling.ival); PR_Configure(menu_world.progs, PR_ReadBytesString(pr_menu_memsize.string), 1, pr_enable_profiling.ival);
mprogs = PR_LoadProgs(menu_world.progs, "menu.dat"); mprogs = PR_LoadProgs(menu_world.progs, "menu.dat");
@ -3193,6 +3293,10 @@ qboolean MP_Init (void)
*menu_world.g.time = Sys_DoubleTime(); *menu_world.g.time = Sys_DoubleTime();
menu_world.g.frametime = (float*)PR_FindGlobal(menu_world.progs, "frametime", 0, NULL); menu_world.g.frametime = (float*)PR_FindGlobal(menu_world.progs, "frametime", 0, NULL);
menu_world.g.v_forward = (float*)PR_FindGlobal(menu_world.progs, "v_forward", 0, NULL); if (!menu_world.g.v_forward) menu_world.g.v_forward = fwd;
menu_world.g.v_right = (float*)PR_FindGlobal(menu_world.progs, "v_right", 0, NULL); if (!menu_world.g.v_right) menu_world.g.v_right = rht;
menu_world.g.v_up = (float*)PR_FindGlobal(menu_world.progs, "v_up", 0, NULL); if (!menu_world.g.v_up) menu_world.g.v_up = up;
menu_world.g.drawfont = (float*)PR_FindGlobal(menu_world.progs, "drawfont", 0, NULL); menu_world.g.drawfont = (float*)PR_FindGlobal(menu_world.progs, "drawfont", 0, NULL);
menu_world.g.drawfontscale = (float*)PR_FindGlobal(menu_world.progs, "drawfontscale", 0, NULL); menu_world.g.drawfontscale = (float*)PR_FindGlobal(menu_world.progs, "drawfontscale", 0, NULL);

View file

@ -1625,7 +1625,7 @@ void rag_updatedeltaent(world_t *w, entity_t *ent, lerpents_t *le)
sko->numanimated = 0; sko->numanimated = 0;
else if (sko->doll) else if (sko->doll)
sko->numanimated = sko->doll->numdefaultanimated; sko->numanimated = sko->doll->numdefaultanimated;
Mod_GetBoneRelations(mod, 0, skorel.numbones, &ent->framestate, skorel.bonematrix); Mod_GetBoneRelations(mod, 0, skorel.numbones, NULL, &ent->framestate, skorel.bonematrix);
skorel.modelindex = sko->modelindex; skorel.modelindex = sko->modelindex;
skorel.model = sko->model; skorel.model = sko->model;
if (sko->numanimated || sko->doll != mod->dollinfo) if (sko->numanimated || sko->doll != mod->dollinfo)
@ -1932,6 +1932,7 @@ void QCBUILTIN PF_skel_build(pubprogfuncs_t *prinst, struct globalvars_s *pr_glo
framestate_t fstate; framestate_t fstate;
skelobject_t *skelobj; skelobject_t *skelobj;
model_t *model; model_t *model;
galiasbone_t *boneinfo;
//default to failure //default to failure
G_FLOAT(OFS_RETURN) = 0; G_FLOAT(OFS_RETURN) = 0;
@ -1946,19 +1947,27 @@ void QCBUILTIN PF_skel_build(pubprogfuncs_t *prinst, struct globalvars_s *pr_glo
fstate.bonecount = 0; fstate.bonecount = 0;
fstate.bonestate = NULL; fstate.bonestate = NULL;
if (!skelidx)
{
numbones = Mod_GetNumBones(model, false); numbones = Mod_GetNumBones(model, false);
if (!numbones) if (!numbones)
{ {
return; //this isn't a skeletal model. return; //this isn't a skeletal model.
} }
if (!skelidx)
skelobj = skel_create(w, numbones); skelobj = skel_create(w, numbones);
}
else else
skelobj = skel_get(w, skelidx); skelobj = skel_get(w, skelidx);
if (!skelobj) if (!skelobj)
return; //couldn't get one, ran out of memory or something? return; //couldn't get one, ran out of memory or something?
if (skelobj->model)
boneinfo = Mod_GetBoneInfo(skelobj->model, &numbones);
else
boneinfo = NULL;
numbones = skelobj->numbones;
if (lastbone < 0) if (lastbone < 0)
lastbone = numbones; lastbone = numbones;
if (lastbone > numbones) if (lastbone > numbones)
@ -1980,15 +1989,15 @@ void QCBUILTIN PF_skel_build(pubprogfuncs_t *prinst, struct globalvars_s *pr_glo
if (retainfrac == 0) if (retainfrac == 0)
{ {
if (addition == 1) /*replace everything*/ if (addition == 0) /*wipe it*/
Mod_GetBoneRelations(model, firstbone, lastbone, &fstate, skelobj->bonematrix);
else if (addition == 0) /*wipe it*/
memset(skelobj->bonematrix + firstbone*12, 0, sizeof(float)*12*(lastbone-firstbone)); memset(skelobj->bonematrix + firstbone*12, 0, sizeof(float)*12*(lastbone-firstbone));
else if (addition == 1) /*replace everything*/
Mod_GetBoneRelations(model, firstbone, lastbone, boneinfo, &fstate, skelobj->bonematrix);
else else
{ {
//scale new //scale new
float relationsbuf[MAX_BONES*12]; float relationsbuf[MAX_BONES*12];
Mod_GetBoneRelations(model, firstbone, lastbone, &fstate, relationsbuf); Mod_GetBoneRelations(model, firstbone, lastbone, boneinfo, &fstate, relationsbuf);
for (i = firstbone; i < lastbone; i++) for (i = firstbone; i < lastbone; i++)
{ {
for (j = 0; j < 12; j++) for (j = 0; j < 12; j++)
@ -1998,6 +2007,8 @@ void QCBUILTIN PF_skel_build(pubprogfuncs_t *prinst, struct globalvars_s *pr_glo
} }
else else
{ {
float relationsbuf[MAX_BONES*12];
if (retainfrac != 1) if (retainfrac != 1)
{ {
//rescale the existing bones //rescale the existing bones
@ -2007,22 +2018,19 @@ void QCBUILTIN PF_skel_build(pubprogfuncs_t *prinst, struct globalvars_s *pr_glo
skelobj->bonematrix[i*12+j] *= retainfrac; skelobj->bonematrix[i*12+j] *= retainfrac;
} }
} }
//just add
Mod_GetBoneRelations(model, firstbone, lastbone, boneinfo, &fstate, relationsbuf);
if (addition == 1) if (addition == 1)
{ {
//just add
float relationsbuf[MAX_BONES*12];
Mod_GetBoneRelations(model, firstbone, lastbone, &fstate, relationsbuf);
for (i = firstbone; i < lastbone; i++) for (i = firstbone; i < lastbone; i++)
{ {
for (j = 0; j < 12; j++) for (j = 0; j < 12; j++)
skelobj->bonematrix[i*12+j] += relationsbuf[i*12+j]; skelobj->bonematrix[i*12+j] += relationsbuf[i*12+j];
} }
} }
else if (addition) else
{ {
//add+scale
float relationsbuf[MAX_BONES*12];
Mod_GetBoneRelations(model, firstbone, lastbone, &fstate, relationsbuf);
for (i = firstbone; i < lastbone; i++) for (i = firstbone; i < lastbone; i++)
{ {
for (j = 0; j < 12; j++) for (j = 0; j < 12; j++)
@ -2068,6 +2076,7 @@ void QCBUILTIN PF_skel_build_ptr(pubprogfuncs_t *prinst, struct globalvars_s *pr
int numbones, firstbone, lastbone; int numbones, firstbone, lastbone;
model_t *model; model_t *model;
qboolean noadd; qboolean noadd;
const galiasbone_t *boneinfo = NULL;
//default to failure //default to failure
G_FLOAT(OFS_RETURN) = 0; G_FLOAT(OFS_RETURN) = 0;
@ -2170,7 +2179,7 @@ void QCBUILTIN PF_skel_build_ptr(pubprogfuncs_t *prinst, struct globalvars_s *pr
} }
} }
else if (blends->prescale == 0) //new data only. directly replace the existing data else if (blends->prescale == 0) //new data only. directly replace the existing data
Mod_GetBoneRelations(model, firstbone, lastbone, &fstate, skelobj->bonematrix); Mod_GetBoneRelations(model, firstbone, lastbone, boneinfo, &fstate, skelobj->bonematrix);
else else
{ {
if (blends->prescale != 1) if (blends->prescale != 1)
@ -2183,7 +2192,7 @@ void QCBUILTIN PF_skel_build_ptr(pubprogfuncs_t *prinst, struct globalvars_s *pr
} }
} }
Mod_GetBoneRelations(model, firstbone, lastbone, &fstate, relationsbuf); Mod_GetBoneRelations(model, firstbone, lastbone, boneinfo, &fstate, relationsbuf);
for (i = firstbone; i < lastbone; i++) for (i = firstbone; i < lastbone; i++)
{ {
for (j = 0; j < 12; j++) for (j = 0; j < 12; j++)
@ -2671,10 +2680,10 @@ void QCBUILTIN PF_frametoname (pubprogfuncs_t *prinst, struct globalvars_s *pr_g
{ {
world_t *w = prinst->parms->user; world_t *w = prinst->parms->user;
int modelindex = G_FLOAT(OFS_PARM0); int modelindex = G_FLOAT(OFS_PARM0);
unsigned int skinnum = G_FLOAT(OFS_PARM1); unsigned int animnum = G_FLOAT(OFS_PARM1);
int surfaceidx = 0; int surfaceidx = 0;
model_t *mod = w->Get_CModel(w, modelindex); model_t *mod = w->Get_CModel(w, modelindex);
const char *n = Mod_FrameNameForNum(mod, surfaceidx, skinnum); const char *n = Mod_FrameNameForNum(mod, surfaceidx, animnum);
if (n) if (n)
RETURN_TSTRING(n); RETURN_TSTRING(n);

View file

@ -208,7 +208,7 @@ extern "C" {
#endif #endif
#if defined(Q3CLIENT) || defined(Q3SERVER) #if defined(Q3CLIENT) || defined(Q3SERVER)
#include "q3api.h" #include "../common/q3api.h"
#endif #endif
#ifdef __cplusplus #ifdef __cplusplus

View file

@ -876,7 +876,7 @@ static void Surf_StoreLightmap_RGB(qbyte *dest, unsigned int *bl, int smax, int
switch(lm->fmt) switch(lm->fmt)
{ {
default: default:
Sys_Error("Bad lightmap_fmt\n"); Sys_Error("Surf_StoreLightmap_RGB: Bad format - %s\n", Image_FormatName(lm->fmt));
break; break;
case PTI_A2BGR10: case PTI_A2BGR10:
stride = (lm->width-smax)<<2; stride = (lm->width-smax)<<2;
@ -1492,7 +1492,7 @@ static void Surf_BuildLightMap (model_t *model, msurface_t *surf, int map, int s
// add all the lightmaps // add all the lightmaps
if (src) if (src)
{ {
if (model->fromgame == fg_quake3) if (model->lightmaps.prebaked)
Sys_Error("Surf_BuildLightMap: q3bsp"); Sys_Error("Surf_BuildLightMap: q3bsp");
switch(model->lightmaps.fmt) switch(model->lightmaps.fmt)
{ {
@ -1773,7 +1773,7 @@ static void Surf_BuildLightMap_Worker (model_t *wmodel, msurface_t *surf, int sh
// add all the lightmaps // add all the lightmaps
if (src) if (src)
{ {
if (wmodel->fromgame == fg_quake3) //rgb if (wmodel->lightmaps.prebaked) //rgb
{ {
/*q3 lightmaps are meant to be pre-built /*q3 lightmaps are meant to be pre-built
this code is misguided, and ought never be executed anyway. this code is misguided, and ought never be executed anyway.
@ -1790,6 +1790,7 @@ static void Surf_BuildLightMap_Worker (model_t *wmodel, msurface_t *surf, int sh
bl+=3; bl+=3;
} }
} }
Sys_Error("Surf_BuildLightMap_Worker: q3bsp");
} }
else switch(wmodel->lightmaps.fmt) else switch(wmodel->lightmaps.fmt)
{ {
@ -2055,7 +2056,11 @@ dynamic:
#ifdef _DEBUG #ifdef _DEBUG
if ((unsigned)fa->lightmaptexturenums[0] >= numlightmaps) if ((unsigned)fa->lightmaptexturenums[0] >= numlightmaps)
Sys_Error("Invalid lightmap index\n"); {
static float throttle;
Con_ThrottlePrintf(&throttle, 0, CON_WARNING"Invalid lightmap index\n");
return;
}
#endif #endif
@ -2303,7 +2308,7 @@ void Surf_GenBrushBatches(batch_t **batches, entity_t *ent)
// calculate dynamic lighting for bmodel if it's not an // calculate dynamic lighting for bmodel if it's not an
// instanced model // instanced model
if (model->fromgame != fg_quake3 && model->fromgame != fg_doom3 && lightmap && !(webo_blocklightmapupdates&1)) if (!model->lightmaps.prebaked && lightmap && !(webo_blocklightmapupdates&1))
{ {
int k; int k;
@ -3094,7 +3099,7 @@ void Surf_DrawWorld (void)
gennew = true; //generate an initial one, if we can. gennew = true; //generate an initial one, if we can.
else else
{ {
if (!gennew && currentmodel->fromgame != fg_quake3) if (!gennew && !currentmodel->lightmaps.prebaked)
{ {
int i = cl_max_lightstyles; int i = cl_max_lightstyles;
for (i = 0; i < cl_max_lightstyles; i++) for (i = 0; i < cl_max_lightstyles; i++)
@ -3449,6 +3454,8 @@ uploadfmt_t Surf_NameToFormat(const char *nam)
uploadfmt_t Surf_LightmapMode(model_t *model) uploadfmt_t Surf_LightmapMode(model_t *model)
{ {
uploadfmt_t fmt = Surf_NameToFormat(r_lightmap_format.string); uploadfmt_t fmt = Surf_NameToFormat(r_lightmap_format.string);
if (model && model->lightmaps.prebaked && model->lightmaps.fmt!=LM_RGB8)
fmt = PTI_INVALID; //don't let them force it away if we can't support it. this sucks.
if (!sh_config.texfmt[fmt]) if (!sh_config.texfmt[fmt])
{ {
qboolean hdr = (vid.flags&VID_SRGBAWARE), rgb = false; qboolean hdr = (vid.flags&VID_SRGBAWARE), rgb = false;
@ -3755,7 +3762,7 @@ void Surf_BuildModelLightmaps (model_t *m)
R_BumpLightstyles(m->lightmaps.maxstyle); //should only really happen with lazy loading R_BumpLightstyles(m->lightmaps.maxstyle); //should only really happen with lazy loading
if (m->submodelof && m->fromgame == fg_quake3) //FIXME: should be all bsp formats if (m->submodelof && m->lightmaps.prebaked) //FIXME: should be all bsp formats
{ {
if (m->submodelof->loadstate != MLS_LOADED) if (m->submodelof->loadstate != MLS_LOADED)
return; return;
@ -3763,7 +3770,7 @@ void Surf_BuildModelLightmaps (model_t *m)
} }
else else
{ {
if (!m->lightdata && m->lightmaps.count && m->fromgame == fg_quake3) if (!m->lightdata && m->lightmaps.count && m->lightmaps.prebaked)
{ {
char pattern[MAX_QPATH]; char pattern[MAX_QPATH];
COM_StripAllExtensions(m->name, pattern, sizeof(pattern)); COM_StripAllExtensions(m->name, pattern, sizeof(pattern));
@ -3787,7 +3794,7 @@ void Surf_BuildModelLightmaps (model_t *m)
} }
} }
if (m->fromgame == fg_quake3) if (m->lightmaps.prebaked)
{ {
int j; int j;
unsigned char *src, *stop; unsigned char *src, *stop;
@ -3817,24 +3824,38 @@ void Surf_BuildModelLightmaps (model_t *m)
if (!m->submodelof) if (!m->submodelof)
for (i = 0; i < m->lightmaps.count; i++) for (i = 0; i < m->lightmaps.count; i++)
{ {
if (lightmap[newfirst+i]->external) if (lightmap[newfirst+i]->external || !m->lightdata)
continue; continue;
if (lightmap[newfirst+i]->fmt == m->lightmaps.prebaked)
{
unsigned int bb,bw,bh,bd;
Image_BlockSizeForEncoding(m->lightmaps.prebaked, &bb,&bw,&bh,&bd);
dst = lightmap[newfirst+i]->lightmaps;
src = m->lightdata + i*m->lightmaps.width*m->lightmaps.height*bb;
stop = m->lightdata + (i+1)*m->lightmaps.width*m->lightmaps.height*bb;
if (stop-m->lightdata > m->lightdatasize)
stop = m->lightdata + m->lightdatasize;
memcpy(dst, src, stop-src);
}
//FIXME: replace with Image_ChangeFormat here. but the data may be partial for the last mip.
else switch(m->lightmaps.fmt)
{
case LM_RGB8:
dst = lightmap[newfirst+i]->lightmaps; dst = lightmap[newfirst+i]->lightmaps;
src = m->lightdata + i*m->lightmaps.width*m->lightmaps.height*3; src = m->lightdata + i*m->lightmaps.width*m->lightmaps.height*3;
stop = m->lightdata + (i+1)*m->lightmaps.width*m->lightmaps.height*3; stop = m->lightdata + (i+1)*m->lightmaps.width*m->lightmaps.height*3;
if (stop-m->lightdata > m->lightdatasize) if (stop-m->lightdata > m->lightdatasize)
stop = m->lightdata + m->lightdatasize; stop = m->lightdata + m->lightdatasize;
if (m->lightdata)
{
switch(lightmap[newfirst+i]->fmt) switch(lightmap[newfirst+i]->fmt)
{ {
default: default:
Sys_Error("Bad lightmap_fmt\n"); Sys_Error("Surf_BuildModelLightmaps: Bad format - %s\n", Image_FormatName(lightmap[newfirst+i]->fmt));
break; break;
case PTI_A2BGR10: case PTI_A2BGR10:
for (; src < stop; dst += 4, src += 3) for (; src < stop; dst += 4, src += 3)
*(unsigned int*)dst = (0x3<<30) | (src[2]<<22) | (src[1]<<12) | (src[0]<<2); *(unsigned int*)dst = (0x3u<<30) | (src[2]<<22) | (src[1]<<12) | (src[0]<<2);
break; break;
case PTI_E5BGR9: case PTI_E5BGR9:
for (; src < stop; dst += 4, src += 3) for (; src < stop; dst += 4, src += 3)
@ -3850,7 +3871,8 @@ void Surf_BuildModelLightmaps (model_t *m)
dst[3] = 255; dst[3] = 255;
} }
break; break;
/*case TF_RGBA32: case PTI_RGBA8:
case PTI_RGBX8:
for (; src < stop; dst += 4, src += 3) for (; src < stop; dst += 4, src += 3)
{ {
dst[0] = src[0]; dst[0] = src[0];
@ -3859,15 +3881,15 @@ void Surf_BuildModelLightmaps (model_t *m)
dst[3] = 255; dst[3] = 255;
} }
break; break;
case TF_BGR24: case PTI_BGR8:
for (; src < stop; dst += 3, src += 3) for (; src < stop; dst += 3, src += 3)
{ {
dst[0] = src[2]; dst[0] = src[2];
dst[1] = src[1]; dst[1] = src[1];
dst[2] = src[0]; dst[2] = src[0];
} }
break;*/ break;
case TF_RGB24: case PTI_RGB8:
for (; src < stop; dst += 3, src += 3) for (; src < stop; dst += 3, src += 3)
{ {
dst[0] = src[0]; dst[0] = src[0];
@ -3886,6 +3908,23 @@ void Surf_BuildModelLightmaps (model_t *m)
} }
break; break;
} }
break;
case LM_E5BGR9:
dst = lightmap[newfirst+i]->lightmaps;
src = m->lightdata + i*m->lightmaps.width*m->lightmaps.height*4;
stop = m->lightdata + (i+1)*m->lightmaps.width*m->lightmaps.height*4;
if (stop-m->lightdata > m->lightdatasize)
stop = m->lightdata + m->lightdatasize;
if (lightmap[newfirst+i]->fmt == PTI_E5BGR9)
memcpy(dst, src, stop-src);
else //this can happen on older gpus...
Con_Printf(CON_WARNING"Unsupported lightmap format. set ^[/r_lightmap_format e5bgr9^]\n");
break;
default:
Con_Printf(CON_WARNING"Unsupported input lightmap format\n");
break;
} }
} }
} }
@ -4010,7 +4049,7 @@ void Surf_NewMap (model_t *worldmodel)
//evil haxx //evil haxx
r_dynamic.ival = r_dynamic.value; r_dynamic.ival = r_dynamic.value;
if (r_dynamic.ival > 0 && (!cl.worldmodel || cl.worldmodel->fromgame == fg_quake3)) //quake3 has no lightmaps, disable r_dynamic if (r_dynamic.ival > 0 && (!cl.worldmodel || cl.worldmodel->lightmaps.prebaked)) //quake3 has no lightmaps, disable r_dynamic
r_dynamic.ival = 0; r_dynamic.ival = 0;
memset (&r_worldentity, 0, sizeof(r_worldentity)); memset (&r_worldentity, 0, sizeof(r_worldentity));

View file

@ -586,7 +586,7 @@ struct llightinfo_s;
void LightPlane (struct relight_ctx_s *ctx, struct llightinfo_s *threadctx, lightstyleindex_t surf_styles[MAXCPULIGHTMAPS], unsigned int *surf_expsamples, qbyte *surf_rgbsamples, qbyte *surf_deluxesamples, vec4_t surf_plane, vec4_t surf_texplanes[2], vec2_t exactmins, vec2_t exactmaxs, int texmins[2], int texsize[2], float lmscale); //special version that doesn't know what a face is or anything. void LightPlane (struct relight_ctx_s *ctx, struct llightinfo_s *threadctx, lightstyleindex_t surf_styles[MAXCPULIGHTMAPS], unsigned int *surf_expsamples, qbyte *surf_rgbsamples, qbyte *surf_deluxesamples, vec4_t surf_plane, vec4_t surf_texplanes[2], vec2_t exactmins, vec2_t exactmaxs, int texmins[2], int texsize[2], float lmscale); //special version that doesn't know what a face is or anything.
struct relight_ctx_s *LightStartup(struct relight_ctx_s *ctx, struct model_s *model, qboolean shadows, qboolean skiplit); struct relight_ctx_s *LightStartup(struct relight_ctx_s *ctx, struct model_s *model, qboolean shadows, qboolean skiplit);
void LightReloadEntities(struct relight_ctx_s *ctx, const char *entstring, qboolean ignorestyles); void LightReloadEntities(struct relight_ctx_s *ctx, const char *entstring, qboolean ignorestyles);
void LightShutdown(struct relight_ctx_s *ctx); void LightShutdown(struct relight_ctx_s *ctx, struct model_s *model);
extern const size_t lightthreadctxsize; extern const size_t lightthreadctxsize;
qboolean RelightSetup (struct model_s *model, size_t lightsamples, qboolean generatelit); qboolean RelightSetup (struct model_s *model, size_t lightsamples, qboolean generatelit);
@ -699,9 +699,7 @@ extern qboolean r_softwarebanding;
extern cvar_t r_lightprepass_cvar; extern cvar_t r_lightprepass_cvar;
extern int r_lightprepass; //0=off,1=16bit,2=32bit extern int r_lightprepass; //0=off,1=16bit,2=32bit
#ifdef R_XFLIP
extern cvar_t r_xflip; extern cvar_t r_xflip;
#endif
extern cvar_t gl_mindist, gl_maxdist; extern cvar_t gl_mindist, gl_maxdist;
extern cvar_t r_clear; extern cvar_t r_clear;

View file

@ -161,8 +161,9 @@ cvar_t r_fb_bmodels = CVARAFD("r_fb_bmodels", "1",
"gl_fb_bmodels", CVAR_SEMICHEAT|CVAR_RENDERERLATCH, "Enables loading lumas on the map, as well as any external bsp models."); "gl_fb_bmodels", CVAR_SEMICHEAT|CVAR_RENDERERLATCH, "Enables loading lumas on the map, as well as any external bsp models.");
cvar_t r_fb_models = CVARAFD ("r_fb_models", "1", cvar_t r_fb_models = CVARAFD ("r_fb_models", "1",
"gl_fb_models", CVAR_SEMICHEAT, "Enables the use of lumas on models. Note that if ruleset_allow_fbmodels is enabled, then all models are unconditionally fullbright in deathmatch, because cheaters would set up their models like that anyway, hurrah for beating them at their own game. QuakeWorld players suck."); "gl_fb_models", CVAR_SEMICHEAT, "Enables the use of lumas on models. Note that if ruleset_allow_fbmodels is enabled, then all models are unconditionally fullbright in deathmatch, because cheaters would set up their models like that anyway, hurrah for beating them at their own game. QuakeWorld players suck.");
cvar_t r_skin_overlays = CVARF ("r_skin_overlays", "1", cvar_t gl_overbright_models = CVARFD("gl_overbright_models", "0", CVAR_SEMICHEAT|CVAR_ARCHIVE, "Doubles the brightness of models, to match QuakeSpasm's misfeature of the same name.");
CVAR_SEMICHEAT|CVAR_RENDERERLATCH); //cvar_t r_skin_overlays = CVARF ("r_skin_overlays", "1",
// CVAR_SEMICHEAT|CVAR_RENDERERLATCH);
cvar_t r_globalskin_first = CVARFD ("r_globalskin_first", "100", CVAR_RENDERERLATCH, "Specifies the first .skin value that is a global skin. Entities within this range will use the shader/image called 'gfx/skinSKIN.lmp' instead of their regular skin. See also: r_globalskin_count."); cvar_t r_globalskin_first = CVARFD ("r_globalskin_first", "100", CVAR_RENDERERLATCH, "Specifies the first .skin value that is a global skin. Entities within this range will use the shader/image called 'gfx/skinSKIN.lmp' instead of their regular skin. See also: r_globalskin_count.");
cvar_t r_globalskin_count = CVARFD ("r_globalskin_count", "10", CVAR_RENDERERLATCH, "Specifies how many globalskins there are."); cvar_t r_globalskin_count = CVARFD ("r_globalskin_count", "10", CVAR_RENDERERLATCH, "Specifies how many globalskins there are.");
cvar_t r_coronas = CVARFD ("r_coronas", "0", CVAR_ARCHIVE, "Draw coronas on realtime lights. Overrides glquake-esque flashblends."); cvar_t r_coronas = CVARFD ("r_coronas", "0", CVAR_ARCHIVE, "Draw coronas on realtime lights. Overrides glquake-esque flashblends.");
@ -323,6 +324,8 @@ cvar_t r_stereo_separation = CVARD("r_stereo_separation", "4", "How far apar
cvar_t r_stereo_convergence = CVARD("r_stereo_convergence", "0", "Nudges the angle of each eye inwards when using stereoscopic rendering."); cvar_t r_stereo_convergence = CVARD("r_stereo_convergence", "0", "Nudges the angle of each eye inwards when using stereoscopic rendering.");
cvar_t r_stereo_method = CVARFD("r_stereo_method", "0", CVAR_ARCHIVE, "Value 0 = Off.\nValue 1 = Attempt hardware acceleration. Requires vid_restart.\nValue 2 = red/cyan.\nValue 3 = red/blue.\nValue 4=red/green.\nValue 5=eye strain."); cvar_t r_stereo_method = CVARFD("r_stereo_method", "0", CVAR_ARCHIVE, "Value 0 = Off.\nValue 1 = Attempt hardware acceleration. Requires vid_restart.\nValue 2 = red/cyan.\nValue 3 = red/blue.\nValue 4=red/green.\nValue 5=eye strain.");
cvar_t r_xflip = CVAR("leftisright", "0");
extern cvar_t r_dodgytgafiles; extern cvar_t r_dodgytgafiles;
extern cvar_t r_dodgypcxfiles; extern cvar_t r_dodgypcxfiles;
extern cvar_t r_keepimages; extern cvar_t r_keepimages;
@ -581,10 +584,6 @@ void GLRenderer_Init(void)
Cvar_Register (&gl_smoothcrosshair, GRAPHICALNICETIES); Cvar_Register (&gl_smoothcrosshair, GRAPHICALNICETIES);
#ifdef R_XFLIP
Cvar_Register (&r_xflip, GLRENDEREROPTIONS);
#endif
// Cvar_Register (&gl_lightmapmode, GLRENDEREROPTIONS); // Cvar_Register (&gl_lightmapmode, GLRENDEREROPTIONS);
Cvar_Register (&gl_picmip, GLRENDEREROPTIONS); Cvar_Register (&gl_picmip, GLRENDEREROPTIONS);
@ -943,6 +942,7 @@ void Renderer_Init(void)
Cvar_Register (&scr_allowsnap, SCREENOPTIONS); Cvar_Register (&scr_allowsnap, SCREENOPTIONS);
Cvar_Register (&scr_consize, SCREENOPTIONS); Cvar_Register (&scr_consize, SCREENOPTIONS);
Cvar_Register (&scr_centersbar, SCREENOPTIONS); Cvar_Register (&scr_centersbar, SCREENOPTIONS);
Cvar_Register (&r_xflip, GLRENDEREROPTIONS);
Cvar_Register(&r_bloodstains, GRAPHICALNICETIES); Cvar_Register(&r_bloodstains, GRAPHICALNICETIES);
@ -1002,8 +1002,9 @@ void Renderer_Init(void)
Cvar_Register (&r_fb_bmodels, GRAPHICALNICETIES); Cvar_Register (&r_fb_bmodels, GRAPHICALNICETIES);
Cvar_Register (&r_fb_models, GRAPHICALNICETIES); Cvar_Register (&r_fb_models, GRAPHICALNICETIES);
Cvar_Register (&gl_overbright_models, GRAPHICALNICETIES);
// Cvar_Register (&r_fullbrights, GRAPHICALNICETIES); //dpcompat: 1 if r_fb_bmodels&&r_fb_models // Cvar_Register (&r_fullbrights, GRAPHICALNICETIES); //dpcompat: 1 if r_fb_bmodels&&r_fb_models
Cvar_Register (&r_skin_overlays, GRAPHICALNICETIES); // Cvar_Register (&r_skin_overlays, GRAPHICALNICETIES);
Cvar_Register (&r_globalskin_first, GRAPHICALNICETIES); Cvar_Register (&r_globalskin_first, GRAPHICALNICETIES);
Cvar_Register (&r_globalskin_count, GRAPHICALNICETIES); Cvar_Register (&r_globalskin_count, GRAPHICALNICETIES);
Cvar_Register (&r_shadows, GRAPHICALNICETIES); Cvar_Register (&r_shadows, GRAPHICALNICETIES);
@ -1824,7 +1825,7 @@ TRACE(("dbg: R_ApplyRenderer: starting on client state\n"));
TRACE(("dbg: R_ApplyRenderer: reloading ALL models\n")); TRACE(("dbg: R_ApplyRenderer: reloading ALL models\n"));
for (i=1 ; i<MAX_PRECACHE_MODELS ; i++) for (i=1 ; i<MAX_PRECACHE_MODELS ; i++)
{ {
if (!cl.model_name[i][0]) if (!cl.model_name[i])
break; break;
TRACE(("dbg: R_ApplyRenderer: reloading model %s\n", cl.model_name[i])); TRACE(("dbg: R_ApplyRenderer: reloading model %s\n", cl.model_name[i]));
@ -1846,7 +1847,7 @@ TRACE(("dbg: R_ApplyRenderer: reloading ALL models\n"));
#ifdef HAVE_LEGACY #ifdef HAVE_LEGACY
for (i=0; i < MAX_VWEP_MODELS; i++) for (i=0; i < MAX_VWEP_MODELS; i++)
{ {
if (*cl.model_name_vwep[i]) if (cl.model_name_vwep[i])
cl.model_precache_vwep[i] = Mod_ForName (cl.model_name_vwep[i], MLV_SILENT); cl.model_precache_vwep[i] = Mod_ForName (cl.model_name_vwep[i], MLV_SILENT);
else else
cl.model_precache_vwep[i] = NULL; cl.model_precache_vwep[i] = NULL;
@ -2201,7 +2202,8 @@ void R_RestartRenderer (rendererstate_t *newr)
rendererstate_t oldr; rendererstate_t oldr;
if (r_blockvidrestart) if (r_blockvidrestart)
{ {
Con_TPrintf("Ignoring vid_restart from config\n"); if (r_blockvidrestart != 2)
Con_TPrintf("Unable to restart renderer at this time\n");
return; return;
} }
@ -2324,6 +2326,13 @@ void R_RestartRenderer_f (void)
double time; double time;
rendererstate_t newr; rendererstate_t newr;
if (r_blockvidrestart)
{
if (r_blockvidrestart!=2)
Con_TPrintf("Ignoring vid_restart from config\n");
return;
}
Cvar_ApplyLatches(CVAR_VIDEOLATCH|CVAR_RENDERERLATCH, false); Cvar_ApplyLatches(CVAR_VIDEOLATCH|CVAR_RENDERERLATCH, false);
if (!R_BuildRenderstate(&newr, vid_renderer.string)) if (!R_BuildRenderstate(&newr, vid_renderer.string))
{ {
@ -2558,72 +2567,6 @@ mspriteframe_t *R_GetSpriteFrame (entity_t *currententity)
return pspriteframe; return pspriteframe;
} }
/*
void MYgluPerspective(double fovx, double fovy, double zNear, double zFar)
{
Matrix4_Projection_Far(r_refdef.m_projection, fovx, fovy, zNear, zFar);
}
void GL_InfinatePerspective(double fovx, double fovy,
double zNear)
{
// nudge infinity in just slightly for lsb slop
float nudge = 1;// - 1.0 / (1<<23);
double xmin, xmax, ymin, ymax;
ymax = zNear * tan( fovy * M_PI / 360.0 );
ymin = -ymax;
xmax = zNear * tan( fovx * M_PI / 360.0 );
xmin = -xmax;
r_projection_matrix[0] = (2*zNear) / (xmax - xmin);
r_projection_matrix[4] = 0;
r_projection_matrix[8] = (xmax + xmin) / (xmax - xmin);
r_projection_matrix[12] = 0;
r_projection_matrix[1] = 0;
r_projection_matrix[5] = (2*zNear) / (ymax - ymin);
r_projection_matrix[9] = (ymax + ymin) / (ymax - ymin);
r_projection_matrix[13] = 0;
r_projection_matrix[2] = 0;
r_projection_matrix[6] = 0;
r_projection_matrix[10] = -1 * nudge;
r_projection_matrix[14] = -2*zNear * nudge;
r_projection_matrix[3] = 0;
r_projection_matrix[7] = 0;
r_projection_matrix[11] = -1;
r_projection_matrix[15] = 0;
}
void GL_ParallelPerspective(double xmin, double xmax, double ymax, double ymin,
double znear, double zfar)
{
r_projection_matrix[0] = 2/(xmax-xmin);
r_projection_matrix[4] = 0;
r_projection_matrix[8] = 0;
r_projection_matrix[12] = (xmax+xmin)/(xmax-xmin);
r_projection_matrix[1] = 0;
r_projection_matrix[5] = 2/(ymax-ymin);
r_projection_matrix[9] = 0;
r_projection_matrix[13] = (ymax+ymin)/(ymax-ymin);
r_projection_matrix[2] = 0;
r_projection_matrix[6] = 0;
r_projection_matrix[10] = -2/(zfar-znear);
r_projection_matrix[14] = (zfar+znear)/(zfar-znear);
r_projection_matrix[3] = 0;
r_projection_matrix[7] = 0;
r_projection_matrix[11] = 0;
r_projection_matrix[15] = 1;
}
*/
/* /*
=============== ===============

View file

@ -2401,7 +2401,7 @@ void Sbar_DrawScoreboard (playerview_t *pv)
#endif #endif
isdead = false; isdead = false;
if (pv->spectator && (cls.demoplayback == DPB_MVD || cls.demoplayback == DPB_EZTV)) if (pv->spectator && cls.demoplayback == DPB_MVD)
{ {
int t = pv->cam_spec_track; int t = pv->cam_spec_track;
if (t >= 0 && CAM_ISLOCKED(pv) && cl.players[t].statsf[STAT_HEALTH] <= 0) if (t >= 0 && CAM_ISLOCKED(pv) && cl.players[t].statsf[STAT_HEALTH] <= 0)
@ -3544,14 +3544,14 @@ ping time frags name
sprintf(num, S_COLOR_WHITE"%4i", p); \ sprintf(num, S_COLOR_WHITE"%4i", p); \
else \ else \
sprintf(num, S_COLOR_GREEN"%4i", p); \ sprintf(num, S_COLOR_GREEN"%4i", p); \
Draw_FunStringWidth(x, y, num, 4*8, false, false); \ Draw_FunStringWidth(x, y, num, 4*8+4, false, highlight); \
},NOFILL) },NOFILL)
#define COLUMN_PL COLUMN(pl, 2*8, \ #define COLUMN_PL COLUMN(pl, 2*8, \
{ \ { \
int p = s->pl; \ int p = s->pl; \
sprintf(num, "%2i", p); \ sprintf(num, "%2i", p); \
Draw_FunStringWidth(x, y, num, 2*8, false, false); \ Draw_FunStringWidth(x, y, num, 2*8+4, false, highlight); \
},NOFILL) },NOFILL)
#define COLUMN_TIME COLUMN(time, 4*8, \ #define COLUMN_TIME COLUMN(time, 4*8, \
{ \ { \
@ -3563,14 +3563,14 @@ ping time frags name
minutes = (int)total/60; \ minutes = (int)total/60; \
sprintf (num, "%4i", minutes); \ sprintf (num, "%4i", minutes); \
} \ } \
Draw_FunStringWidth(x, y, num, 4*8, false, false); \ Draw_FunStringWidth(x, y, num, 4*8+4, false, highlight); \
},NOFILL) },NOFILL)
#define COLUMN_FRAGS COLUMN(frags, 5*8, \ #define COLUMN_FRAGS COLUMN(frags, 5*8, \
{ \ { \
int cx; int cy; \ int cx; int cy; \
if (s->spectator && s->spectator != 2) \ if (s->spectator && s->spectator != 2) \
{ \ { \
Draw_FunStringWidth(x, y, "spectator", 5*8, false, false); \ Draw_FunStringWidth(x, y, "spectator", 5*8+4, false, false); \
} \ } \
else \ else \
{ \ { \
@ -3607,7 +3607,7 @@ ping time frags name
{ \ { \
if (!s->spectator) \ if (!s->spectator) \
{ \ { \
Draw_FunStringWidth(x, y, s->team, 4*8, false, false); \ Draw_FunStringWidth(x, y, s->team, 4*8+4, false, highlight); \
} \ } \
},NOFILL) },NOFILL)
#define COLUMN_STAT(title, width, code, fill) COLUMN(title, width, { \ #define COLUMN_STAT(title, width, code, fill) COLUMN(title, width, { \
@ -3616,13 +3616,13 @@ ping time frags name
code \ code \
} \ } \
}, fill) }, fill)
#define COLUMN_RULESET COLUMN(ruleset, 8*8, {Draw_FunStringWidth(x, y, s->ruleset, 8*8, false, false);},NOFILL) #define COLUMN_RULESET COLUMN(ruleset, 8*8, {Draw_FunStringWidth(x, y, s->ruleset, 8*8+4, false, false);},NOFILL)
#define COLUMN_NAME COLUMN(name, namesize, {Draw_FunStringWidth(x, y, s->name, namesize, false, false);},NOFILL) #define COLUMN_NAME COLUMN(name, namesize, {Draw_FunStringWidth(x, y, s->name, namesize, false, highlight);},NOFILL)
#define COLUMN_KILLS COLUMN_STAT(kils, 4*8, {Draw_FunStringWidth(x, y, va("%4i", Stats_GetKills(k)), 4*8, false, false);},NOFILL) #define COLUMN_KILLS COLUMN_STAT(kils, 4*8, {Draw_FunStringWidth(x, y, va("%4i", Stats_GetKills(k)), 4*8+4, false, false);},NOFILL)
#define COLUMN_TKILLS COLUMN_STAT(tkil, 4*8, {Draw_FunStringWidth(x, y, va("%4i", Stats_GetTKills(k)), 4*8, false, false);},NOFILL) #define COLUMN_TKILLS COLUMN_STAT(tkil, 4*8, {Draw_FunStringWidth(x, y, va("%4i", Stats_GetTKills(k)), 4*8+4, false, false);},NOFILL)
#define COLUMN_DEATHS COLUMN_STAT(dths, 4*8, {Draw_FunStringWidth(x, y, va("%4i", Stats_GetDeaths(k)), 4*8, false, false);},NOFILL) #define COLUMN_DEATHS COLUMN_STAT(dths, 4*8, {Draw_FunStringWidth(x, y, va("%4i", Stats_GetDeaths(k)), 4*8+4, false, false);},NOFILL)
#define COLUMN_TOUCHES COLUMN_STAT(tchs, 4*8, {Draw_FunStringWidth(x, y, va("%4i", Stats_GetTouches(k)), 4*8, false, false);},NOFILL) #define COLUMN_TOUCHES COLUMN_STAT(tchs, 4*8, {Draw_FunStringWidth(x, y, va("%4i", Stats_GetTouches(k)), 4*8+4, false, false);},NOFILL)
#define COLUMN_CAPS COLUMN_STAT(caps, 4*8, {Draw_FunStringWidth(x, y, va("%4i", Stats_GetCaptures(k)), 4*8, false, false);},NOFILL) #define COLUMN_CAPS COLUMN_STAT(caps, 4*8, {Draw_FunStringWidth(x, y, va("%4i", Stats_GetCaptures(k)), 4*8+4, false, false);},NOFILL)
#define COLUMN_AFK COLUMN(afk, 0, {int cs = atoi(InfoBuf_ValueForKey(&s->userinfo, "chat")); if (cs)Draw_FunStringWidth(x+4, y, (cs&2)?"afk":"msg", 4*8, false, false);},NOFILL) #define COLUMN_AFK COLUMN(afk, 0, {int cs = atoi(InfoBuf_ValueForKey(&s->userinfo, "chat")); if (cs)Draw_FunStringWidth(x+4, y, (cs&2)?"afk":"msg", 4*8, false, false);},NOFILL)
@ -3658,12 +3658,13 @@ void Sbar_DeathmatchOverlay (playerview_t *pv, int start)
int pages; int pages;
int linesperpage, firstline, lastline; int linesperpage, firstline, lastline;
int highlight;
if (!pv) if (!pv)
return; return;
// request new ping times every two second // request new ping times every two second
if (realtime - cl.last_ping_request > 2 && cls.demoplayback != DPB_EZTV) if (realtime - cl.last_ping_request > 2 && !cls.demoplayback)
{ {
if (cls.protocol == CP_QUAKEWORLD) if (cls.protocol == CP_QUAKEWORLD)
{ {
@ -3944,6 +3945,18 @@ if (showcolumns & (1<<COLUMN##title)) \
isme = (pv->cam_state == CAM_FREECAM && k == pv->playernum) || isme = (pv->cam_state == CAM_FREECAM && k == pv->playernum) ||
(pv->cam_state != CAM_FREECAM && k == pv->cam_spec_track); (pv->cam_state != CAM_FREECAM && k == pv->cam_spec_track);
if ((key_dest_absolutemouse & key_dest_mask & ~kdm_game) &&
!Key_Dest_Has(~kdm_game) &&
mousecursor_x >= startx && mousecursor_x < startx+rank_width &&
mousecursor_y >= y && mousecursor_y < y+skip)
{
highlight = 2;
cl.mouseplayerview = pv;
cl.mousenewtrackplayer = k;
}
else
highlight = 0;
x = startx; x = startx;
#define COLUMN(title, width, code, fills) \ #define COLUMN(title, width, code, fills) \
if (showcolumns & (1<<COLUMN##title)) \ if (showcolumns & (1<<COLUMN##title)) \
@ -4018,6 +4031,9 @@ static void Sbar_MiniDeathmatchOverlay (playerview_t *pv)
top = Sbar_TopColour(s); top = Sbar_TopColour(s);
bottom = Sbar_BottomColour(s); bottom = Sbar_BottomColour(s);
if (S_Voip_Speaking(k))
Sbar_FillPCDark (x, py, ((cl.teamplay && !consistentteams)?40:0)+48+MAX_DISPLAYEDNAME*8, 8, 0x00ff00, scr_scoreboard_backgroundalpha.value*scr_scoreboard_fillalpha.value);
Sbar_FillPC ( x, py+1, 40, 3, top); Sbar_FillPC ( x, py+1, 40, 3, top);
Sbar_FillPC ( x, py+4, 40, 4, bottom); Sbar_FillPC ( x, py+4, 40, 4, bottom);
py += 8; py += 8;

View file

@ -488,17 +488,17 @@ void Skin_NextDownload (void)
CL_CheckOrEnqueDownloadFile(va("players/%s/tris.md2", skinname), NULL, 0); CL_CheckOrEnqueDownloadFile(va("players/%s/tris.md2", skinname), NULL, 0);
for (j = 1; j < MAX_PRECACHE_MODELS; j++) for (j = 1; j < MAX_PRECACHE_MODELS; j++)
{ {
if (!cl.model_name[j])
break;
if (cl.model_name[j][0] == '#') if (cl.model_name[j][0] == '#')
CL_CheckOrEnqueDownloadFile(va("players/%s/%s", skinname, cl.model_name[j]+1), NULL, 0); CL_CheckOrEnqueDownloadFile(va("players/%s/%s", skinname, cl.model_name[j]+1), NULL, 0);
if (!*cl.model_name[j])
break;
} }
for (j = 1; j < MAX_PRECACHE_SOUNDS; j++) for (j = 1; j < MAX_PRECACHE_SOUNDS; j++)
{ {
if (!cl.sound_name[j])
break;
if (cl.sound_name[j][0] == '*') if (cl.sound_name[j][0] == '*')
CL_CheckOrEnqueDownloadFile(va("players/%s/%s", skinname, cl.sound_name[j]+1), NULL, 0); CL_CheckOrEnqueDownloadFile(va("players/%s/%s", skinname, cl.sound_name[j]+1), NULL, 0);
if (!*cl.sound_name[j])
break;
} }
*slash = '/'; *slash = '/';
CL_CheckOrEnqueDownloadFile(va("players/%s.pcx", skinname), NULL, 0); CL_CheckOrEnqueDownloadFile(va("players/%s.pcx", skinname), NULL, 0);

View file

@ -53,6 +53,9 @@ We also have no doppler with WebAudio.
#ifdef OPENAL_STATIC #ifdef OPENAL_STATIC
#include <AL/al.h> //output #include <AL/al.h> //output
#include <AL/alc.h> //context+input #include <AL/alc.h> //context+input
#ifdef USEEFX
#include <AL/efx.h>
#endif
#ifndef AL_API #ifndef AL_API
#define AL_API #define AL_API
@ -103,6 +106,13 @@ We also have no doppler with WebAudio.
#define palGetProcAddress alGetProcAddress #define palGetProcAddress alGetProcAddress
//voip stuff
#define palcCaptureOpenDevice alcCaptureOpenDevice
#define palcCaptureCloseDevice alcCaptureCloseDevice
#define palcCaptureStart alcCaptureStart
#define palcCaptureStop alcCaptureStop
#define palcCaptureSamples alcCaptureSamples
#ifdef FTE_TARGET_WEB //emscripten sucks. #ifdef FTE_TARGET_WEB //emscripten sucks.
AL_API void (AL_APIENTRY alSpeedOfSound)( ALfloat value ) {} AL_API void (AL_APIENTRY alSpeedOfSound)( ALfloat value ) {}
#endif #endif
@ -115,6 +125,8 @@ AL_API void (AL_APIENTRY alSpeedOfSound)( ALfloat value ) {}
#endif #endif
#define AL_API #define AL_API
#undef AL_ALEXT_PROTOTYPES
typedef int ALint; typedef int ALint;
typedef unsigned int ALuint; typedef unsigned int ALuint;
@ -131,6 +143,7 @@ static qboolean openallib_tried;
static AL_API ALenum (AL_APIENTRY *palGetError)( void ); static AL_API ALenum (AL_APIENTRY *palGetError)( void );
static AL_API void (AL_APIENTRY *palSourcef)( ALuint sid, ALenum param, ALfloat value ); static AL_API void (AL_APIENTRY *palSourcef)( ALuint sid, ALenum param, ALfloat value );
static AL_API void (AL_APIENTRY *palSourcei)( ALuint sid, ALenum param, ALint value ); static AL_API void (AL_APIENTRY *palSourcei)( ALuint sid, ALenum param, ALint value );
static AL_API void (AL_APIENTRY *palSource3i)(ALuint source, ALenum param, ALint value1, ALint value2, ALint value3);
static AL_API void (AL_APIENTRY *palSourcePlayv)( ALsizei ns, const ALuint *sids ); static AL_API void (AL_APIENTRY *palSourcePlayv)( ALsizei ns, const ALuint *sids );
static AL_API void (AL_APIENTRY *palSourceStopv)( ALsizei ns, const ALuint *sids ); static AL_API void (AL_APIENTRY *palSourceStopv)( ALsizei ns, const ALuint *sids );
@ -251,19 +264,17 @@ static ALC_API void* (ALC_APIENTRY *palcGetProcAddress)(ALCdevice *dev
#if defined(VOICECHAT) #if defined(VOICECHAT)
//capture-specific stuff //capture-specific stuff
static ALC_API void (ALC_APIENTRY *palcGetIntegerv)( ALCdevice *device, ALCenum param, ALCsizei size, ALCint *data ); static void (ALC_APIENTRY *palcGetIntegerv)( ALCdevice *device, ALCenum param, ALCsizei size, ALCint *data );
static ALC_API ALCdevice * (ALC_APIENTRY *palcCaptureOpenDevice)( const ALCchar *devicename, ALCuint frequency, ALCenum format, ALCsizei buffersize ); static ALCdevice * (ALC_APIENTRY *palcCaptureOpenDevice)( const ALCchar *devicename, ALCuint frequency, ALCenum format, ALCsizei buffersize );
static ALC_API ALCboolean (ALC_APIENTRY *palcCaptureCloseDevice)( ALCdevice *device ); static ALCboolean (ALC_APIENTRY *palcCaptureCloseDevice)( ALCdevice *device );
static ALC_API void (ALC_APIENTRY *palcCaptureStart)( ALCdevice *device ); static void (ALC_APIENTRY *palcCaptureStart)( ALCdevice *device );
static ALC_API void (ALC_APIENTRY *palcCaptureStop)( ALCdevice *device ); static void (ALC_APIENTRY *palcCaptureStop)( ALCdevice *device );
static ALC_API void (ALC_APIENTRY *palcCaptureSamples)( ALCdevice *device, ALCvoid *buffer, ALCsizei samples ); static void (ALC_APIENTRY *palcCaptureSamples)( ALCdevice *device, ALCvoid *buffer, ALCsizei samples );
#define ALC_CAPTURE_DEVICE_SPECIFIER 0x310 #define ALC_CAPTURE_DEVICE_SPECIFIER 0x310
#define ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER 0x311 #define ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER 0x311
#define ALC_CAPTURE_SAMPLES 0x312 #define ALC_CAPTURE_SAMPLES 0x312
#endif #endif
#endif
//efx //efx
#ifdef USEEFX #ifdef USEEFX
@ -312,18 +323,32 @@ static ALC_API void (ALC_APIENTRY *palcCaptureSamples)( ALCdevice *dev
#define AL_EAXREVERB_LFREFERENCE 0x0015 #define AL_EAXREVERB_LFREFERENCE 0x0015
#define AL_EAXREVERB_ROOM_ROLLOFF_FACTOR 0x0016 #define AL_EAXREVERB_ROOM_ROLLOFF_FACTOR 0x0016
#define AL_EAXREVERB_DECAY_HFLIMIT 0x0017 #define AL_EAXREVERB_DECAY_HFLIMIT 0x0017
static AL_API void (AL_APIENTRY *palSource3i)(ALuint source, ALenum param, ALint value1, ALint value2, ALint value3); #endif
#endif
static AL_API void (AL_APIENTRY *palAuxiliaryEffectSloti)(ALuint effectslot, ALenum param, ALint iValue); #ifdef USEEFX
static AL_API ALvoid (AL_APIENTRY *palGenAuxiliaryEffectSlots)(ALsizei n, ALuint *effectslots); #if defined(AL_ALEXT_PROTOTYPES) && defined(OPENAL_STATIC)
static AL_API ALvoid (AL_APIENTRY *palDeleteAuxiliaryEffectSlots)(ALsizei n, const ALuint *effectslots); #define palAuxiliaryEffectSloti alAuxiliaryEffectSloti
static AL_API ALvoid (AL_APIENTRY *palDeleteEffects)(ALsizei n, const ALuint *effects); #define palGenAuxiliaryEffectSlots alGenAuxiliaryEffectSlots
#define palDeleteAuxiliaryEffectSlots alDeleteAuxiliaryEffectSlots
#define palDeleteEffects alDeleteEffects
#define palGenEffects alGenEffects
#define palEffecti alEffecti
// #define palEffectiv alEffectiv
#define palEffectf alEffectf
#define palEffectfv alEffectfv
#else
static void (AL_APIENTRY *palAuxiliaryEffectSloti)(ALuint effectslot, ALenum param, ALint iValue);
static ALvoid (AL_APIENTRY *palGenAuxiliaryEffectSlots)(ALsizei n, ALuint *effectslots);
static ALvoid (AL_APIENTRY *palDeleteAuxiliaryEffectSlots)(ALsizei n, const ALuint *effectslots);
static ALvoid (AL_APIENTRY *palDeleteEffects)(ALsizei n, const ALuint *effects);
static AL_API ALvoid (AL_APIENTRY *palGenEffects)(ALsizei n, ALuint *effects); static ALvoid (AL_APIENTRY *palGenEffects)(ALsizei n, ALuint *effects);
static AL_API ALvoid (AL_APIENTRY *palEffecti)(ALuint effect, ALenum param, ALint iValue); static ALvoid (AL_APIENTRY *palEffecti)(ALuint effect, ALenum param, ALint iValue);
static AL_API ALvoid (AL_APIENTRY *palEffectiv)(ALuint effect, ALenum param, const ALint *piValues); // static ALvoid (AL_APIENTRY *palEffectiv)(ALuint effect, ALenum param, const ALint *piValues);
static AL_API ALvoid (AL_APIENTRY *palEffectf)(ALuint effect, ALenum param, ALfloat flValue); static ALvoid (AL_APIENTRY *palEffectf)(ALuint effect, ALenum param, ALfloat flValue);
static AL_API ALvoid (AL_APIENTRY *palEffectfv)(ALuint effect, ALenum param, const ALfloat *pflValues); static ALvoid (AL_APIENTRY *palEffectfv)(ALuint effect, ALenum param, const ALfloat *pflValues);
#endif
#endif #endif
//AL_EXT_float32 //AL_EXT_float32
@ -1084,13 +1109,10 @@ static void OpenAL_ChannelUpdate(soundcardinfo_t *sc, channel_t *chan, chanupdat
palSourcef(src, AL_PITCH, pitch); palSourcef(src, AL_PITCH, pitch);
#ifdef USEEFX #ifdef USEEFX
if (palSource3i)
{
if (chan->flags & CF_NOREVERB) //don't do the underwater thing on static sounds. it sounds like arse with all those sources. if (chan->flags & CF_NOREVERB) //don't do the underwater thing on static sounds. it sounds like arse with all those sources.
palSource3i(src, AL_AUXILIARY_SEND_FILTER, 0, 0, AL_FILTER_NULL); palSource3i(src, AL_AUXILIARY_SEND_FILTER, 0, 0, AL_FILTER_NULL);
else else
palSource3i(src, AL_AUXILIARY_SEND_FILTER, oali->effectslot, 0, AL_FILTER_NULL); palSource3i(src, AL_AUXILIARY_SEND_FILTER, oali->effectslot, 0, AL_FILTER_NULL);
}
#endif #endif
palSourcei(src, AL_LOOPING, (!stream && ((chan->flags & CF_FORCELOOP)||(sfx->loopstart>=0&&!stream)))?AL_TRUE:AL_FALSE); palSourcei(src, AL_LOOPING, (!stream && ((chan->flags & CF_FORCELOOP)||(sfx->loopstart>=0&&!stream)))?AL_TRUE:AL_FALSE);
@ -1205,6 +1227,7 @@ static qboolean OpenAL_InitLibrary(void)
{(void*)&palGetError, "alGetError"}, {(void*)&palGetError, "alGetError"},
{(void*)&palSourcef, "alSourcef"}, {(void*)&palSourcef, "alSourcef"},
{(void*)&palSourcei, "alSourcei"}, {(void*)&palSourcei, "alSourcei"},
{(void*)&palSource3i, "alSource3i"},
{(void*)&palSourcePlayv, "alSourcePlayv"}, {(void*)&palSourcePlayv, "alSourcePlayv"},
{(void*)&palSourceStopv, "alSourceStopv"}, {(void*)&palSourceStopv, "alSourceStopv"},
{(void*)&palSourcePlay, "alSourcePlay"}, {(void*)&palSourcePlay, "alSourcePlay"},
@ -1238,6 +1261,7 @@ static qboolean OpenAL_InitLibrary(void)
{(void*)&palcMakeContextCurrent, "alcMakeContextCurrent"}, {(void*)&palcMakeContextCurrent, "alcMakeContextCurrent"},
{(void*)&palcProcessContext, "alcProcessContext"}, {(void*)&palcProcessContext, "alcProcessContext"},
{(void*)&palcGetString, "alcGetString"}, {(void*)&palcGetString, "alcGetString"},
{(void*)&palcGetIntegerv, "alcGetIntegerv"},
{(void*)&palcIsExtensionPresent, "alcIsExtensionPresent"}, {(void*)&palcIsExtensionPresent, "alcIsExtensionPresent"},
{(void*)&palcGetProcAddress, "alcGetProcAddress"}, {(void*)&palcGetProcAddress, "alcGetProcAddress"},
{NULL} {NULL}
@ -1854,16 +1878,17 @@ static qboolean QDECL OpenAL_InitCard2(soundcardinfo_t *sc, const char *devname,
#ifdef USEEFX #ifdef USEEFX
PrintALError("preeffects"); PrintALError("preeffects");
palSource3i = palGetProcAddress("alSource3i"); #ifndef AL_ALEXT_PROTOTYPES
palAuxiliaryEffectSloti = palGetProcAddress("alAuxiliaryEffectSloti"); palAuxiliaryEffectSloti = palGetProcAddress("alAuxiliaryEffectSloti");
palGenAuxiliaryEffectSlots = palGetProcAddress("alGenAuxiliaryEffectSlots"); palGenAuxiliaryEffectSlots = palGetProcAddress("alGenAuxiliaryEffectSlots");
palDeleteAuxiliaryEffectSlots = palGetProcAddress("alDeleteAuxiliaryEffectSlots"); palDeleteAuxiliaryEffectSlots = palGetProcAddress("alDeleteAuxiliaryEffectSlots");
palDeleteEffects = palGetProcAddress("alDeleteEffects"); palDeleteEffects = palGetProcAddress("alDeleteEffects");
palGenEffects = palGetProcAddress("alGenEffects"); palGenEffects = palGetProcAddress("alGenEffects");
palEffecti = palGetProcAddress("alEffecti"); palEffecti = palGetProcAddress("alEffecti");
palEffectiv = palGetProcAddress("alEffectiv"); // palEffectiv = palGetProcAddress("alEffectiv");
palEffectf = palGetProcAddress("alEffectf"); palEffectf = palGetProcAddress("alEffectf");
palEffectfv = palGetProcAddress("alEffectfv"); palEffectfv = palGetProcAddress("alEffectfv");
#endif
if (palGenAuxiliaryEffectSlots && s_al_use_reverb.ival) if (palGenAuxiliaryEffectSlots && s_al_use_reverb.ival)
palGenAuxiliaryEffectSlots(1, &oali->effectslot); palGenAuxiliaryEffectSlots(1, &oali->effectslot);
@ -1915,10 +1940,11 @@ static qboolean OpenAL_InitCapture(void)
//if (!palcIsExtensionPresent(NULL, "ALC_EXT_capture")) //if (!palcIsExtensionPresent(NULL, "ALC_EXT_capture"))
// return false; // return false;
#ifdef OPENAL_STATIC
return true;
#else
if(!palcCaptureOpenDevice) if(!palcCaptureOpenDevice)
{ {
palcGetIntegerv = Sys_GetAddressForName(openallib, "alcGetIntegerv");
palcCaptureOpenDevice = Sys_GetAddressForName(openallib, "alcCaptureOpenDevice"); palcCaptureOpenDevice = Sys_GetAddressForName(openallib, "alcCaptureOpenDevice");
palcCaptureStart = Sys_GetAddressForName(openallib, "alcCaptureStart"); palcCaptureStart = Sys_GetAddressForName(openallib, "alcCaptureStart");
palcCaptureSamples = Sys_GetAddressForName(openallib, "alcCaptureSamples"); palcCaptureSamples = Sys_GetAddressForName(openallib, "alcCaptureSamples");
@ -1927,6 +1953,7 @@ static qboolean OpenAL_InitCapture(void)
} }
return palcGetIntegerv&&palcCaptureOpenDevice&&palcCaptureStart&&palcCaptureSamples&&palcCaptureStop&&palcCaptureCloseDevice; return palcGetIntegerv&&palcCaptureOpenDevice&&palcCaptureStart&&palcCaptureSamples&&palcCaptureStop&&palcCaptureCloseDevice;
#endif
} }
static qboolean QDECL OPENAL_Capture_Enumerate (void (QDECL *callback) (const char *drivername, const char *devicecode, const char *readablename)) static qboolean QDECL OPENAL_Capture_Enumerate (void (QDECL *callback) (const char *drivername, const char *devicecode, const char *readablename))
{ {
@ -1955,8 +1982,13 @@ static void *QDECL OPENAL_Capture_Init (int samplerate, const char *device)
if (!device || !*device) if (!device || !*device)
{ {
#if defined(FTE_TARGET_WEB) && (__EMSCRIPTEN_major__>2 || (__EMSCRIPTEN_major__==2&&__EMSCRIPTEN_tiny__>=14))
//emscripten, and recent enough to actually work. don't check s_al_disable here as we don't have dsound/alsa fallbacks and we do want to actually use it.
//older versions of emscripten are too buggy to use.
#else
if (s_al_disable.ival) if (s_al_disable.ival)
return NULL; //no default device return NULL; //no default device
#endif
device = palcGetString(NULL, ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER); device = palcGetString(NULL, ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER);
} }

View file

@ -38,41 +38,41 @@
static void *alsasharedobject; static void *alsasharedobject;
int (*psnd_pcm_open) (snd_pcm_t **pcm, const char *name, snd_pcm_stream_t stream, int mode); static int (*psnd_pcm_open) (snd_pcm_t **pcm, const char *name, snd_pcm_stream_t stream, int mode);
int (*psnd_pcm_close) (snd_pcm_t *pcm); static int (*psnd_pcm_close) (snd_pcm_t *pcm);
int (*psnd_config_update_free_global)(void); static int (*psnd_config_update_free_global)(void);
const char *(*psnd_strerror) (int errnum); static const char *(*psnd_strerror) (int errnum);
int (*psnd_pcm_hw_params_any) (snd_pcm_t *pcm, snd_pcm_hw_params_t *params); static int (*psnd_pcm_hw_params_any) (snd_pcm_t *pcm, snd_pcm_hw_params_t *params);
int (*psnd_pcm_hw_params_set_access) (snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_access_t _access); static int (*psnd_pcm_hw_params_set_access) (snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_access_t _access);
int (*psnd_pcm_hw_params_set_format) (snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_format_t val); static int (*psnd_pcm_hw_params_set_format) (snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_format_t val);
int (*psnd_pcm_hw_params_set_channels) (snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int val); static int (*psnd_pcm_hw_params_set_channels) (snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int val);
int (*psnd_pcm_hw_params_set_rate_near) (snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir); static int (*psnd_pcm_hw_params_set_rate_near) (snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir);
int (*psnd_pcm_hw_params_set_period_size_near) (snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val, int *dir); static int (*psnd_pcm_hw_params_set_period_size_near) (snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val, int *dir);
int (*psnd_pcm_hw_params) (snd_pcm_t *pcm, snd_pcm_hw_params_t *params); static int (*psnd_pcm_hw_params) (snd_pcm_t *pcm, snd_pcm_hw_params_t *params);
int (*psnd_pcm_sw_params_current) (snd_pcm_t *pcm, snd_pcm_sw_params_t *params); static int (*psnd_pcm_sw_params_current) (snd_pcm_t *pcm, snd_pcm_sw_params_t *params);
int (*psnd_pcm_sw_params_set_start_threshold) (snd_pcm_t *pcm, snd_pcm_sw_params_t *params, snd_pcm_uframes_t val); static int (*psnd_pcm_sw_params_set_start_threshold) (snd_pcm_t *pcm, snd_pcm_sw_params_t *params, snd_pcm_uframes_t val);
int (*psnd_pcm_sw_params_set_stop_threshold) (snd_pcm_t *pcm, snd_pcm_sw_params_t *params, snd_pcm_uframes_t val); static int (*psnd_pcm_sw_params_set_stop_threshold) (snd_pcm_t *pcm, snd_pcm_sw_params_t *params, snd_pcm_uframes_t val);
int (*psnd_pcm_sw_params) (snd_pcm_t *pcm, snd_pcm_sw_params_t *params); static int (*psnd_pcm_sw_params) (snd_pcm_t *pcm, snd_pcm_sw_params_t *params);
int (*psnd_pcm_hw_params_get_buffer_size) (const snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val); static int (*psnd_pcm_hw_params_get_buffer_size) (const snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val);
int (*psnd_pcm_hw_params_set_buffer_size_near) (snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val); static int (*psnd_pcm_hw_params_set_buffer_size_near) (snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val);
int (*psnd_pcm_set_params) (snd_pcm_t *pcm, snd_pcm_format_t format, snd_pcm_access_t access, unsigned int channels, unsigned int rate, int soft_resample, unsigned int latency); static int (*psnd_pcm_set_params) (snd_pcm_t *pcm, snd_pcm_format_t format, snd_pcm_access_t access, unsigned int channels, unsigned int rate, int soft_resample, unsigned int latency);
snd_pcm_sframes_t (*psnd_pcm_avail_update) (snd_pcm_t *pcm); static snd_pcm_sframes_t (*psnd_pcm_avail_update) (snd_pcm_t *pcm);
snd_pcm_state_t (*psnd_pcm_state) (snd_pcm_t *pcm); static snd_pcm_state_t (*psnd_pcm_state) (snd_pcm_t *pcm);
int (*psnd_pcm_start) (snd_pcm_t *pcm); static int (*psnd_pcm_start) (snd_pcm_t *pcm);
int (*psnd_pcm_recover) (snd_pcm_t *pcm, int err, int silent); static int (*psnd_pcm_recover) (snd_pcm_t *pcm, int err, int silent);
size_t (*psnd_pcm_hw_params_sizeof) (void); static size_t (*psnd_pcm_hw_params_sizeof) (void);
size_t (*psnd_pcm_sw_params_sizeof) (void); static size_t (*psnd_pcm_sw_params_sizeof) (void);
int (*psnd_pcm_mmap_begin) (snd_pcm_t *pcm, const snd_pcm_channel_area_t **areas, snd_pcm_uframes_t *offset, snd_pcm_uframes_t *frames); static int (*psnd_pcm_mmap_begin) (snd_pcm_t *pcm, const snd_pcm_channel_area_t **areas, snd_pcm_uframes_t *offset, snd_pcm_uframes_t *frames);
snd_pcm_sframes_t (*psnd_pcm_mmap_commit) (snd_pcm_t *pcm, snd_pcm_uframes_t offset, snd_pcm_uframes_t frames); static snd_pcm_sframes_t (*psnd_pcm_mmap_commit) (snd_pcm_t *pcm, snd_pcm_uframes_t offset, snd_pcm_uframes_t frames);
snd_pcm_sframes_t (*psnd_pcm_writei) (snd_pcm_t *pcm, const void *buffer, snd_pcm_uframes_t size); static snd_pcm_sframes_t (*psnd_pcm_writei) (snd_pcm_t *pcm, const void *buffer, snd_pcm_uframes_t size);
int (*psnd_pcm_prepare) (snd_pcm_t *pcm); static int (*psnd_pcm_prepare) (snd_pcm_t *pcm);
int (*psnd_device_name_hint) (int card, const char *iface, void ***hints); static int (*psnd_device_name_hint) (int card, const char *iface, void ***hints);
char * (*psnd_device_name_get_hint) (const void *hint, const char *id); static char * (*psnd_device_name_get_hint) (const void *hint, const char *id);
int (*psnd_device_name_free_hint) (void **hints); static int (*psnd_device_name_free_hint) (void **hints);
static unsigned int ALSA_MMap_GetDMAPos (soundcardinfo_t *sc) static unsigned int ALSA_MMap_GetDMAPos (soundcardinfo_t *sc)

View file

@ -92,13 +92,8 @@ cvar_t snd_precache = CVARAF( "s_precache", "1",
cvar_t snd_loadas8bit = CVARAFD( "s_loadas8bit", "0", cvar_t snd_loadas8bit = CVARAFD( "s_loadas8bit", "0",
"loadas8bit", CVAR_ARCHIVE, "loadas8bit", CVAR_ARCHIVE,
"Downsample sounds on load as lower quality 8-bit sound, to save memory."); "Downsample sounds on load as lower quality 8-bit sound, to save memory.");
#ifdef FTE_TARGET_WEB
cvar_t snd_loadasstereo = CVARD( "snd_loadasstereo", "1",
"Force mono sounds to load as if stereo ones, to waste memory. Used to work around stupid browser bugs.");
#else
cvar_t snd_loadasstereo = CVARD( "snd_loadasstereo", "0", cvar_t snd_loadasstereo = CVARD( "snd_loadasstereo", "0",
"Force mono sounds to load as if stereo ones, to waste memory. Not normally useful."); "Force mono sounds to load as if stereo ones, to waste memory. Not normally useful.");
#endif
cvar_t ambient_level = CVARAFD( "s_ambientlevel", "0.3", cvar_t ambient_level = CVARAFD( "s_ambientlevel", "0.3",
"ambient_level", CVAR_ARCHIVE, "ambient_level", CVAR_ARCHIVE,
"This controls the volume levels of automatic area-based sounds (like water or sky), and is quite annoying. If you're playing deathmatch you'll definitely want this OFF."); "This controls the volume levels of automatic area-based sounds (like water or sky), and is quite annoying. If you're playing deathmatch you'll definitely want this OFF.");
@ -1091,6 +1086,7 @@ static float S_Voip_Preprocess(short *start, unsigned int samples, float micamp)
} }
static void S_Voip_TryInitCaptureContext(char *driver, char *device, int rate) static void S_Voip_TryInitCaptureContext(char *driver, char *device, int rate)
{ {
static float throttle;
int i; int i;
s_voip.cdriver = NULL; s_voip.cdriver = NULL;
@ -1114,12 +1110,12 @@ static void S_Voip_TryInitCaptureContext(char *driver, char *device, int rate)
if (!s_voip.cdriver) if (!s_voip.cdriver)
{ {
if (!driver) if (!driver)
Con_Printf("No microphone drivers supported\n"); Con_ThrottlePrintf(&throttle, 0, CON_ERROR"No microphone drivers supported\n");
else else
Con_Printf("Microphone driver \"%s\" is not valid\n", driver); Con_ThrottlePrintf(&throttle, 0, CON_ERROR"Microphone driver \"%s\" is not valid\n", driver);
} }
else else
Con_Printf("No microphone detected\n"); Con_ThrottlePrintf(&throttle, 0, CON_ERROR"No microphone detected\n");
s_voip.cdriver = NULL; s_voip.cdriver = NULL;
} }
@ -1388,7 +1384,7 @@ void S_Voip_Transmit(unsigned char clc, sizebuf_t *buf)
s_voip.capturepos += s_voip.cdriver->Update(s_voip.cdriverctx, (unsigned char*)s_voip.capturebuf + s_voip.capturepos, s_voip.encframesize*2, sizeof(s_voip.capturebuf) - s_voip.capturepos); s_voip.capturepos += s_voip.cdriver->Update(s_voip.cdriverctx, (unsigned char*)s_voip.capturebuf + s_voip.capturepos, s_voip.encframesize*2, sizeof(s_voip.capturebuf) - s_voip.capturepos);
if (!s_voip.wantsend && s_voip.capturepos < s_voip.encframesize*2) if (!voipsendenable || (!s_voip.wantsend && s_voip.capturepos < s_voip.encframesize*2))
{ {
s_voip.voiplevel = -1; s_voip.voiplevel = -1;
s_voip.capturepos = 0; s_voip.capturepos = 0;
@ -1710,10 +1706,10 @@ void S_Voip_MapChange(void)
} }
int S_Voip_Loudness(qboolean ignorevad) int S_Voip_Loudness(qboolean ignorevad)
{ {
if (s_voip.voiplevel > 100)
return 100;
if (!s_voip.cdriverctx || (!ignorevad && s_voip.dumps)) if (!s_voip.cdriverctx || (!ignorevad && s_voip.dumps))
return -1; return -1;
if (s_voip.voiplevel > 100)
return 100;
return s_voip.voiplevel; return s_voip.voiplevel;
} }
int S_Voip_ClientLoudness(unsigned int plno) int S_Voip_ClientLoudness(unsigned int plno)
@ -1770,6 +1766,10 @@ void S_Voip_Parse(void)
bytes = MSG_ReadShort(); bytes = MSG_ReadShort();
MSG_ReadSkip(bytes); MSG_ReadSkip(bytes);
} }
int S_Voip_ClientLoudness(unsigned int plno)
{
return -1;
}
#endif #endif
@ -2188,7 +2188,7 @@ void S_DoRestart (qboolean onlyifneeded)
for (i=1 ; i<MAX_PRECACHE_SOUNDS ; i++) for (i=1 ; i<MAX_PRECACHE_SOUNDS ; i++)
{ {
if (!cl.sound_name[i][0]) if (!cl.sound_name[i])
break; break;
cl.sound_precache[i] = S_FindName (cl.sound_name[i], true, false); cl.sound_precache[i] = S_FindName (cl.sound_name[i], true, false);
} }
@ -2710,7 +2710,7 @@ static void SND_AccumulateSpacialization(soundcardinfo_t *sc, channel_t *ch, vec
listener_vec[1] = DotProduct(listener[seat].right, world_vec); listener_vec[1] = DotProduct(listener[seat].right, world_vec);
listener_vec[2] = DotProduct(listener[seat].up, world_vec); listener_vec[2] = DotProduct(listener[seat].up, world_vec);
if (snd_leftisright.ival) if (snd_leftisright.ival^r_xflip.ival)
listener_vec[1] = -listener_vec[1]; listener_vec[1] = -listener_vec[1];
for (i = 0; i < sc->sn.numchannels; i++) for (i = 0; i < sc->sn.numchannels; i++)
@ -2859,7 +2859,7 @@ static void SND_Spatialize(soundcardinfo_t *sc, channel_t *ch)
listener_vec[1] = DotProduct(listener[seat].right, world_vec); listener_vec[1] = DotProduct(listener[seat].right, world_vec);
listener_vec[2] = DotProduct(listener[seat].up, world_vec); listener_vec[2] = DotProduct(listener[seat].up, world_vec);
if (snd_leftisright.ival) if (snd_leftisright.ival^r_xflip.ival)
listener_vec[1] = -listener_vec[1]; listener_vec[1] = -listener_vec[1];
for (i = 0; i < sc->sn.numchannels; i++) for (i = 0; i < sc->sn.numchannels; i++)

View file

@ -37,10 +37,6 @@ typedef struct
static wavinfo_t GetWavinfo (char *name, qbyte *wav, int wavlength); static wavinfo_t GetWavinfo (char *name, qbyte *wav, int wavlength);
int cache_full_cycle;
qbyte *S_Alloc (int size);
#define LINEARUPSCALE(in, inrate, insamps, out, outrate, outlshift, outrshift) \ #define LINEARUPSCALE(in, inrate, insamps, out, outrate, outlshift, outrshift) \
{ \ { \
scale = inrate / (double)outrate; \ scale = inrate / (double)outrate; \
@ -822,9 +818,54 @@ static qboolean QDECL S_LoadWavSound (sfx_t *s, qbyte *data, size_t datalen, int
return ResampleSfx (s, info.rate, info.numchannels, format, info.samples, info.loopstart, data + info.dataofs); return ResampleSfx (s, info.rate, info.numchannels, format, info.samples, info.loopstart, data + info.dataofs);
} }
qboolean QDECL S_LoadOVSound (sfx_t *s, qbyte *data, size_t datalen, int sndspeed, qboolean forcedecode);
#ifdef FTE_TARGET_WEB #ifdef FTE_TARGET_WEB
#if 1
void S_BrowserDecoded (void *ctx, void *dataptr, int frames, int channels, float rate)
{
sfx_t *sfx = ctx;
//make sure we were not restarting at the time... FIXME: make stricter?
extern sfx_t *known_sfx;
extern int num_sfx;
int id = sfx-known_sfx;
if (id < 0 || id >= num_sfx || sfx != &known_sfx[id])
return; //err... don't crash out!
sfx->loopstart = -1;
if (dataptr)
{ //okay, something loaded. woo.
Z_Free(sfx->decoder.buf);
sfx->decoder.buf = NULL;
sfx->decoder.decodedata = NULL;
ResampleSfx (sfx, rate, channels, QAF_S16, frames, -1, dataptr);
}
else
{
Con_Printf(CON_WARNING"Failed to decode %s\n", sfx->name);
sfx->loadstate = SLS_FAILED;
}
}
static qboolean QDECL S_LoadBrowserFile (sfx_t *s, qbyte *data, size_t datalen, int sndspeed, qboolean forcedecode)
{
struct sfxcache_s *buf;
if (datalen > 4 && !strncmp(data, "RIFF", 4))
return false; //do NOT use this code for wav files. we have no way to read the looping flags which would break things in certain situations. we MUST fall back on our normal loader.
s->decoder.buf = buf = Z_Malloc(sizeof(*buf)+128);
//fill with a placeholder
buf->length = 128;
buf->speed = snd_speed;
buf->format = QAF_S8; //something basic
buf->numchannels=1;
buf->soundoffset = 0;
buf->data = (qbyte*)(buf+1);
s->loopstart = 0; //keep looping silence until it actually loads something.
return emscriptenfte_pcm_loadaudiofile(s, S_BrowserDecoded, data, datalen, sndspeed);
}
#else
//web browsers contain their own decoding libraries that our openal stuff can use. //web browsers contain their own decoding libraries that our openal stuff can use.
static qboolean QDECL S_LoadBrowserFile (sfx_t *s, qbyte *data, size_t datalen, int sndspeed, qboolean forcedecode) static qboolean QDECL S_LoadBrowserFile (sfx_t *s, qbyte *data, size_t datalen, int sndspeed, qboolean forcedecode)
{ {
@ -842,6 +883,9 @@ static qboolean QDECL S_LoadBrowserFile (sfx_t *s, qbyte *data, size_t datalen,
return true; return true;
} }
#endif #endif
#endif
qboolean QDECL S_LoadOVSound (sfx_t *s, qbyte *data, size_t datalen, int sndspeed, qboolean forcedecode);
//highest priority is last. //highest priority is last.
static struct static struct

View file

@ -242,12 +242,12 @@ void S_ResetFailedLoad(void);
#ifdef PEXT2_VOICECHAT #ifdef PEXT2_VOICECHAT
void S_Voip_Parse(void); void S_Voip_Parse(void);
#endif #endif
int S_Voip_ClientLoudness(unsigned int plno);
#ifdef VOICECHAT #ifdef VOICECHAT
extern cvar_t snd_voip_showmeter; extern cvar_t snd_voip_showmeter;
void S_Voip_Transmit(unsigned char clc, sizebuf_t *buf); void S_Voip_Transmit(unsigned char clc, sizebuf_t *buf);
void S_Voip_MapChange(void); void S_Voip_MapChange(void);
int S_Voip_Loudness(qboolean ignorevad); //-1 for not capturing, otherwise between 0 and 100 int S_Voip_Loudness(qboolean ignorevad); //-1 for not capturing, otherwise between 0 and 100
int S_Voip_ClientLoudness(unsigned int plno);
qboolean S_Voip_Speaking(unsigned int plno); qboolean S_Voip_Speaking(unsigned int plno);
void S_Voip_Ignore(unsigned int plno, qboolean ignore); void S_Voip_Ignore(unsigned int plno, qboolean ignore);
#else #else

View file

@ -452,7 +452,7 @@ static void Sys_Register_File_Associations_f(void)
if (!strcmp(iconname, "afterquake") || !strcmp(iconname, "nq")) //hacks so that we don't need to create icons. if (!strcmp(iconname, "afterquake") || !strcmp(iconname, "nq")) //hacks so that we don't need to create icons.
iconname = "quake"; iconname = "quake";
if (FS_NativePath("icon.png", FS_PUBBASEGAMEONLY, iconsyspath, sizeof(iconsyspath))) if (FS_SystemPath("icon.png", FS_PUBBASEGAMEONLY, iconsyspath, sizeof(iconsyspath)))
iconname = iconsyspath; iconname = iconsyspath;
s = va("%s/applications/fte-%s.desktop", xdgbase, fs_manifest->installation); s = va("%s/applications/fte-%s.desktop", xdgbase, fs_manifest->installation);
@ -1215,7 +1215,7 @@ static void DoSign(const char *fname, int signtype)
searchpathfuncs_t *search = FS_OpenPackByExtension(f, NULL, fname, fname, prefix); searchpathfuncs_t *search = FS_OpenPackByExtension(f, NULL, fname, fname, prefix);
if (search) if (search)
{ {
printf("%#08x", search->GeneratePureCRC(search, 0, 0)); printf("%#08x", search->GeneratePureCRC(search, NULL));
search->ClosePath(search); search->ClosePath(search);
} }
else else
@ -1551,15 +1551,6 @@ int main (int c, const char **v)
Host_Init(&parms); Host_Init(&parms);
for (i = 1; i < parms.argc; i++)
{
if (!parms.argv[i])
continue;
if (*parms.argv[i] == '+' || *parms.argv[i] == '-')
break;
Host_RunFile(parms.argv[i], strlen(parms.argv[i]), NULL);
}
oldtime = Sys_DoubleTime (); oldtime = Sys_DoubleTime ();
while (1) while (1)
{ {

View file

@ -948,7 +948,6 @@ int QDECL main(int argc, char **argv)
{ {
float time, newtime, oldtime; float time, newtime, oldtime;
quakeparms_t parms; quakeparms_t parms;
int i;
memset(&parms, 0, sizeof(parms)); memset(&parms, 0, sizeof(parms));
@ -975,15 +974,6 @@ int QDECL main(int argc, char **argv)
oldtime = Sys_DoubleTime (); oldtime = Sys_DoubleTime ();
for (i = 1; i < parms.argc; i++)
{
if (!parms.argv[i])
continue;
if (*parms.argv[i] == '+' || *parms.argv[i] == '-')
break;
Host_RunFile(parms.argv[i], strlen(parms.argv[i]), NULL);
}
//client console should now be initialized. //client console should now be initialized.
/* main window message loop */ /* main window message loop */

View file

@ -3629,7 +3629,7 @@ static qboolean Sys_DoInstall(void)
GetModuleFileNameW(NULL, wide, countof(wide)); GetModuleFileNameW(NULL, wide, countof(wide));
narrowen(exepath, sizeof(exepath), wide); narrowen(exepath, sizeof(exepath), wide);
FS_NativePath(va("%s.exe", fs_gamename.string), FS_ROOT, newexepath, sizeof(newexepath)); FS_SystemPath(va("%s.exe", fs_gamename.string), FS_ROOT, newexepath, sizeof(newexepath));
CopyFileU(exepath, newexepath, FALSE); CopyFileU(exepath, newexepath, FALSE);
/*the game can now be run (using regular autoupdate stuff), but most installers are expected to install the data instead of just more downloaders, so lets do that with a 'nice' progress box*/ /*the game can now be run (using regular autoupdate stuff), but most installers are expected to install the data instead of just more downloaders, so lets do that with a 'nice' progress box*/
@ -4347,16 +4347,6 @@ int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLin
oldtime = Sys_DoubleTime (); oldtime = Sys_DoubleTime ();
if (qtvfile)
{
if (!Host_RunFile(qtvfile, strlen(qtvfile), NULL))
{
SetHookState(false);
Host_Shutdown ();
return EXIT_FAILURE;
}
}
//client console should now be initialized. //client console should now be initialized.
#ifndef MINGW #ifndef MINGW

View file

@ -1437,6 +1437,9 @@ void Validation_Auto_Response(int playernum, char *s)
static float cmdlineresponsetime; static float cmdlineresponsetime;
static float scriptsresponsetime; static float scriptsresponsetime;
if (cls.demoplayback)
return; //noone gives a shit about qtv spectator versions that can't even play without reconnecting.
//quakeworld tends to use f_* //quakeworld tends to use f_*
//netquake uses the slightly more guessable q_* form //netquake uses the slightly more guessable q_* form
if (!strncmp(s, "f_", 2)) if (!strncmp(s, "f_", 2))

View file

@ -94,8 +94,8 @@ static cvar_t v_ipitch_level = CVAR("v_ipitch_level", "0.3");
static cvar_t v_idlescale = CVARD("v_idlescale", "0", "Enable swishing of the view (whether idle or otherwise). Often used for concussion effects."); static cvar_t v_idlescale = CVARD("v_idlescale", "0", "Enable swishing of the view (whether idle or otherwise). Often used for concussion effects.");
cvar_t crosshair = CVARF("crosshair", "1", CVAR_ARCHIVE); cvar_t crosshair = CVARF("crosshair", "1", CVAR_ARCHIVE);
cvar_t crosshaircolor = CVARF("crosshaircolor", "255 255 255", CVAR_ARCHIVE); cvar_t crosshaircolor = CVARF("crosshaircolor", "255 255 255", CVAR_ARCHIVE); //QSSM misnamed it...
cvar_t crosshairsize = CVARF("crosshairsize", "8", CVAR_ARCHIVE); cvar_t crosshairsize = CVARF("crosshairsize", "8", CVAR_ARCHIVE); //QS has scr_crosshairscale, but its a multiplier rather than (vritual) size.
cvar_t cl_crossx = CVARF("cl_crossx", "0", CVAR_ARCHIVE); cvar_t cl_crossx = CVARF("cl_crossx", "0", CVAR_ARCHIVE);
cvar_t cl_crossy = CVARF("cl_crossy", "0", CVAR_ARCHIVE); cvar_t cl_crossy = CVARF("cl_crossy", "0", CVAR_ARCHIVE);
@ -1877,7 +1877,7 @@ static void SCR_DrawAutoID(vec3_t org, player_info_t *pl, qboolean isteam)
x = center[0]*r_refdef.vrect.width+r_refdef.vrect.x; x = center[0]*r_refdef.vrect.width+r_refdef.vrect.x;
y = (1-center[1])*r_refdef.vrect.height+r_refdef.vrect.y; y = (1-center[1])*r_refdef.vrect.height+r_refdef.vrect.y;
if (cls.demoplayback == DPB_MVD || cls.demoplayback == DPB_EZTV) if (cls.demoplayback == DPB_MVD)
{ {
health = pl->statsf[STAT_HEALTH]; health = pl->statsf[STAT_HEALTH];
armour = pl->statsf[STAT_ARMOR]; armour = pl->statsf[STAT_ARMOR];
@ -2050,6 +2050,10 @@ void R_DrawNameTags(void)
vec3_t targ; vec3_t targ;
vec2_t scale = {12,12}; vec2_t scale = {12,12};
msurface_t *surf; msurface_t *surf;
shader_t *shader;
const char *shadername;
char *body;
char fname[MAX_QPATH];
VectorMA(r_refdef.vieworg, 8192, vpn, targ); VectorMA(r_refdef.vieworg, 8192, vpn, targ);
#ifdef CSQC_DAT #ifdef CSQC_DAT
if (csqc_world.progs) if (csqc_world.progs)
@ -2063,23 +2067,53 @@ void R_DrawNameTags(void)
#endif #endif
cl.worldmodel->funcs.NativeTrace(cl.worldmodel, 0, PE_FRAMESTATE, NULL, r_refdef.vieworg, targ, vec3_origin, vec3_origin, false, ~0, &trace); cl.worldmodel->funcs.NativeTrace(cl.worldmodel, 0, PE_FRAMESTATE, NULL, r_refdef.vieworg, targ, vec3_origin, vec3_origin, false, ~0, &trace);
surf = (trace.fraction == 1)?NULL:Mod_GetSurfaceNearPoint(cl.worldmodel, trace.endpos); if (trace.fraction >= 1)
if (surf) str = "hit nothing";
else
{ {
shader_t *shader = surf->texinfo->texture->shader; shader = NULL;
char fname[MAX_QPATH]; if (cl.worldmodel->terrain && trace.brush_id && (shader = Terr_GetShader(cl.worldmodel, &trace)))
char *body = shader?Shader_GetShaderBody(shader, fname, countof(fname)):NULL; shadername = shader->name;
else if ((surf = (trace.fraction == 1)?NULL:Mod_GetSurfaceNearPoint(cl.worldmodel, trace.endpos)))
{
shadername = surf->texinfo->texture->name;
shader = surf->texinfo->texture->shader;
}
else if (trace.surface && *trace.surface->name)
{
shadername = trace.surface->name;
shader = NULL;
}
else
{
shadername = "the unknown";
shader = NULL;
}
body = shader?Shader_GetShaderBody(shader, fname, countof(fname)):NULL;
if (body) if (body)
{ {
// Q_snprintfz(fname, sizeof(fname), "<default shader>"); int width, height;
str = va("^2%s^7\n%s%s\n{%s\n", fname, ruleset_allow_shaders.ival?"":CON_ERROR"WARNING: ruleset_allow_shaders disables external shaders"CON_DEFAULT"\n", surf->texinfo->texture->name, body); char *cr;
const char *fl = "";
if (shader->usageflags & SUF_LIGHTMAP)
fl = S_COLOR_GRAY" (lightmapped)"S_COLOR_WHITE;
else if (shader->usageflags & SUF_2D)
fl = S_COLOR_GRAY" (2d)"S_COLOR_WHITE;
else //if (shader->usageflags & SUF_2D)
fl = S_COLOR_GRAY" (auto)"S_COLOR_WHITE;
if (R_GetShaderSizes(shader, &width, &height, false)>0)
fl = va("%s (%ix%i)", fl, width, height);
while((cr = strchr(body, '\r')))
*cr = ' ';
str = va(S_COLOR_GREEN"%s"S_COLOR_WHITE"\n%s%s%s\n{%s\n", fname, ruleset_allow_shaders.ival?"":CON_ERROR"WARNING: ruleset_allow_shaders disables external shaders"CON_DEFAULT"\n", shadername, fl, body);
Z_Free(body); Z_Free(body);
} }
else else
str = va("hit '%s'", surf->texinfo->texture->name); str = va("hit '%s'", shadername);
} }
else
str = "hit nothing";
R_DrawTextField(r_refdef.vrect.x + r_refdef.vrect.width/4, r_refdef.vrect.y, r_refdef.vrect.width/2, r_refdef.vrect.height, str, CON_WHITEMASK, CPRINT_LALIGN, font_console, scale); R_DrawTextField(r_refdef.vrect.x + r_refdef.vrect.width/4, r_refdef.vrect.y, r_refdef.vrect.width/2, r_refdef.vrect.height, str, CON_WHITEMASK, CPRINT_LALIGN, font_console, scale);
} }
else else

View file

@ -67,14 +67,17 @@ typedef struct vrsetup_s
}; };
} vrsetup_t; } vrsetup_t;
#define VRF_OVERRIDEFRAMETIME 1 //the vr interface is responsible for determining frame intervals instead of using regular clocks (so they can fiddle with prediction etc)
#define VRF_UIACTIVE 2 //we're actually rendering through a headset. use 3d rendering exclusively, with VR UI and stuff.
//interface registered by plugins for VR stuff. //interface registered by plugins for VR stuff.
typedef struct plugvrfuncs_s typedef struct plugvrfuncs_s
{ {
const char *description; const char *description;
qboolean (*Prepare) (vrsetup_t *setupinfo); //called before graphics context init qboolean (*Prepare) (vrsetup_t *setupinfo); //called before graphics context init
qboolean (*Init) (vrsetup_t *setupinfo, rendererstate_t *info); //called after graphics context init qboolean (*Init) (vrsetup_t *setupinfo, rendererstate_t *info); //called after graphics context init
qboolean (*SyncFrame)(double *frametime); //called in the client's main loop, to block/tweak frame times. True means the game should render as fast as possible. unsigned int (*SyncFrame)(double *frametime); //called in the client's main loop, to block/tweak frame times. True means the game should render as fast as possible.
qboolean (*Render) (void(*rendereye)(texid_t tex, vec4_t fovoverride, vec3_t angorg[2])); qboolean (*Render) (void(*rendereye)(texid_t tex, const pxrect_t *viewport, const vec4_t fovoverride, const float projmatrix[16], const float eyematrix[12]));
void (*Shutdown) (void); void (*Shutdown) (void);
#define plugvrfuncs_name "VR" #define plugvrfuncs_name "VR"
} plugvrfuncs_t; } plugvrfuncs_t;

View file

@ -128,7 +128,8 @@ extern qboolean mouseinitialized;
//extern HANDLE hinput, houtput; //extern HANDLE hinput, houtput;
extern HCURSOR hArrowCursor, hCustomCursor; extern HCURSOR hArrowCursor, hCustomCursor;
void *WIN_CreateCursor(const qbyte *imagedata, int width, int height, uploadfmt_t format, float hotx, float hoty, float scale); enum uploadfmt;
void *WIN_CreateCursor(const qbyte *imagedata, int width, int height, enum uploadfmt format, float hotx, float hoty, float scale);
qboolean WIN_SetCursor(void *cursor); qboolean WIN_SetCursor(void *cursor);
void WIN_DestroyCursor(void *cursor); void WIN_DestroyCursor(void *cursor);
void WIN_WindowCreated(HWND window); void WIN_WindowCreated(HWND window);

View file

@ -76,16 +76,16 @@ static void QDECL TP_EnemyColor_CB (struct cvar_s *var, char *oldvalue);
#define TP_SKIN_CVARS \ #define TP_SKIN_CVARS \
TP_CVARAC(cl_teamskin, "", teamskin, TP_SkinCvar_Callback); \ TP_CVARAC(cl_teamskin, "", teamskin, TP_SkinCvar_Callback); \
TP_CVARAC(cl_enemyskin, "", enemyskin, TP_SkinCvar_Callback); \ TP_CVARAC(cl_enemyskin, "", enemyskin, TP_SkinCvar_Callback); \
TP_CVARC(enemycolor, "off", TP_EnemyColor_CB); \ static TP_CVARC(enemycolor, "off", TP_EnemyColor_CB); \
TP_CVARC(teamcolor, "off", TP_TeamColor_CB); static TP_CVARC(teamcolor, "off", TP_TeamColor_CB);
#else #else
#define TP_SKIN_CVARS #define TP_SKIN_CVARS
#endif #endif
#ifdef QUAKESTATS #ifdef QUAKESTATS
#define TP_NAME_CVARS \ #define TP_NAME_CVARS \
TP_CVAR(tp_name_none, ""); \ static TP_CVAR(tp_name_none, ""); \
TP_CVAR(tp_name_axe, "axe"); \ static TP_CVAR(tp_name_axe, "axe"); \
TP_CVAR(tp_name_sg, "sg"); \ TP_CVAR(tp_name_sg, "sg"); \
TP_CVAR(tp_name_ssg, "ssg"); \ TP_CVAR(tp_name_ssg, "ssg"); \
TP_CVAR(tp_name_ng, "ng"); \ TP_CVAR(tp_name_ng, "ng"); \
@ -93,75 +93,75 @@ static void QDECL TP_EnemyColor_CB (struct cvar_s *var, char *oldvalue);
TP_CVAR(tp_name_gl, "gl"); \ TP_CVAR(tp_name_gl, "gl"); \
TP_CVAR(tp_name_rl, "rl"); \ TP_CVAR(tp_name_rl, "rl"); \
TP_CVAR(tp_name_lg, "lg"); \ TP_CVAR(tp_name_lg, "lg"); \
TP_CVAR(tp_name_ra, "ra"); \ static TP_CVAR(tp_name_ra, "ra"); \
TP_CVAR(tp_name_ya, "ya"); \ static TP_CVAR(tp_name_ya, "ya"); \
TP_CVAR(tp_name_ga, "ga"); \ static TP_CVAR(tp_name_ga, "ga"); \
TP_CVAR(tp_name_quad, "quad"); \ static TP_CVAR(tp_name_quad, "quad"); \
TP_CVAR(tp_name_pent, "pent"); \ static TP_CVAR(tp_name_pent, "pent"); \
TP_CVAR(tp_name_ring, "ring"); \ static TP_CVAR(tp_name_ring, "ring"); \
TP_CVAR(tp_name_suit, "suit"); \ static TP_CVAR(tp_name_suit, "suit"); \
TP_CVAR(tp_name_shells, "shells"); \ static TP_CVAR(tp_name_shells, "shells"); \
TP_CVAR(tp_name_nails, "nails"); \ static TP_CVAR(tp_name_nails, "nails"); \
TP_CVAR(tp_name_rockets, "rockets"); \ static TP_CVAR(tp_name_rockets, "rockets"); \
TP_CVAR(tp_name_cells, "cells"); \ static TP_CVAR(tp_name_cells, "cells"); \
TP_CVAR(tp_name_mh, "mega"); \ static TP_CVAR(tp_name_mh, "mega"); \
TP_CVAR(tp_name_health, "health"); \ static TP_CVAR(tp_name_health, "health"); \
TP_CVAR(tp_name_backpack, "pack"); \ static TP_CVAR(tp_name_backpack, "pack"); \
TP_CVAR(tp_name_flag, "flag"); \ static TP_CVAR(tp_name_flag, "flag"); \
TP_CVAR(tp_name_nothing, "nothing"); \ static TP_CVAR(tp_name_nothing, "nothing"); \
TP_CVAR(tp_name_at, "at"); \ static TP_CVAR(tp_name_at, "at"); \
TP_CVAR(tp_need_ra, "50"); \ static TP_CVAR(tp_need_ra, "50"); \
TP_CVAR(tp_need_ya, "50"); \ static TP_CVAR(tp_need_ya, "50"); \
TP_CVAR(tp_need_ga, "50"); \ static TP_CVAR(tp_need_ga, "50"); \
TP_CVAR(tp_need_health, "50"); \ static TP_CVAR(tp_need_health, "50"); \
TP_CVAR(tp_need_weapon, "35687"); \ static TP_CVAR(tp_need_weapon, "35687"); \
TP_CVAR(tp_need_rl, "1"); \ static TP_CVAR(tp_need_rl, "1"); \
TP_CVAR(tp_need_rockets, "5"); \ static TP_CVAR(tp_need_rockets, "5"); \
TP_CVAR(tp_need_cells, "20"); \ static TP_CVAR(tp_need_cells, "20"); \
TP_CVAR(tp_need_nails, "40"); \ static TP_CVAR(tp_need_nails, "40"); \
TP_CVAR(tp_need_shells, "10"); \ static TP_CVAR(tp_need_shells, "10"); \
TP_CVAR(tp_name_disp, "dispenser"); \ static TP_CVAR(tp_name_disp, "dispenser"); \
TP_CVAR(tp_name_sentry, "sentry gun"); \ static TP_CVAR(tp_name_sentry, "sentry gun"); \
TP_CVAR(tp_name_rune_1, "resistance rune"); \ static TP_CVAR(tp_name_rune_1, "resistance rune"); \
TP_CVAR(tp_name_rune_2, "strength rune"); \ static TP_CVAR(tp_name_rune_2, "strength rune"); \
TP_CVAR(tp_name_rune_3, "haste rune"); \ static TP_CVAR(tp_name_rune_3, "haste rune"); \
TP_CVAR(tp_name_rune_4, "regeneration rune"); \ static TP_CVAR(tp_name_rune_4, "regeneration rune"); \
\ \
TP_CVAR(tp_name_status_red, "$R"); \ static TP_CVAR(tp_name_status_red, "$R"); \
TP_CVAR(tp_name_status_green, "$G"); \ static TP_CVAR(tp_name_status_green, "$G"); \
TP_CVAR(tp_name_status_yellow, "$Y"); \ static TP_CVAR(tp_name_status_yellow, "$Y"); \
TP_CVAR(tp_name_status_blue, "$B"); \ static TP_CVAR(tp_name_status_blue, "$B"); \
\ \
TP_CVAR(tp_name_armortype_ga, "g"); \ static TP_CVAR(tp_name_armortype_ga, "g"); \
TP_CVAR(tp_name_armortype_ya, "y"); \ static TP_CVAR(tp_name_armortype_ya, "y"); \
TP_CVAR(tp_name_armortype_ra, "r"); \ static TP_CVAR(tp_name_armortype_ra, "r"); \
TP_CVAR(tp_name_armor, "armor"); \ static TP_CVAR(tp_name_armor, "armor"); \
TP_CVAR(tp_name_weapon, "weapon"); \ static TP_CVAR(tp_name_weapon, "weapon"); \
TP_CVAR(tp_weapon_order, "78654321"); \ static TP_CVAR(tp_weapon_order, "78654321"); \
\ \
TP_CVAR(tp_name_quaded, "quaded"); \ static TP_CVAR(tp_name_quaded, "quaded"); \
TP_CVAR(tp_name_pented, "pented"); \ static TP_CVAR(tp_name_pented, "pented"); \
TP_CVAR(tp_name_separator, "/"); \ static TP_CVAR(tp_name_separator, "/"); \
\ \
TP_CVAR(tp_name_enemy, "enemy"); \ static TP_CVAR(tp_name_enemy, "enemy"); \
TP_CVAR(tp_name_teammate, ""); \ static TP_CVAR(tp_name_teammate, ""); \
TP_CVAR(tp_name_eyes, "eyes"); \ static TP_CVAR(tp_name_eyes, "eyes"); \
\ \
TP_CVAR(loc_name_separator, "-"); \ static TP_CVAR(loc_name_separator, "-"); \
TP_CVAR(loc_name_ssg, "ssg"); \ static TP_CVAR(loc_name_ssg, "ssg"); \
TP_CVAR(loc_name_ng, "ng"); \ static TP_CVAR(loc_name_ng, "ng"); \
TP_CVAR(loc_name_sng, "sng"); \ static TP_CVAR(loc_name_sng, "sng"); \
TP_CVAR(loc_name_gl, "gl"); \ static TP_CVAR(loc_name_gl, "gl"); \
TP_CVAR(loc_name_rl, "rl"); \ static TP_CVAR(loc_name_rl, "rl"); \
TP_CVAR(loc_name_lg, "lg"); \ static TP_CVAR(loc_name_lg, "lg"); \
TP_CVAR(loc_name_ga, "ga"); \ static TP_CVAR(loc_name_ga, "ga"); \
TP_CVAR(loc_name_ya, "ya"); \ static TP_CVAR(loc_name_ya, "ya"); \
TP_CVAR(loc_name_ra, "ra"); \ static TP_CVAR(loc_name_ra, "ra"); \
TP_CVAR(loc_name_mh, "mh"); \ static TP_CVAR(loc_name_mh, "mh"); \
TP_CVAR(loc_name_quad, "quad"); \ static TP_CVAR(loc_name_quad, "quad"); \
TP_CVAR(loc_name_pent, "pent"); \ static TP_CVAR(loc_name_pent, "pent"); \
TP_CVAR(loc_name_ring, "ring"); \ static TP_CVAR(loc_name_ring, "ring"); \
TP_CVAR(loc_name_suit, "suit"); static TP_CVAR(loc_name_suit, "suit");
#else #else
#define TP_NAME_CVARS #define TP_NAME_CVARS
#endif #endif
@ -171,16 +171,16 @@ static void QDECL TP_EnemyColor_CB (struct cvar_s *var, char *oldvalue);
#define TP_CVARS \ #define TP_CVARS \
TP_SKIN_CVARS \ TP_SKIN_CVARS \
TP_NAME_CVARS \ TP_NAME_CVARS \
TP_CVAR(cl_fakename, ""); \ static TP_CVAR(cl_fakename, ""); \
TP_CVAR(cl_parseSay, "1"); \ TP_CVAR(cl_parseSay, "1"); \
TP_CVAR(cl_parseFunChars, "1"); \ TP_CVAR(cl_parseFunChars, "1"); \
TP_CVAR(cl_triggers, "1"); \ TP_CVAR(cl_triggers, "1"); \
TP_CVAR(tp_autostatus, ""); /* things which will not always change, but are useful */ \ static TP_CVAR(tp_autostatus, ""); /* things which will not always change, but are useful */ \
TP_CVAR(tp_forceTriggers, "0"); \ TP_CVAR(tp_forceTriggers, "0"); \
TP_CVAR(tp_loadlocs, "1"); \ TP_CVAR(tp_loadlocs, "1"); \
TP_CVAR(tp_soundtrigger, "~"); \ static TP_CVAR(tp_soundtrigger, "~"); \
\ \
TP_CVAR(tp_name_someplace, "someplace") static TP_CVAR(tp_name_someplace, "someplace")
//create the globals for all the TP cvars. //create the globals for all the TP cvars.
#define TP_CVAR(name,def) cvar_t name = CVAR(#name, def) #define TP_CVAR(name,def) cvar_t name = CVAR(#name, def)
@ -906,10 +906,6 @@ static char *Macro_demoplayback (void)
case DPB_QUAKE2: case DPB_QUAKE2:
return "dm2playback"; return "dm2playback";
#endif #endif
//gcc will warn if we add annother playback and forget here, otherwise I'd use a default.
case DPB_EZTV:
break;
} }
return "1"; //unknown. return "1"; //unknown.
} }
@ -2311,9 +2307,9 @@ int TP_CategorizeMessage (char *s, int *offset, player_info_t **plr)
// no team messages in teamplay 0, except for our own // no team messages in teamplay 0, except for our own
if (pv->spectator) if (pv->spectator)
{ {
unsigned int track = Cam_TrackNum(pv); int track = Cam_TrackNum(pv);
if (i == track || ( cl.teamplay && if (track>=0 && (i == track || ( cl.teamplay &&
!strcmp(cl.players[track].team, player->team)) ) !strcmp(cl.players[track].team, player->team)) ))
{ {
flags |= TPM_OBSERVEDTEAM; flags |= TPM_OBSERVEDTEAM;
} }
@ -3710,7 +3706,9 @@ void TP_Init (void)
#define TP_CVAR(name,def) Cvar_Register (&name, TEAMPLAYVARS); #define TP_CVAR(name,def) Cvar_Register (&name, TEAMPLAYVARS);
#define TP_CVARC(name,def,callback) Cvar_Register (&name, TEAMPLAYVARS); #define TP_CVARC(name,def,callback) Cvar_Register (&name, TEAMPLAYVARS);
#define TP_CVARAC(name,def,name2,callback) Cvar_Register (&name, TEAMPLAYVARS); #define TP_CVARAC(name,def,name2,callback) Cvar_Register (&name, TEAMPLAYVARS);
#define static
TP_CVARS; TP_CVARS;
#undef static
#undef TP_CVAR #undef TP_CVAR
#undef TP_CVARC #undef TP_CVARC
#undef TP_CVARAC #undef TP_CVARAC

View file

@ -173,10 +173,10 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#define DISTRIBUTIONLONG "Forethought Entertainment" //effectively the 'company' name #define DISTRIBUTIONLONG "Forethought Entertainment" //effectively the 'company' name
#endif #endif
#ifndef FULLENGINENAME #ifndef FULLENGINENAME
#define FULLENGINENAME "FTE Quake" //the posh name for the engine #define FULLENGINENAME "FTE QW" //the posh name for the engine, note that 'Quake' is trademarked so we should not be using it here.
#endif #endif
#ifndef ENGINEWEBSITE #ifndef ENGINEWEBSITE
#define ENGINEWEBSITE "^8http://^4fte^8.^4triptohell^8.^4info" //url for program #define ENGINEWEBSITE "^8https://^4fte^8.^4triptohell^8.^4info" //url for program
#endif #endif
#if !defined(_WIN32) || defined(WINRT) #if !defined(_WIN32) || defined(WINRT)
@ -187,9 +187,9 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#undef AVAIL_WASAPI #undef AVAIL_WASAPI
#endif #endif
#if !(defined(__linux__) || defined(__CYGWIN__)) || defined(ANDROID) //#if !(defined(__linux__) || defined(__CYGWIN__)) || defined(ANDROID)
#undef HAVE_GNUTLS // #undef HAVE_GNUTLS
#endif //#endif
#if !defined(_WIN32) || (defined(_MSC_VER) && (_MSC_VER < 1300)) || defined(FTE_SDL) #if !defined(_WIN32) || (defined(_MSC_VER) && (_MSC_VER < 1300)) || defined(FTE_SDL)
#undef HAVE_WINSSPI #undef HAVE_WINSSPI
#endif #endif
@ -253,7 +253,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#undef Q2BSPS #undef Q2BSPS
#undef Q3BSPS #undef Q3BSPS
#undef RFBSPS #undef RFBSPS
#undef WEBSERVER //http server
#undef FTPSERVER //ftp server #undef FTPSERVER //ftp server
#undef WEBCLIENT //http client. #undef WEBCLIENT //http client.
#undef FTPCLIENT //ftp client. #undef FTPCLIENT //ftp client.
@ -285,7 +284,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#undef HAVE_PACKET //no udp support #undef HAVE_PACKET //no udp support
//try to trim the fat //try to trim the fat
#undef VOICECHAT //too lazy to compile opus // #undef VOICECHAT //too lazy to compile opus
#undef HLCLIENT //dlls... #undef HLCLIENT //dlls...
#undef HLSERVER //dlls... #undef HLSERVER //dlls...
// #undef CL_MASTER //bah. use the site to specify the servers. // #undef CL_MASTER //bah. use the site to specify the servers.
@ -293,7 +292,9 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#undef RAGDOLL //no ode #undef RAGDOLL //no ode
#undef TCPCONNECT //err... #undef TCPCONNECT //err...
#undef IRCCONNECT //not happening #undef IRCCONNECT //not happening
#if !defined(USE_INTERNAL_BULLET) && !defined(USE_INTERNAL_ODE) && !defined(MODELFMT_GLTF) && !defined(STATIC_EZHUD) && !defined(STATIC_OPENSSL) && !defined(STATIC_Q3)
#undef PLUGINS //pointless #undef PLUGINS //pointless
#endif
#undef VM_Q1 //no dlls #undef VM_Q1 //no dlls
#undef MAP_PROC //meh #undef MAP_PROC //meh
// #undef HALFLIFEMODELS //blurgh // #undef HALFLIFEMODELS //blurgh
@ -392,15 +393,18 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#ifdef NO_GNUTLS #ifdef NO_GNUTLS
#undef HAVE_GNUTLS #undef HAVE_GNUTLS
#endif #endif
#ifdef NO_WINSSPI
#undef HAVE_WINSSPI
#endif
#ifdef NO_OPENGL #ifdef NO_OPENGL
#undef GLQUAKE #undef GLQUAKE
#undef USE_EGL #undef USE_EGL
#endif #endif
#if defined(HAVE_GNUTLS) || defined(HAVE_WINSSPI) || defined(HAVE_PLUGINS) #if (defined(HAVE_GNUTLS) || defined(HAVE_WINSSPI) || defined(PLUGINS)) && !defined(FTE_TARGET_WEB)
#define HAVE_SSL #define HAVE_SSL
#endif #endif
#if defined(HAVE_GNUTLS) || defined(HAVE_WINSSPI) || defined(HAVE_PLUGINS) #if (defined(HAVE_GNUTLS) || defined(HAVE_WINSSPI) || defined(PLUGINS)) && !defined(FTE_TARGET_WEB)
//FIXME: HAVE_WINSSPI does not work as a server. //FIXME: HAVE_WINSSPI does not work as a server.
//FIXME: advertising dtls without a valid certificate will probably bug out if a client tries to auto-upgrade. //FIXME: advertising dtls without a valid certificate will probably bug out if a client tries to auto-upgrade.
//FIXME: we don't cache server certs //FIXME: we don't cache server certs
@ -456,7 +460,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#ifndef HAVE_TCP #ifndef HAVE_TCP
#undef TCPCONNECT #undef TCPCONNECT
#undef IRCCONNECT #undef IRCCONNECT
#undef WEBSERVER //http server
#undef FTPSERVER //ftp server #undef FTPSERVER //ftp server
#undef FTPCLIENT //ftp client. #undef FTPCLIENT //ftp client.
#if !defined(FTE_TARGET_WEB) #if !defined(FTE_TARGET_WEB)
@ -488,7 +491,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#undef Q2SERVER #undef Q2SERVER
#undef Q3SERVER #undef Q3SERVER
#undef HLSERVER #undef HLSERVER
#undef WEBSERVER
#undef FTPSERVER #undef FTPSERVER
#undef SUBSERVERS #undef SUBSERVERS
#undef VM_Q1 #undef VM_Q1
@ -558,6 +560,11 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#else #else
#define IFMINIMAL(x,y) y #define IFMINIMAL(x,y) y
#endif #endif
#ifdef FTE_TARGET_WEB
#define IFWEB(x,y) x
#else
#define IFWEB(x,y) y
#endif
// defs common to client and server // defs common to client and server
@ -902,8 +909,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#define MAX_NET_LIGHTSTYLES (INVALID_LIGHTSTYLE+1) // 16bit. the last index MAY be used to signify an invalid lightmap in the bsp, but is still valid for rtlights. #define MAX_NET_LIGHTSTYLES (INVALID_LIGHTSTYLE+1) // 16bit. the last index MAY be used to signify an invalid lightmap in the bsp, but is still valid for rtlights.
#define MAX_STANDARDLIGHTSTYLES 64 #define MAX_STANDARDLIGHTSTYLES 64
#define MAX_PRECACHE_MODELS 4096 // 14bit. #define MAX_PRECACHE_MODELS 16384 // 14bit.
#define MAX_PRECACHE_SOUNDS 2048 // 14bit. #define MAX_PRECACHE_SOUNDS 4096 // 14bit.
#define MAX_SSPARTICLESPRE 1024 // 14bit. precached particle effect names, for server-side pointparticles/trailparticles. #define MAX_SSPARTICLESPRE 1024 // 14bit. precached particle effect names, for server-side pointparticles/trailparticles.
#define MAX_VWEP_MODELS 32 #define MAX_VWEP_MODELS 32

View file

@ -177,19 +177,19 @@ enum q1contents_e
Q1CONTENTS_SLIME = -4, Q1CONTENTS_SLIME = -4,
Q1CONTENTS_LAVA = -5, Q1CONTENTS_LAVA = -5,
Q1CONTENTS_SKY = -6, Q1CONTENTS_SKY = -6,
//#define Q1CONTENTS_ORIGIN -7 /*not known to engine - origin or something*/ //#define HLCONTENTS_ORIGIN -7 /*not known to engine - origin or something*/
Q1CONTENTS_CLIP = -8, /*solid to players+monsters, but not tracelines*/ HLCONTENTS_CLIP = -8, /*solid to players+monsters, but not tracelines*/
Q1CONTENTS_CURRENT_0 = -9, /*moves player*/ HLCONTENTS_CURRENT_0 = -9, /*moves player*/
Q1CONTENTS_CURRENT_90 = -10, /*moves player*/ HLCONTENTS_CURRENT_90 = -10, /*moves player*/
Q1CONTENTS_CURRENT_180 = -11, /*moves player*/ HLCONTENTS_CURRENT_180 = -11, /*moves player*/
Q1CONTENTS_CURRENT_270 = -12, /*moves player*/ HLCONTENTS_CURRENT_270 = -12, /*moves player*/
Q1CONTENTS_CURRENT_UP = -13, /*moves player*/ HLCONTENTS_CURRENT_UP = -13, /*moves player*/
Q1CONTENTS_CURRENT_DOWN = -14, /*moves player*/ HLCONTENTS_CURRENT_DOWN = -14, /*moves player*/
Q1CONTENTS_TRANS = -15, /*should be solid I guess*/ HLCONTENTS_TRANS = -15, /*empty, but blocks pvs (for opaque non-solid windows, like vanilla-q1 water)*/
Q1CONTENTS_LADDER = -16, /*player can climb up/down*/ Q1CONTENTS_LADDER = -16, /*player can climb up/down*/
Q1CONTENTS_MONSTERCLIP = -17, /*solid to monster movement*/ Q1CONTENTS_MONSTERCLIP = -17, /*solid to monster movement*/
Q1CONTENTS_PLAYERCLIP = -18, /*solid to player movement*/ Q1CONTENTS_PLAYERCLIP = -18, /*solid to player movement*/
Q1CONTENTS_CORPSE = -19, /*solid to tracelines*/ Q1CONTENTS_CORPSE = -19, /*solid to tracelines but not boxes*/
}; };
// !!! if this is changed, it must be changed in asm_i386.h too !!! // !!! if this is changed, it must be changed in asm_i386.h too !!!
@ -572,7 +572,7 @@ typedef struct
#define Q2CONTENTS_ORIGIN 0x01000000 // removed before bsping an entity #define Q2CONTENTS_ORIGIN 0x01000000 // removed before bsping an entity
#define Q2CONTENTS_MONSTER FTECONTENTS_BODY //0x02000000 // should never be on a brush, only in game #define Q2CONTENTS_MONSTER FTECONTENTS_BODY //0x02000000 // should never be on a brush, only in game
#define Q2CONTENTS_DEADMONSTER FTECONTENTS_CORPSE //0x04000000 #define Q2CONTENTS_DEADMONSTER FTECONTENTS_CORPSE //0x04000000
#define Q2CONTENTS_DETAIL 0x08000000 // brushes to be added after vis leafs #define Q2CONTENTS_DETAIL FTECONTENTS_DETAIL // 0x08000000 // brushes to be added after vis leafs
#define Q2CONTENTS_TRANSLUCENT 0x10000000 // auto set if any surface has trans #define Q2CONTENTS_TRANSLUCENT 0x10000000 // auto set if any surface has trans
#define Q2CONTENTS_LADDER 0x20000000 #define Q2CONTENTS_LADDER 0x20000000
//0x40000000 //0x40000000
@ -606,7 +606,7 @@ typedef struct
#define Q3CONTENTS_ORIGIN Q2CONTENTS_ORIGIN //0x01000000 #define Q3CONTENTS_ORIGIN Q2CONTENTS_ORIGIN //0x01000000
#define Q3CONTENTS_BODY FTECONTENTS_BODY //0x02000000 #define Q3CONTENTS_BODY FTECONTENTS_BODY //0x02000000
#define Q3CONTENTS_CORPSE FTECONTENTS_CORPSE //0x04000000 #define Q3CONTENTS_CORPSE FTECONTENTS_CORPSE //0x04000000
#define Q3CONTENTS_DETAIL Q2CONTENTS_DETAIL //0x08000000 #define Q3CONTENTS_DETAIL FTECONTENTS_DETAIL //0x08000000
#define Q3CONTENTS_STRUCTURAL 0x10000000 #define Q3CONTENTS_STRUCTURAL 0x10000000
#define Q3CONTENTS_TRANSLUCENT 0x20000000 #define Q3CONTENTS_TRANSLUCENT 0x20000000
#define Q3CONTENTS_TRIGGER 0x40000000 #define Q3CONTENTS_TRIGGER 0x40000000
@ -649,11 +649,11 @@ typedef struct
//#define TI_KINGPIN_WNDW33 0x4000 //#define TI_KINGPIN_WNDW33 0x4000
//#define TI_KINGPIN_WNDW64 0x8000 //#define TI_KINGPIN_WNDW64 0x8000
#define TI_Q2EX_ALPHATEST (1u<<25) #define TI_Q2EX_ALPHATEST (1u<<25) //seems to be a thing in other pre q2e engines too.
#define TI_N64_UV (1u<<28) #define TI_N64_UV (1u<<28) //2 qu per texel instead of 1... (still 16qu per luxel)
#define TI_N64_SCROLL_X (1u<<29) #define TI_N64_SCROLL_X (1u<<29) //scrolls fully right each second.
#define TI_N64_SCROLL_Y (1u<<30) #define TI_N64_SCROLL_Y (1u<<30) //scrolls fully down each second.
#define TI_N64_SCROLL_FLIP (1u<<31) #define TI_N64_SCROLL_FLIP (1u<<31) //reverses the scroll dirs.
//Surface flags //Surface flags
//#define Q3SURFACEFLAG_NODAMAGE 0x1 // never give falling damage //#define Q3SURFACEFLAG_NODAMAGE 0x1 // never give falling damage

View file

@ -36,6 +36,7 @@ static const cvar_t dpcompat_console = {0};
int Cmd_ExecLevel; int Cmd_ExecLevel;
qboolean cmd_didwait; qboolean cmd_didwait;
qboolean cmd_blockwait; qboolean cmd_blockwait;
static qboolean cmd_stuffedcmdline;
void Cmd_ForwardToServer (void); void Cmd_ForwardToServer (void);
@ -590,68 +591,67 @@ quake -nosound +cmd amlev1
*/ */
void Cmd_StuffCmds (void) void Cmd_StuffCmds (void)
{ {
int i, j; int i;
int s; int s;
char *text, *build, c; char *text;
const char *arg;
int pluscmd = false;
if (cmd_stuffedcmdline)
return; //don't do it multiple times
// build the combined string to parse from // build the combined string to parse from
s = 0; s = 2;
for (i=1 ; i<com_argc ; i++) for (i=1 ; i<com_argc ; i++)
{ {
if (!com_argv[i]) if (!com_argv[i])
continue; // NEXTSTEP nulls out -NXHost continue; // NEXTSTEP nulls out -NXHost
s += Q_strlen (com_argv[i]) + 3; s += Q_strlen (com_argv[i])*2 + 4;
} }
if (!s) if (!s)
return; return;
text = (char*)Z_Malloc (s+1); text = (char*)Z_Malloc (s+2);
text[0] = 0; text[0] = 0;
for (i=1 ; i<com_argc ; i++) for (i=1 ; i<com_argc ; i++)
{ {
if (!com_argv[i]) if (!com_argv[i])
continue; // NEXTSTEP nulls out -NXHost continue; // NEXTSTEP nulls out -NXHost
if (strchr(com_argv[i], ' ') || strchr(com_argv[i], '\t') || strchr(com_argv[i], '@') || strchr(com_argv[i], '/') || strchr(com_argv[i], '\\')) arg = com_argv[i];
if ((*arg == '+' || *arg == '-') && !(arg[1] >= '0' && arg[1] <= '9')) //we only really want the '+foo arg' commands, split by +/- prefixes. if its a -1 or +1 then that's a numerical parameter, not a separate command!
{ {
Q_strcat (text,"\""); if (*text)
Q_strcat (text,com_argv[i]); {
Q_strcat (text,"\""); Q_strcat (text, "\n");
Cbuf_AddText (text, RESTRICT_LOCAL);
*text = 0;
} }
else pluscmd = *arg++ == '+';
Q_strcat (text,com_argv[i]); }
if (i != com_argc-1)
if (pluscmd)
{
if (*text)
Q_strcat (text, " "); Q_strcat (text, " ");
if (strchr(arg, ' ') || strchr(arg, '\t') || strchr(arg, '@') || strchr(arg, '/') || strchr(arg, '\\'))
COM_QuotedString(arg, text+strlen(text),s-strlen(text), false);
else
Q_strcat (text,arg);
}
} }
// pull out the commands if (*text)
build = (char*)Z_Malloc (s+1);
build[0] = 0;
for (i=0 ; i<s-1 ; i++)
{ {
if (text[i] == '+') Q_strcat (text, "\n");
{ Cbuf_AddText (text, RESTRICT_LOCAL);
i++;
for (j=i ; ((text[j-1] != ' ') || ((text[j] != '+') && (text[j] != '-'))) && (text[j] != 0) ; j++)
;
c = text[j];
text[j] = 0;
Q_strcat (build, text+i);
Q_strcat (build, "\n");
text[j] = c;
i = j-1;
} }
}
if (build[0])
Cbuf_AddText (build, RESTRICT_LOCAL);
Z_Free (text); Z_Free (text);
Z_Free (build);
cmd_stuffedcmdline = true; //don't add multiple times.
//and exec anything added.
Cbuf_Execute ();
} }
#if defined(HAVE_LEGACY) && defined(HAVE_CLIENT) #if defined(HAVE_LEGACY) && defined(HAVE_CLIENT)
@ -784,8 +784,8 @@ static void Cmd_Exec_f (void)
char fulldefault[MAX_OSPATH]; char fulldefault[MAX_OSPATH];
char fullconfig[MAX_OSPATH]; char fullconfig[MAX_OSPATH];
*fulldefault = *fullconfig = 0; *fulldefault = *fullconfig = 0;
FS_NativePath("default.cfg", FS_GAME, fulldefault, sizeof(fulldefault)); FS_DisplayPath("default.cfg", FS_GAME, fulldefault, sizeof(fulldefault));
FS_NativePath(name, FS_GAME, fullconfig, sizeof(fullconfig)); FS_DisplayPath(name, FS_GAME, fullconfig, sizeof(fullconfig));
Con_Printf("Refusing to execute \"%s\", superceded by %s\n", fullconfig, fulldefault); Con_Printf("Refusing to execute \"%s\", superceded by %s\n", fullconfig, fulldefault);
} }
return; return;
@ -802,8 +802,8 @@ static void Cmd_Exec_f (void)
char fulldefault[MAX_OSPATH]; char fulldefault[MAX_OSPATH];
char fullconfig[MAX_OSPATH]; char fullconfig[MAX_OSPATH];
*fulldefault = *fullconfig = 0; *fulldefault = *fullconfig = 0;
FS_NativePath("default.cfg", FS_GAME, fulldefault, sizeof(fulldefault)); FS_DisplayPath("default.cfg", FS_GAME, fulldefault, sizeof(fulldefault));
FS_NativePath(name, FS_GAME, fullconfig, sizeof(fullconfig)); FS_DisplayPath(name, FS_GAME, fullconfig, sizeof(fullconfig));
Con_Printf("Refusing to execute \"%s\", superceded by %s\n", fullconfig, fulldefault); Con_Printf("Refusing to execute \"%s\", superceded by %s\n", fullconfig, fulldefault);
} }
return; return;
@ -4137,7 +4137,7 @@ static void Cmd_WriteConfig_f(void)
vfsfile_t *f; vfsfile_t *f;
char *filename; char *filename;
char fname[MAX_QPATH]; char fname[MAX_QPATH];
char sysname[MAX_OSPATH]; char displayname[MAX_OSPATH];
qboolean all = true; qboolean all = true;
//special variation that only saves if an archived cvar was actually modified. //special variation that only saves if an archived cvar was actually modified.
@ -4154,7 +4154,7 @@ static void Cmd_WriteConfig_f(void)
MasterInfo_WriteServers(); MasterInfo_WriteServers();
#endif #endif
f = FS_OpenWithFriends(fname, sysname, sizeof(sysname), 4, "quake.rc", "hexen.rc", "*.cfg", "configs/*.cfg", "dlcache/*.pk3*"); f = FS_OpenWithFriends(fname, displayname, sizeof(displayname), 4, "quake.rc", "hexen.rc", "*.cfg", "configs/*.cfg", "dlcache/*.pk3*");
all = cfg_save_all.ival; all = cfg_save_all.ival;
} }
@ -4170,7 +4170,7 @@ static void Cmd_WriteConfig_f(void)
return; return;
} }
FS_NativePath(fname, FS_BASEGAMEONLY, sysname, sizeof(sysname)); FS_DisplayPath(fname, FS_BASEGAMEONLY, displayname, sizeof(displayname));
FS_CreatePath(fname, FS_BASEGAMEONLY); FS_CreatePath(fname, FS_BASEGAMEONLY);
f = FS_OpenVFS(fname, "wbp", FS_BASEGAMEONLY); f = FS_OpenVFS(fname, "wbp", FS_BASEGAMEONLY);
@ -4192,7 +4192,7 @@ static void Cmd_WriteConfig_f(void)
Q_snprintfz(fname, sizeof(fname), "configs/%s", filename); Q_snprintfz(fname, sizeof(fname), "configs/%s", filename);
COM_DefaultExtension(fname, ".cfg", sizeof(fname)); COM_DefaultExtension(fname, ".cfg", sizeof(fname));
FS_NativePath(fname, FS_BASEGAMEONLY, sysname, sizeof(sysname)); FS_DisplayPath(fname, FS_BASEGAMEONLY, displayname, sizeof(displayname));
FS_CreatePath(fname, FS_BASEGAMEONLY); FS_CreatePath(fname, FS_BASEGAMEONLY);
f = FS_OpenVFS(fname, "wbp", FS_BASEGAMEONLY); f = FS_OpenVFS(fname, "wbp", FS_BASEGAMEONLY);
@ -4200,7 +4200,7 @@ static void Cmd_WriteConfig_f(void)
} }
if (!f) if (!f)
{ {
Con_Printf (CON_ERROR "Couldn't write config %s\n", sysname); Con_Printf (CON_ERROR "Couldn't write config %s\n", displayname);
return; return;
} }
@ -4237,7 +4237,7 @@ static void Cmd_WriteConfig_f(void)
Cvar_Saved(); Cvar_Saved();
Con_Printf ("Wrote %s\n",sysname); Con_Printf ("Wrote %s\n",displayname);
} }
static void Cmd_Reset_f(void) static void Cmd_Reset_f(void)
@ -4426,6 +4426,7 @@ Cmd_Init
*/ */
void Cmd_Init (void) void Cmd_Init (void)
{ {
cmd_stuffedcmdline = false;
macro_count = 0; macro_count = 0;
// //
// register our commands // register our commands

View file

@ -85,7 +85,7 @@ qboolean Mod_DoCRC(model_t *mod, char *buffer, int buffersize)
extern cvar_t gl_part_flame, r_fullbrightSkins, r_fb_models; extern cvar_t gl_part_flame, r_fullbrightSkins, r_fb_models;
extern cvar_t r_noaliasshadows; extern cvar_t r_noaliasshadows;
extern cvar_t r_skin_overlays; //extern cvar_t r_skin_overlays;
extern cvar_t mod_md3flags; extern cvar_t mod_md3flags;
@ -1020,7 +1020,7 @@ typedef struct
float *pose[FRAME_BLENDS*2]; //pointer to the raw frame data for bone 0. float *pose[FRAME_BLENDS*2]; //pointer to the raw frame data for bone 0.
void *needsfree[FRAME_BLENDS*2]; void *needsfree[FRAME_BLENDS*2];
} skellerps_t; } skellerps_t;
static qboolean Alias_BuildSkelLerps(skellerps_t *lerps, const struct framestateregion_s *fs, int numbones, const galiasinfo_t *inf) static qboolean Alias_BuildSkelLerps(skellerps_t *lerps, const struct framestateregion_s *fs, const galiasbone_t *boneinf, int numbones, const galiasinfo_t *inf)
{ {
int frame1; //signed, because frametime might be negative... int frame1; //signed, because frametime might be negative...
int frame2; int frame2;
@ -1066,7 +1066,7 @@ static qboolean Alias_BuildSkelLerps(skellerps_t *lerps, const struct framestate
{ {
lerps->frac[l] = fs->lerpweight[b]; lerps->frac[l] = fs->lerpweight[b];
lerps->needsfree[l] = BZ_Malloc(sizeof(float)*12*numbones); lerps->needsfree[l] = BZ_Malloc(sizeof(float)*12*numbones);
lerps->pose[l] = g->GetRawBones(inf, g, time, lerps->needsfree[l], numbones); lerps->pose[l] = g->GetRawBones(inf, g, time, lerps->needsfree[l], boneinf, numbones);
if (lerps->pose[l]) if (lerps->pose[l])
l++; l++;
else else
@ -1107,14 +1107,14 @@ static qboolean Alias_BuildSkelLerps(skellerps_t *lerps, const struct framestate
{ {
totalweight += lerps->frac[l]; totalweight += lerps->frac[l];
lerps->needsfree[l] = NULL; lerps->needsfree[l] = NULL;
lerps->pose[l++] = (float*)g->boneofs + numbones*12*frame1; lerps->pose[l++] = (float*)g->boneofs + inf->numbones*12*frame1;
} }
lerps->frac[l] = (mlerp)*fs->lerpweight[b]; lerps->frac[l] = (mlerp)*fs->lerpweight[b];
if (lerps->frac[l]>0) if (lerps->frac[l]>0)
{ {
totalweight += lerps->frac[l]; totalweight += lerps->frac[l];
lerps->needsfree[l] = NULL; lerps->needsfree[l] = NULL;
lerps->pose[l++] = (float*)g->boneofs + numbones*12*frame2; lerps->pose[l++] = (float*)g->boneofs + inf->numbones*12*frame2;
} }
} }
} }
@ -1153,16 +1153,13 @@ static qboolean Alias_BuildSkelLerps(skellerps_t *lerps, const struct framestate
/* /*
finds the various blend info. returns number of bone blocks used. finds the various blend info. returns number of bone blocks used.
*/ */
static int Alias_FindRawSkelData(galiasinfo_t *inf, const framestate_t *fstate, skellerps_t *lerps, size_t firstbone, size_t lastbone) static int Alias_FindRawSkelData(galiasinfo_t *inf, const framestate_t *fstate, skellerps_t *lerps, size_t firstbone, size_t lastbone, const galiasbone_t *boneinfo)
{ {
int bonegroup; int bonegroup;
int cbone = 0; int cbone = 0;
int endbone; int endbone;
int numbonegroups=0; int numbonegroups=0;
if (lastbone > inf->numbones)
lastbone = inf->numbones;
for (bonegroup = 0; bonegroup < FS_COUNT; bonegroup++) for (bonegroup = 0; bonegroup < FS_COUNT; bonegroup++)
{ {
endbone = fstate->g[bonegroup].endbone; endbone = fstate->g[bonegroup].endbone;
@ -1176,7 +1173,7 @@ static int Alias_FindRawSkelData(galiasinfo_t *inf, const framestate_t *fstate,
if (lerps->firstbone == lerps->endbone) if (lerps->firstbone == lerps->endbone)
continue; continue;
if (!inf->numanimations || !Alias_BuildSkelLerps(lerps, &fstate->g[bonegroup], inf->numbones, inf)) //if there's no animations in this model, use the base pose instead. if (!inf->numanimations || !Alias_BuildSkelLerps(lerps, &fstate->g[bonegroup], boneinfo, lerps->endbone, inf)) //if there's no animations in this model, use the base pose instead.
{ {
if (!inf->baseframeofs) if (!inf->baseframeofs)
continue; //nope, not happening. continue; //nope, not happening.
@ -1200,11 +1197,11 @@ static int Alias_FindRawSkelData(galiasinfo_t *inf, const framestate_t *fstate,
return value is the lastbone argument, or less if the model simply doesn't have that many bones. return value is the lastbone argument, or less if the model simply doesn't have that many bones.
_always_ writes into result _always_ writes into result
*/ */
static int Alias_BlendBoneData(galiasinfo_t *inf, framestate_t *fstate, float *result, skeltype_t skeltype, int firstbone, int lastbone) static int Alias_BlendBoneData(galiasinfo_t *inf, const framestate_t *fstate, float *result, skeltype_t skeltype, int firstbone, int lastbone, const galiasbone_t *boneinfo)
{ {
skellerps_t lerps[FS_COUNT], *lerp; skellerps_t lerps[FS_COUNT], *lerp;
size_t bone, endbone = 0; size_t bone, endbone = 0;
size_t numgroups = Alias_FindRawSkelData(inf, fstate, lerps, firstbone, lastbone); size_t numgroups = Alias_FindRawSkelData(inf, fstate, lerps, firstbone, lastbone, boneinfo);
float *pose, *matrix; float *pose, *matrix;
int k, b; int k, b;
@ -1219,7 +1216,7 @@ static int Alias_BlendBoneData(galiasinfo_t *inf, framestate_t *fstate, float *r
memcpy(result+bone*12, lerp->pose[0]+bone*12, (endbone-bone)*12*sizeof(float)); memcpy(result+bone*12, lerp->pose[0]+bone*12, (endbone-bone)*12*sizeof(float));
else else
{ {
//set up the identity matrix //blend each influence
for (; bone < endbone; bone++) for (; bone < endbone; bone++)
{ {
pose = result + 12*bone; pose = result + 12*bone;
@ -1247,7 +1244,7 @@ static int Alias_BlendBoneData(galiasinfo_t *inf, framestate_t *fstate, float *r
only writes targetbuffer if needed. the return value is the only real buffer result. only writes targetbuffer if needed. the return value is the only real buffer result.
assumes that all blended types are the same. probably buggy, but meh. assumes that all blended types are the same. probably buggy, but meh.
*/ */
static const float *Alias_GetBoneInformation(galiasinfo_t *inf, const framestate_t *framestate, skeltype_t targettype, float *targetbuffer, float *targetbufferalt, size_t maxbufferbones) static const float *Alias_GetBoneInformation(galiasinfo_t *inf, const framestate_t *framestate, skeltype_t targettype, float *targetbuffer, float *targetbufferalt, size_t numbones, const galiasbone_t *boneinfo)
{ {
skellerps_t lerps[FS_COUNT], *lerp; skellerps_t lerps[FS_COUNT], *lerp;
size_t numgroups; size_t numgroups;
@ -1256,7 +1253,7 @@ static const float *Alias_GetBoneInformation(galiasinfo_t *inf, const framestate
lerps[0].skeltype = SKEL_IDENTITY; //just in case. lerps[0].skeltype = SKEL_IDENTITY; //just in case.
#ifdef SKELETALOBJECTS #ifdef SKELETALOBJECTS
if (framestate->bonestate && framestate->bonecount >= inf->numbones) if (framestate->bonestate && framestate->bonecount >= numbones)
{ {
lerps[0].skeltype = framestate->skeltype; lerps[0].skeltype = framestate->skeltype;
lerps[0].firstbone = 0; lerps[0].firstbone = 0;
@ -1270,13 +1267,18 @@ static const float *Alias_GetBoneInformation(galiasinfo_t *inf, const framestate
else else
#endif #endif
{ {
numgroups = Alias_FindRawSkelData(inf, framestate, lerps, 0, inf->numbones); numgroups = Alias_FindRawSkelData(inf, framestate, lerps, 0, numbones, boneinfo);
} }
//try to return data in-place. //try to return data in-place.
if (numgroups==1 && lerps[0].lerpcount == 1) if (numgroups==1 && lerps[0].lerpcount == 1)
{ {
ret = Alias_ConvertBoneData(lerps[0].skeltype, lerps[0].pose[0], min(lerps[0].endbone, inf->numbones), inf->ofsbones, targettype, targetbuffer, targetbufferalt, maxbufferbones); ret = Alias_ConvertBoneData(lerps[0].skeltype, lerps[0].pose[0], min(lerps[0].endbone, inf->numbones), inf->ofsbones, targettype, targetbuffer, targetbufferalt, numbones);
if (ret == lerps[0].needsfree[0])
{ //bum
memcpy(targetbuffer, ret, sizeof(float)*min(lerps[0].endbone, numbones)*12);
ret = targetbuffer;
}
BZ_Free(lerps[0].needsfree[0]); BZ_Free(lerps[0].needsfree[0]);
return ret; return ret;
} }
@ -1365,7 +1367,7 @@ static const float *Alias_GetBoneInformation(galiasinfo_t *inf, const framestate
} }
} }
return Alias_ConvertBoneData(lerps[0].skeltype, targetbuffer, inf->numbones, inf->ofsbones, targettype, targetbuffer, targetbufferalt, maxbufferbones); return Alias_ConvertBoneData(lerps[0].skeltype, targetbuffer, inf->numbones, inf->ofsbones, targettype, targetbuffer, targetbufferalt, numbones);
} }
static void Alias_BuildSkeletalMesh(mesh_t *mesh, framestate_t *framestate, galiasinfo_t *inf) static void Alias_BuildSkeletalMesh(mesh_t *mesh, framestate_t *framestate, galiasinfo_t *inf)
@ -1375,9 +1377,9 @@ static void Alias_BuildSkeletalMesh(mesh_t *mesh, framestate_t *framestate, gali
const float *morphweights; const float *morphweights;
if (meshcache.bonecachetype != SKEL_INVERSE_ABSOLUTE) if (meshcache.bonecachetype != SKEL_INVERSE_ABSOLUTE)
meshcache.usebonepose = Alias_GetBoneInformation(inf, framestate, meshcache.bonecachetype=SKEL_INVERSE_ABSOLUTE, meshcache.boneposebuffer1, meshcache.boneposebuffer2, MAX_BONES); meshcache.usebonepose = Alias_GetBoneInformation(inf, framestate, meshcache.bonecachetype=SKEL_INVERSE_ABSOLUTE, meshcache.boneposebuffer1, meshcache.boneposebuffer2, inf->numbones, NULL);
morphweights = inf->AnimateMorphs?inf->AnimateMorphs(inf, framestate):NULL; morphweights = inf->AnimateMorphs?inf->AnimateMorphs(inf, framestate, alloca(sizeof(*morphweights)*inf->nummorphs)):NULL;
if (morphweights) if (morphweights)
{ {
size_t m,v; size_t m,v;
@ -1820,6 +1822,7 @@ qboolean Alias_GAliasBuildMesh(mesh_t *mesh, vbo_t **vbop, galiasinfo_t *inf, in
{ {
//if we have skeletal xyz info, but no skeletal weights, then its a partial model that cannot possibly be animated. //if we have skeletal xyz info, but no skeletal weights, then its a partial model that cannot possibly be animated.
meshcache.usebonepose = NULL; meshcache.usebonepose = NULL;
meshcache.bonecachetype = -1;
mesh->xyz_array = inf->ofs_skel_xyz; mesh->xyz_array = inf->ofs_skel_xyz;
mesh->xyz2_array = NULL; mesh->xyz2_array = NULL;
mesh->normals_array = inf->ofs_skel_norm; mesh->normals_array = inf->ofs_skel_norm;
@ -1875,7 +1878,7 @@ qboolean Alias_GAliasBuildMesh(mesh_t *mesh, vbo_t **vbop, galiasinfo_t *inf, in
else else
{ {
if (meshcache.bonecachetype != SKEL_ABSOLUTE) if (meshcache.bonecachetype != SKEL_ABSOLUTE)
meshcache.usebonepose = Alias_GetBoneInformation(inf, &e->framestate, meshcache.bonecachetype=SKEL_ABSOLUTE, meshcache.boneposebuffer1, meshcache.boneposebuffer2, MAX_BONES); meshcache.usebonepose = Alias_GetBoneInformation(inf, &e->framestate, meshcache.bonecachetype=SKEL_ABSOLUTE, meshcache.boneposebuffer1, meshcache.boneposebuffer2, MAX_BONES, NULL);
#ifndef SERVERONLY #ifndef SERVERONLY
if (inf->shares_bones != surfnum && qrenderer) if (inf->shares_bones != surfnum && qrenderer)
Alias_DrawSkeletalBones(inf->ofsbones, (const float *)meshcache.usebonepose, inf->numbones, e->framestate.g[0].endbone); Alias_DrawSkeletalBones(inf->ofsbones, (const float *)meshcache.usebonepose, inf->numbones, e->framestate.g[0].endbone);
@ -1885,7 +1888,7 @@ qboolean Alias_GAliasBuildMesh(mesh_t *mesh, vbo_t **vbop, galiasinfo_t *inf, in
else else
{ {
if (meshcache.bonecachetype != SKEL_INVERSE_ABSOLUTE) if (meshcache.bonecachetype != SKEL_INVERSE_ABSOLUTE)
meshcache.usebonepose = Alias_GetBoneInformation(inf, &e->framestate, meshcache.bonecachetype=SKEL_INVERSE_ABSOLUTE, meshcache.boneposebuffer1, meshcache.boneposebuffer2, MAX_BONES); meshcache.usebonepose = Alias_GetBoneInformation(inf, &e->framestate, meshcache.bonecachetype=SKEL_INVERSE_ABSOLUTE, meshcache.boneposebuffer1, meshcache.boneposebuffer2, MAX_BONES, NULL);
//hardware bone animation //hardware bone animation
mesh->xyz_array = inf->ofs_skel_xyz; mesh->xyz_array = inf->ofs_skel_xyz;
@ -2632,7 +2635,7 @@ static qboolean Mod_Trace(model_t *model, int forcehullnum, const framestate_t *
if (curbonesurf != mod->shares_bones) if (curbonesurf != mod->shares_bones)
{ {
curbonesurf = mod->shares_bones; curbonesurf = mod->shares_bones;
bonepose = Alias_GetBoneInformation(mod, framestate, SKEL_INVERSE_ABSOLUTE, buffer, bufferalt, MAX_BONES); bonepose = Alias_GetBoneInformation(mod, framestate, SKEL_INVERSE_ABSOLUTE, buffer, bufferalt, MAX_BONES, NULL);
} }
posedata = alloca(mod->numverts*sizeof(vecV_t)); posedata = alloca(mod->numverts*sizeof(vecV_t));
Alias_TransformVerticies_V(bonepose, mod->numverts, mod->ofs_skel_idx[0], mod->ofs_skel_weight[0], mod->ofs_skel_xyz[0], posedata[0]); Alias_TransformVerticies_V(bonepose, mod->numverts, mod->ofs_skel_idx[0], mod->ofs_skel_weight[0], mod->ofs_skel_xyz[0], posedata[0]);
@ -3170,7 +3173,7 @@ static void Mod_GenerateMeshVBO(model_t *mod, galiasinfo_t *galias)
} }
} }
else else
Con_DPrintf("\"%s\":\"%s\" exceeds gpu bone limit and will be software-skinned - %i > %i\n", mod->name, galias->surfacename, k, sh_config.max_gpu_bones); Con_DPrintf(CON_WARNING"PERF: \"%s\":\"%s\" exceeds gpu bone limit and will be software-skinned - %i > %i\n", mod->name, galias->surfacename, k, sh_config.max_gpu_bones);
} }
if (galias->mappedbones) if (galias->mappedbones)
{ {
@ -3834,8 +3837,6 @@ static void Mod_FloodFillSkin( qbyte *skin, int skinwidth, int skinheight )
static void *Q1MDL_LoadSkins_GL (galiasinfo_t *galias, dmdl_t *pq1inmodel, model_t *loadmodel, daliasskintype_t *pskintype, uploadfmt_t skintranstype) static void *Q1MDL_LoadSkins_GL (galiasinfo_t *galias, dmdl_t *pq1inmodel, model_t *loadmodel, daliasskintype_t *pskintype, uploadfmt_t skintranstype)
{ {
skinframe_t *frames; skinframe_t *frames;
char skinname[MAX_QPATH];
char alttexpath[MAX_QPATH];
int i; int i;
int s, t; int s, t;
float sinter; float sinter;
@ -3843,8 +3844,6 @@ static void *Q1MDL_LoadSkins_GL (galiasinfo_t *galias, dmdl_t *pq1inmodel, model
daliasskininterval_t *intervals; daliasskininterval_t *intervals;
qbyte *data, *saved; qbyte *data, *saved;
galiasskin_t *outskin = galias->ofsskins; galiasskin_t *outskin = galias->ofsskins;
const char *slash;
unsigned int texflags;
s = pq1inmodel->skinwidth*pq1inmodel->skinheight; s = pq1inmodel->skinwidth*pq1inmodel->skinheight;
for (i = 0; i < pq1inmodel->numskins; i++) for (i = 0; i < pq1inmodel->numskins; i++)
@ -3857,37 +3856,15 @@ static void *Q1MDL_LoadSkins_GL (galiasinfo_t *galias, dmdl_t *pq1inmodel, model
//but only preload it if we have no replacement. //but only preload it if we have no replacement.
outskin->numframes=1; outskin->numframes=1;
if (1 || /*!TEXVALID(texture) ||*/ (loadmodel->engineflags & MDLF_NOTREPLACEMENTS))
{ //the actual texture gets loaded after the shader.
//we're not using 24bits
frames = ZG_Malloc(&loadmodel->memgroup, sizeof(*frames)+s); frames = ZG_Malloc(&loadmodel->memgroup, sizeof(*frames)+s);
saved = (qbyte*)(frames+1); saved = (qbyte*)(frames+1);
frames[0].texels = saved; frames[0].texels = saved;
memcpy(saved, pskintype+1, s); memcpy(saved, pskintype+1, s);
if (i == 0) //Vanilla bug: ONLY skin 0 is flood-filled (the vanilla code operates on a cached 'skin' variable that does NOT get updated between skins reflooding skin 0). We still don't like flood fills either. Hexen2 has the same issue. if (i == 0) //Vanilla bug: ONLY skin 0 is flood-filled (the vanilla code operates on a cached 'skin' variable that does NOT get updated between skins reflooding skin 0). We still don't like flood fills either. Hexen2 has the same issue.
Mod_FloodFillSkin(saved, outskin->skinwidth, outskin->skinheight); Mod_FloodFillSkin(saved, outskin->skinwidth, outskin->skinheight);
}
else
{
frames = ZG_Malloc(&loadmodel->memgroup, sizeof(*frames));
Q_snprintfz(skinname, sizeof(skinname), "%s_%i.lmp", slash, i);
frames[0].texnums.base = R_LoadReplacementTexture(skinname, alttexpath, texflags, frames[0].texels, outskin->skinwidth, outskin->skinheight, skintranstype);
if (r_fb_models.ival)
{
Q_snprintfz(skinname, sizeof(skinname), "%s_%i_luma.lmp", slash, i);
frames[0].texnums.fullbright = R_LoadReplacementTexture(skinname, alttexpath, texflags, frames[0].texels, outskin->skinwidth, outskin->skinheight, TF_TRANS8_FULLBRIGHT);
}
if (r_loadbumpmapping)
{
Q_snprintfz(skinname, sizeof(skinname), "%s_%i_norm.lmp", slash, i);
frames[0].texnums.bump = R_LoadReplacementTexture(skinname, alttexpath, texflags|IF_TRYBUMP|IF_NOSRGB, frames[0].texels, outskin->skinwidth, outskin->skinheight, TF_HEIGHT8PAL);
}
Q_snprintfz(skinname, sizeof(skinname), "%s_%i_shirt.lmp", slash, i);
frames[0].texnums.upperoverlay = R_LoadReplacementTexture(skinname, alttexpath, texflags, NULL, outskin->skinwidth, outskin->skinheight, TF_INVALID);
Q_snprintfz(skinname, sizeof(skinname), "%s_%i_pants.lmp", slash, i);
frames[0].texnums.loweroverlay = R_LoadReplacementTexture(skinname, alttexpath, texflags, NULL, outskin->skinwidth, outskin->skinheight, TF_INVALID);
}
Q_snprintfz(frames[0].shadername, sizeof(frames[0].shadername), "%s_%i.lmp", loadmodel->name, i); Q_snprintfz(frames[0].shadername, sizeof(frames[0].shadername), "%s_%i.lmp", loadmodel->name, i);
frames[0].shader = NULL; frames[0].shader = NULL;
frames[0].defaultshader = NULL; frames[0].defaultshader = NULL;
@ -5135,11 +5112,11 @@ int Mod_GetNumBones(model_t *model, qboolean allowtags)
return 0; return 0;
} }
int Mod_GetBoneRelations(model_t *model, int firstbone, int lastbone, framestate_t *fstate, float *result) int Mod_GetBoneRelations(model_t *model, int firstbone, int lastbone, const galiasbone_t *boneinfo, const framestate_t *fstate, float *result)
{ {
#ifdef SKELETALMODELS #ifdef SKELETALMODELS
if (model && model->type == mod_alias) if (model && model->type == mod_alias)
return Alias_BlendBoneData(Mod_Extradata(model), fstate, result, SKEL_RELATIVE, firstbone, lastbone); return Alias_BlendBoneData(Mod_Extradata(model), fstate, result, SKEL_RELATIVE, firstbone, lastbone, boneinfo);
#endif #endif
#ifdef HALFLIFEMODELS #ifdef HALFLIFEMODELS
if (model && model->type == mod_halflife) if (model && model->type == mod_halflife)
@ -5156,7 +5133,10 @@ galiasbone_t *Mod_GetBoneInfo(model_t *model, int *numbones)
if (!model || model->type != mod_alias) if (!model || model->type != mod_alias)
{
*numbones = 0;
return NULL; return NULL;
}
inf = Mod_Extradata(model); inf = Mod_Extradata(model);
@ -5252,7 +5232,7 @@ qboolean Mod_GetTag(model_t *model, int tagnum, framestate_t *fstate, float *res
} }
else //try getting the data from the frame state else //try getting the data from the frame state
{ {
numbones = Mod_GetBoneRelations(model, 0, tagnum+1, fstate, relatives); numbones = Mod_GetBoneRelations(model, 0, tagnum+1, NULL, fstate, relatives);
lerps = relatives; lerps = relatives;
} }
@ -5323,7 +5303,7 @@ qboolean Mod_GetTag(model_t *model, int tagnum, framestate_t *fstate, float *res
//try getting the data from the frame state //try getting the data from the frame state
if (!numbonegroups) if (!numbonegroups)
numbonegroups = Alias_FindRawSkelData(inf, fstate, lerps, 0, inf->numbones); numbonegroups = Alias_FindRawSkelData(inf, fstate, lerps, 0, inf->numbones, NULL);
//try base pose? //try base pose?
if (!numbonegroups && inf->baseframeofs) if (!numbonegroups && inf->baseframeofs)
@ -5677,7 +5657,7 @@ const char *Mod_FrameNameForNum(model_t *model, int surfaceidx, int num)
while(surfaceidx-->0 && inf) while(surfaceidx-->0 && inf)
inf = inf->nextsurf; inf = inf->nextsurf;
if (!inf || num >= inf->numanimations) if (!inf || (unsigned)num >= (unsigned)inf->numanimations)
return NULL; return NULL;
group = inf->ofsanimations; group = inf->ofsanimations;
return group[num].name; return group[num].name;

View file

@ -49,20 +49,27 @@ typedef struct galiasevent_s
char *data; char *data;
} galiasevent_t; } galiasevent_t;
typedef struct galiasrefpose_s
{
vec4_t quat;
vec3_t org;
vec3_t scale;
} galiasrefpose_t;
//a frame group (aka: animation) //a frame group (aka: animation)
typedef struct galiasanimation_s typedef struct galiasanimation_s
{ {
#ifdef SKELETALMODELS #ifdef SKELETALMODELS
skeltype_t skeltype; //for models with transforms, states that bones need to be transformed from their parent. skeltype_t skeltype; //for models with transforms, states that bones need to be transformed from their parent.
//this is actually bad, and can result in bones shortening as they interpolate. //this is actually bad, and can result in bones shortening as they interpolate.
float *(QDECL *GetRawBones)(const struct galiasinfo_s *mesh, const struct galiasanimation_s *a, float time, float *bonematrixstorage, int numbones); float *(QDECL *GetRawBones)(const struct galiasinfo_s *mesh, const struct galiasanimation_s *a, float time, float *bonematrixstorage, const struct galiasbone_s *boneinf, int numbones);
void *boneofs; //numposes*12*numbones void *boneofs; //numposes*12*numbones
#endif #endif
qboolean loop; qboolean loop;
int numposes; int numposes;
//float *poseendtime; //first starts at 0, anim duration is poseendtime[numposes-1] //float *poseendtime; //first starts at 0, anim duration is poseendtime[numposes-1]
float rate; //average framerate of animation. float rate; //average framerate of animation.
int action; int action; //-1 for none.
float actionweight; float actionweight;
#ifdef NONSKELETALMODELS #ifdef NONSKELETALMODELS
galiaspose_t *poseofs; galiaspose_t *poseofs;
@ -76,9 +83,15 @@ typedef struct galiasbone_s galiasbone_t;
struct galiasbone_s struct galiasbone_s
{ {
char name[64]; char name[64];
#if MAX_BONES>32767
int parent; int parent;
#else
short parent;
#endif
unsigned char group;
// float radius; // float radius;
float inverse[12]; float inverse[12];
galiasrefpose_t ref;
}; };
typedef struct typedef struct
@ -180,10 +193,10 @@ typedef struct galiasinfo_s
#ifdef SKELETALMODELS #ifdef SKELETALMODELS
boneidx_t *bonemap; //filled in automatically if our mesh has more gpu bones than we can support boneidx_t *bonemap; //filled in automatically if our mesh has more gpu bones than we can support
unsigned int mappedbones; unsigned int mappedbones; //number of private per-mesh bones.
unsigned int nummorphs; //extra data after the xyz/norm/stvect arrays unsigned int nummorphs; //extra data after the xyz/norm/stvect arrays
const float *(QDECL *AnimateMorphs)(const struct galiasinfo_s *surf, const framestate_t *framestate); const float *(QDECL *AnimateMorphs)(const struct galiasinfo_s *surf, const framestate_t *framestate, float *resultmorphs); //returns a float weight[nummorphs] array (base verts have an implicit weight of 1, so these are purely additive)
int meshrootbone; int meshrootbone; //unused by engine. for loader callbacks to (ab)use
float *baseframeofs; /*non-heirachical*/ float *baseframeofs; /*non-heirachical*/
int numbones; int numbones;
@ -246,6 +259,7 @@ typedef struct modplugfuncs_s
void (QDECL *VectorAngles)(const float *forward, const float *up, float *result, qboolean meshpitch); void (QDECL *VectorAngles)(const float *forward, const float *up, float *result, qboolean meshpitch);
void (QDECL *AngleVectors)(const vec3_t angles, vec3_t forward, vec3_t right, vec3_t up); void (QDECL *AngleVectors)(const vec3_t angles, vec3_t forward, vec3_t right, vec3_t up);
void (QDECL *GenMatrixPosQuat4Scale)(const vec3_t pos, const vec4_t quat, const vec3_t scale, float result[12]); void (QDECL *GenMatrixPosQuat4Scale)(const vec3_t pos, const vec4_t quat, const vec3_t scale, float result[12]);
void (QDECL *QuaternionSlerp)(const vec4_t p, vec4_t q, float t, vec4_t qt);
//bone stuff //bone stuff
void (QDECL *ForceConvertBoneData)(skeltype_t sourcetype, const float *sourcedata, size_t bonecount, galiasbone_t *bones, skeltype_t desttype, float *destbuffer, size_t destbonecount); void (QDECL *ForceConvertBoneData)(skeltype_t sourcetype, const float *sourcedata, size_t bonecount, galiasbone_t *bones, skeltype_t desttype, float *destbuffer, size_t destbonecount);
@ -267,13 +281,10 @@ typedef struct modplugfuncs_s
void (*RenderDynamicLightmaps) (struct msurface_s *surf); void (*RenderDynamicLightmaps) (struct msurface_s *surf);
entity_t *(*NewSceneEntity) (void); entity_t *(*NewSceneEntity) (void);
void (*EndSubmodelLoad)(struct model_s *submod, int modelloadstate); void (*EndSubmodelLoad)(struct model_s *submod, int modelloadstate);
#if sizeof_index_t==2 #define plugmodfuncs_name_idxpostfix "_IDX" STRINGIFY(sizeof_index_t)
#define plugmodfuncs_name "Models" #define plugmodfuncs_name "Models" plugmodfuncs_name_idxpostfix
#else
#define plugmodfuncs_name "Models_IDX" STRINGIFY(sizeof_index_t)
#endif
} plugmodfuncs_t; } plugmodfuncs_t;
#define MODPLUGFUNCS_VERSION 3 #define MODPLUGFUNCS_VERSION 4
#ifdef SKELETALMODELS #ifdef SKELETALMODELS
void Alias_TransformVerticies(float *bonepose, galisskeletaltransforms_t *weights, int numweights, vecV_t *xyzout, vec3_t *normout); void Alias_TransformVerticies(float *bonepose, galisskeletaltransforms_t *weights, int numweights, vecV_t *xyzout, vec3_t *normout);

View file

@ -1273,7 +1273,7 @@ int MSG_ReadSize16 (sizebuf_t *sb)
{ {
int solid = (((ssolid>>7) & 0x1F8) - 32+32768)<<16; /*up can be negative*/ int solid = (((ssolid>>7) & 0x1F8) - 32+32768)<<16; /*up can be negative*/
solid|= ((ssolid & 0x1F)<<3); solid|= ((ssolid & 0x1F)<<3);
solid|= ((ssolid & 0x3E0)<<10); solid|= ((ssolid & 0x3E0)<<6);
return solid; return solid;
} }
} }
@ -2192,6 +2192,20 @@ int MSG_ReadChar (void)
return c; return c;
} }
int MSG_PeekByte(void)
{
unsigned int msg_readcount;
if (msg_readmsg->packing!=SZ_RAWBYTES)
return -1;
msg_readcount = msg_readmsg->currentbit>>3;
if (msg_readcount+1 > msg_readmsg->cursize)
return -1;
return (unsigned char)msg_readmsg->data[msg_readcount];
}
int MSG_ReadByte (void) int MSG_ReadByte (void)
{ {
unsigned char c; unsigned char c;
@ -2625,6 +2639,7 @@ void MSGQW_ReadDeltaUsercmd (const usercmd_t *from, usercmd_t *move, int protove
} }
} }
#ifdef HAVE_SERVER
void MSGQ2_ReadDeltaUsercmd (client_t *cl, const usercmd_t *from, usercmd_t *move) void MSGQ2_ReadDeltaUsercmd (client_t *cl, const usercmd_t *from, usercmd_t *move)
{ {
int bits; int bits;
@ -2729,6 +2744,7 @@ void MSGQ2_ReadDeltaUsercmd (client_t *cl, const usercmd_t *from, usercmd_t *mov
else else
move->lightlevel = MSG_ReadByte (); move->lightlevel = MSG_ReadByte ();
} }
#endif
void MSG_ReadData (void *data, int len) void MSG_ReadData (void *data, int len)
{ {
@ -5671,7 +5687,11 @@ static void COM_Version_f (void)
Con_Printf("Renderers:"); Con_Printf("Renderers:");
#ifdef GLQUAKE #ifdef GLQUAKE
#ifdef GLESONLY #ifdef GLESONLY
#ifdef FTE_TARGET_WEB //shuld we be just asking the video code for a list?...
Con_Printf(" WebGL");
#else
Con_Printf(" OpenGLES"); Con_Printf(" OpenGLES");
#endif
#else #else
Con_Printf(" OpenGL"); Con_Printf(" OpenGL");
#endif #endif
@ -5711,6 +5731,10 @@ static void COM_Version_f (void)
Con_Printf("Compiled with Cygwin\n"); Con_Printf("Compiled with Cygwin\n");
#endif #endif
#ifdef FTE_TARGET_WEB
Con_Printf("Compiled with emscripten %i.%i.%i\n", __EMSCRIPTEN_major__, __EMSCRIPTEN_minor__, __EMSCRIPTEN_tiny__);
#endif
#ifdef __clang__ #ifdef __clang__
Con_Printf("Compiled with clang version: %i.%i.%i (%s)\n",__clang_major__, __clang_minor__, __clang_patchlevel__, __VERSION__); Con_Printf("Compiled with clang version: %i.%i.%i (%s)\n",__clang_major__, __clang_minor__, __clang_patchlevel__, __VERSION__);
#elif defined(__GNUC__) #elif defined(__GNUC__)
@ -5831,12 +5855,15 @@ static void COM_Version_f (void)
#if !defined(VOICECHAT) #if !defined(VOICECHAT)
Con_Printf(" disabled"); Con_Printf(" disabled");
#else #else
#ifdef HAVE_SPEEX
#ifdef SPEEX_STATIC #ifdef SPEEX_STATIC
Con_Printf(" speex"); Con_Printf(" speex");
Con_DPrintf("^h(static)"); Con_DPrintf("^h(static)");
#else #else
Con_Printf(" speex^h(dynamic)"); Con_Printf(" speex^h(dynamic)");
#endif #endif
#endif
#ifdef HAVE_OPUS
#ifdef OPUS_STATIC #ifdef OPUS_STATIC
Con_Printf(" opus"); Con_Printf(" opus");
Con_DPrintf("^h(static)"); Con_DPrintf("^h(static)");
@ -5844,15 +5871,20 @@ static void COM_Version_f (void)
Con_Printf(" opus^h(dynamic)"); Con_Printf(" opus^h(dynamic)");
#endif #endif
#endif #endif
#endif
Con_Printf("\n"); Con_Printf("\n");
Con_Printf("^3Audio Decoders:^7"); Con_Printf("^3Audio Decoders:^7");
#ifdef FTE_TARGET_WEB
Con_DPrintf(" javascript");
#endif
#ifndef AVAIL_OGGVORBIS #ifndef AVAIL_OGGVORBIS
Con_DPrintf(" ^h(disabled: Ogg Vorbis)^7"); Con_DPrintf(" ^h(disabled: Ogg Vorbis)^7");
#elif defined(LIBVORBISFILE_STATIC) #elif defined(LIBVORBISFILE_STATIC)
Con_Printf(" Ogg Vorbis"); Con_Printf(" Ogg-Vorbis");
Con_DPrintf("^h(static)");
#else #else
Con_Printf(" Ogg Vorbis^h(dynamic)"); Con_Printf(" Ogg-Vorbis^h(dynamic)");
#endif #endif
#if defined(AVAIL_MP3_ACM) #if defined(AVAIL_MP3_ACM)
Con_Printf(" mp3(system)"); Con_Printf(" mp3(system)");
@ -5893,7 +5925,12 @@ static void COM_Version_f (void)
Con_DPrintf(" ^h(disabled: freetype2)^7"); Con_DPrintf(" ^h(disabled: freetype2)^7");
#endif #endif
#ifdef AVAIL_OPENAL #ifdef AVAIL_OPENAL
Con_Printf(" openal^h(dynamic)"); #ifdef FTE_TARGET_WEB
Con_Printf(" WebAudio");
Con_DPrintf("^h(static)");
#else
Con_Printf(" OpenAL^h(dynamic)");
#endif
#else #else
Con_DPrintf(" ^h(disabled: openal)^7"); Con_DPrintf(" ^h(disabled: openal)^7");
#endif #endif
@ -5986,13 +6023,20 @@ static void COM_Version_f (void)
#ifdef FTPSERVER #ifdef FTPSERVER
Con_Printf(" FTPServer"); Con_Printf(" FTPServer");
#endif #endif
#ifdef HAVE_TCP #if (defined(SUPPORT_ICE)&&defined(HAVE_DTLS)) || defined(FTE_TARGET_WEB)
Con_Printf(" WebRTC");
#endif
#ifdef FTE_TARGET_WEB
Con_Printf(" WebSocket/WSS");
#else
#if defined(HAVE_TCP)
#ifdef TCPCONNECT #ifdef TCPCONNECT
Con_Printf(" TCPConnect"); Con_Printf(" TCPConnect");
#endif #endif
#else #else
Con_Printf(" ^h(disabled: TCP)"); Con_Printf(" ^h(disabled: TCP)");
#endif #endif
#endif
#ifdef HAVE_GNUTLS //on linux #ifdef HAVE_GNUTLS //on linux
Con_Printf(" GnuTLS"); Con_Printf(" GnuTLS");
#endif #endif
@ -6705,9 +6749,6 @@ void COM_Init (void)
//random should be random from the start... //random should be random from the start...
srand(time(0)); srand(time(0));
#ifdef MULTITHREAD
Sys_ThreadsInit();
#endif
#ifdef LOADERTHREAD #ifdef LOADERTHREAD
COM_InitWorkerThread(); COM_InitWorkerThread();
#endif #endif

View file

@ -31,7 +31,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#endif #endif
#define VK_NO_STDINT_H //we're handling this. please don't cause conflicts. grr. #define VK_NO_STDINT_H //we're handling this. please don't cause conflicts. grr.
#if __STDC_VERSION__ >= 199901L || defined(__GNUC__) #if __STDC_VERSION__ >= 199901L || defined(__GNUC__) || _MSC_VER >= 1600
//C99 has a stdint header which hopefully contains an intptr_t //C99 has a stdint header which hopefully contains an intptr_t
//its optional... but if its not in there then its unlikely you'll actually be able to get the engine to a stage where it *can* load anything //its optional... but if its not in there then its unlikely you'll actually be able to get the engine to a stage where it *can* load anything
#include <stdint.h> #include <stdint.h>
@ -43,6 +43,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#define quint32_t uint32_t #define quint32_t uint32_t
#define qint64_t int64_t #define qint64_t int64_t
#define quint64_t uint64_t #define quint64_t uint64_t
#define qintmax_t intmax_t
#define quintmax_t uintmax_t
#else #else
#define qint8_t signed char //be explicit with this one. #define qint8_t signed char //be explicit with this one.
#define quint8_t unsigned char #define quint8_t unsigned char
@ -85,6 +87,9 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#define quint64_t unsigned qint64_t #define quint64_t unsigned qint64_t
#endif #endif
#define qintmax_t qint64_t
#define quintmax_t quint64_t
#ifndef uint32_t #ifndef uint32_t
#define int8_t qint8_t #define int8_t qint8_t
#define uint8_t quint8_t #define uint8_t quint8_t
@ -96,6 +101,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#define uint64_t quint64_t #define uint64_t quint64_t
#define intptr_t qintptr_t #define intptr_t qintptr_t
#define uintptr_t quintptr_t #define uintptr_t quintptr_t
#define intmax_t qintmax_t
#define uintmax_t quintmax_t
#endif #endif
#endif #endif
@ -345,6 +352,8 @@ void MSG_WriteDir (sizebuf_t *sb, float dir[3]);
extern qboolean msg_badread; // set if a read goes beyond end of message extern qboolean msg_badread; // set if a read goes beyond end of message
extern struct netprim_s msg_nullnetprim; extern struct netprim_s msg_nullnetprim;
int MSG_PeekByte(void);
void MSG_BeginReading (sizebuf_t *sb, struct netprim_s prim); void MSG_BeginReading (sizebuf_t *sb, struct netprim_s prim);
void MSG_ChangePrimitives(struct netprim_s prim); void MSG_ChangePrimitives(struct netprim_s prim);
int MSG_GetReadCount(void); int MSG_GetReadCount(void);
@ -381,7 +390,6 @@ void MSGQ2_ReadDeltaUsercmd (struct client_s *cl, const struct usercmd_s *from,
void MSG_ReadData (void *data, int len); void MSG_ReadData (void *data, int len);
void MSG_ReadSkip (int len); void MSG_ReadSkip (int len);
int MSG_ReadSize16 (sizebuf_t *sb); int MSG_ReadSize16 (sizebuf_t *sb);
void MSG_WriteSize16 (sizebuf_t *sb, unsigned int sz); void MSG_WriteSize16 (sizebuf_t *sb, unsigned int sz);
void COM_DecodeSize(int solid, float *mins, float *maxs); void COM_DecodeSize(int solid, float *mins, float *maxs);
@ -568,6 +576,7 @@ typedef struct searchpath_s
char logicalpath[MAX_OSPATH]; //printable hunam-readable location of the package. generally includes a system path, including nested packages. char logicalpath[MAX_OSPATH]; //printable hunam-readable location of the package. generally includes a system path, including nested packages.
char purepath[256]; //server tracks the path used to load them so it can tell the client char purepath[256]; //server tracks the path used to load them so it can tell the client
char prefix[MAX_QPATH]; //prefix to add to each file within the archive. may also be ".." to mean ignore the top-level path. char prefix[MAX_QPATH]; //prefix to add to each file within the archive. may also be ".." to mean ignore the top-level path.
int crc_seed; //can skip some hashes if this is cached.
int crc_check; //client sorts packs according to this checksum int crc_check; //client sorts packs according to this checksum
int crc_reply; //client sends a different crc back to the server, for the paks it's actually loaded. int crc_reply; //client sends a different crc back to the server, for the paks it's actually loaded.
int orderkey; //used to check to see if the paths were actually changed or not. int orderkey; //used to check to see if the paths were actually changed or not.
@ -607,6 +616,7 @@ qboolean FS_GetLocMTime(flocation_t *location, time_t *modtime);
const char *FS_GetPackageDownloadFilename(flocation_t *loc); //returns only packages (or null) const char *FS_GetPackageDownloadFilename(flocation_t *loc); //returns only packages (or null)
const char *FS_GetRootPackagePath(flocation_t *loc); //favours packages, but falls back on gamedirs. const char *FS_GetRootPackagePath(flocation_t *loc); //favours packages, but falls back on gamedirs.
searchpath_t *FS_GetPackage(const char *package); //for fancy stuff that should probably have its own helper...
qboolean FS_GetPackageDownloadable(const char *package); qboolean FS_GetPackageDownloadable(const char *package);
char *FS_GetPackHashes(char *buffer, int buffersize, qboolean referencedonly); char *FS_GetPackHashes(char *buffer, int buffersize, qboolean referencedonly);
char *FS_GetPackNames(char *buffer, int buffersize, int referencedonly, qboolean ext); char *FS_GetPackNames(char *buffer, int buffersize, int referencedonly, qboolean ext);
@ -660,12 +670,12 @@ char *VFS_GETS(vfsfile_t *vf, char *buffer, size_t buflen);
void VARGS VFS_PRINTF(vfsfile_t *vf, const char *fmt, ...) LIKEPRINTF(2); void VARGS VFS_PRINTF(vfsfile_t *vf, const char *fmt, ...) LIKEPRINTF(2);
enum fs_relative{ 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. //note that many of theses paths can map to multiple system locations. FS_SystemPath/FS_DisplayPath 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_BINARYPATH, //where the 'exe' is located. we'll check here for dlls too.
FS_LIBRARYPATH, //for system dlls and stuff FS_LIBRARYPATH, //for system dlls and stuff
FS_ROOT, //./ (effectively -homedir if enabled, otherwise effectively -basedir arg) 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. FS_SYSTEM, //a system path. absolute paths are explicitly allowed and expected, but not required.
#define FS_RELATIVE_ISSPECIAL(r) ((r)<FS_GAME)
//after this point, all types must be relative to a gamedir //after this point, all types must be relative to a gamedir
FS_GAME, //standard search (not generally valid for writing/save/rename/delete/etc) FS_GAME, //standard search (not generally valid for writing/save/rename/delete/etc)
FS_GAMEONLY, //$gamedir/ FS_GAMEONLY, //$gamedir/
@ -676,6 +686,8 @@ enum fs_relative{
qboolean COM_WriteFile (const char *filename, enum fs_relative fsroot, const void *data, int len); qboolean COM_WriteFile (const char *filename, enum fs_relative fsroot, const void *data, int len);
char *FS_AbbreviateSize(char *buf, size_t bufsize, qofs_t fsize); //just formats a filesize into the buffer and returns it.
void FS_FlushFSHashWritten(const char *fname); void FS_FlushFSHashWritten(const char *fname);
void FS_FlushFSHashRemoved(const char *fname); void FS_FlushFSHashRemoved(const char *fname);
void FS_FlushFSHashFull(void); //too much/unknown changed... void FS_FlushFSHashFull(void); //too much/unknown changed...
@ -685,7 +697,9 @@ qboolean FS_Rename2(const char *oldf, const char *newf, enum fs_relative oldrela
qboolean FS_Remove(const char *fname, enum fs_relative relativeto); //0 on success, non-0 on error qboolean FS_Remove(const char *fname, enum fs_relative relativeto); //0 on success, non-0 on error
qboolean FS_RemoveTree(searchpathfuncs_t *pathhandle, const char *fname); qboolean FS_RemoveTree(searchpathfuncs_t *pathhandle, const char *fname);
qboolean FS_Copy(const char *source, const char *dest, enum fs_relative relativesource, enum fs_relative relativedest); qboolean FS_Copy(const char *source, const char *dest, enum fs_relative relativesource, enum fs_relative relativedest);
qboolean FS_NativePath(const char *fname, enum fs_relative relativeto, char *out, int outlen); //if you really need to fopen yourself //qboolean FS_NativePath(const char *fname, enum fs_relative relativeto, char *out, int outlen); //if you really need to fopen yourself
qboolean FS_SystemPath(const char *fname, enum fs_relative relativeto, char *out, int outlen); //if you really need to fopen yourself
qboolean FS_DisplayPath(const char *fname, enum fs_relative relativeto, char *out, int outlen); //retrieves a string for user display. prefixes may be masked for privacy.
qboolean FS_WriteFile (const char *filename, const void *data, int len, enum fs_relative relativeto); qboolean FS_WriteFile (const char *filename, const void *data, int len, enum fs_relative relativeto);
void *FS_MallocFile(const char *filename, enum fs_relative relativeto, qofs_t *filesize); void *FS_MallocFile(const char *filename, enum fs_relative relativeto, qofs_t *filesize);
vfsfile_t *QDECL FS_OpenVFS(const char *filename, const char *mode, enum fs_relative relativeto); vfsfile_t *QDECL FS_OpenVFS(const char *filename, const char *mode, enum fs_relative relativeto);
@ -964,6 +978,7 @@ extern hashfunc_t hash_sha2_384;
extern hashfunc_t hash_sha2_512; extern hashfunc_t hash_sha2_512;
extern hashfunc_t hash_crc16; //aka ccitt, required for qw's clc_move and various bits of dp compat extern hashfunc_t hash_crc16; //aka ccitt, required for qw's clc_move and various bits of dp compat
extern hashfunc_t hash_crc16_lower; extern hashfunc_t hash_crc16_lower;
#define hash_certfp hash_sha2_256 //This is the hash function we're using to compute *fp serverinfo. we can detect 1/2-256/2-512 by sizes, but we need consistency to avoid confusion in clientside things too.
unsigned int hashfunc_terminate_uint(const hashfunc_t *hash, void *context); //terminate, except returning the digest as a uint instead of a blob. folds the digest if longer than 4 bytes. unsigned int hashfunc_terminate_uint(const hashfunc_t *hash, void *context); //terminate, except returning the digest as a uint instead of a blob. folds the digest if longer than 4 bytes.
unsigned int CalcHashInt(const hashfunc_t *hash, const void *data, size_t datasize); unsigned int CalcHashInt(const hashfunc_t *hash, const void *data, size_t datasize);
size_t CalcHash(const hashfunc_t *hash, unsigned char *digest, size_t maxdigestsize, const unsigned char *data, size_t datasize); size_t CalcHash(const hashfunc_t *hash, unsigned char *digest, size_t maxdigestsize, const unsigned char *data, size_t datasize);
@ -1001,7 +1016,6 @@ typedef enum {
} logtype_t; } logtype_t;
void Log_String (logtype_t lognum, const char *s); void Log_String (logtype_t lognum, const char *s);
void Con_Log (const char *s); void Con_Log (const char *s);
void Log_Logfile_f (void);
void Log_Init(void); void Log_Init(void);
void Log_ShutDown(void); void Log_ShutDown(void);
#ifdef IPLOG #ifdef IPLOG
@ -1085,8 +1099,15 @@ json_t *JSON_FindChild(json_t *t, const char *child); //find a named child in an
json_t *JSON_GetIndexed(json_t *t, unsigned int idx); //find an indexed child in an array (or object, though slower) json_t *JSON_GetIndexed(json_t *t, unsigned int idx); //find an indexed child in an array (or object, though slower)
double JSON_ReadFloat(json_t *t, double fallback); //read a numeric value. double JSON_ReadFloat(json_t *t, double fallback); //read a numeric value.
size_t JSON_ReadBody(json_t *t, char *out, size_t outsize); //read a string value. size_t JSON_ReadBody(json_t *t, char *out, size_t outsize); //read a string value.
size_t JSON_GetCount(json_t *t);
//exotic fancy functions //exotic fancy functions
json_t *JSON_ParseNode(json_t *t, const char *namestart, const char *nameend, const char *json, int *jsonpos, int jsonlen); //fancy parsing. struct jsonparsectx_s
{
char const *const data;
const size_t size;
size_t pos;
};
json_t *JSON_ParseNode(json_t *t, const char *namestart, const char *nameend, struct jsonparsectx_s *ctx); //fancy parsing.
//helpers //helpers
json_t *JSON_FindIndexedChild(json_t *t, const char *child, unsigned int idx); //just a helper. json_t *JSON_FindIndexedChild(json_t *t, const char *child, unsigned int idx); //just a helper.
qboolean JSON_Equals(json_t *t, const char *child, const char *expected); //compares a bit faster. qboolean JSON_Equals(json_t *t, const char *child, const char *expected); //compares a bit faster.

View file

@ -126,10 +126,8 @@
#undef Q3SERVER //q3 server stuff. #undef Q3SERVER //q3 server stuff.
#undef HEXEN2 //runs hexen2 gamecode, supports hexen2 file formats. #undef HEXEN2 //runs hexen2 gamecode, supports hexen2 file formats.
#undef NQPROT //act as an nq client/server, with nq gamecode. #undef NQPROT //act as an nq client/server, with nq gamecode.
////#undef WEBSERVER //sv_ftp + sv_http cvars.
#undef WEBCLIENT //uri_get+any internal downloads etc #undef WEBCLIENT //uri_get+any internal downloads etc
#undef RUNTIMELIGHTING //automatic generation of .lit files #undef RUNTIMELIGHTING //automatic generation of .lit files
#undef R_XFLIP //old silly thing
#undef TEXTEDITOR //my funky text editor! its awesome! #undef TEXTEDITOR //my funky text editor! its awesome!
#undef TCPCONNECT //support for playing over tcp sockets, instead of just udp. compatible with qizmo. #undef TCPCONNECT //support for playing over tcp sockets, instead of just udp. compatible with qizmo.
#undef IRCCONNECT //lame support for routing game packets via irc server. not a good idea. #undef IRCCONNECT //lame support for routing game packets via irc server. not a good idea.

View file

@ -36,7 +36,6 @@
#define PSET_SCRIPT //scriptable particles (both fte's and importing effectinfo) #define PSET_SCRIPT //scriptable particles (both fte's and importing effectinfo)
#define RTLIGHTS #define RTLIGHTS
#define RUNTIMELIGHTING //automatic generation of .lit files #define RUNTIMELIGHTING //automatic generation of .lit files
#define R_XFLIP //old silly thing
//Extra misc features. //Extra misc features.
//#define CLIENTONLY // //#define CLIENTONLY //
@ -154,7 +153,7 @@
//#define IRCCONNECT //lame support for routing game packets via irc server. not a good idea. //#define IRCCONNECT //lame support for routing game packets via irc server. not a good idea.
#define SUPPORT_ICE //Internet Connectivity Establishment, for use by plugins to establish voice or game connections. #define SUPPORT_ICE //Internet Connectivity Establishment, for use by plugins to establish voice or game connections.
#define CL_MASTER //Clientside Server Browser functionality. #define CL_MASTER //Clientside Server Browser functionality.
#define PACKAGEMANAGER //Allows the user to enable/disable/download(with WEBCLIENT) packages and plugins. #define PACKAGEMANAGER //Allows the user to enable/disable/download(with WEBCLIENT) packages and plugins. Also handles map packages.
// Audio Drivers // Audio Drivers
#define AVAIL_OPENAL #define AVAIL_OPENAL
@ -191,23 +190,24 @@
////#define QTERM //qterm... adds a console command that allows running programs from within quake - bit like xterm. ////#define QTERM //qterm... adds a console command that allows running programs from within quake - bit like xterm.
//#define SVCHAT //ancient lame builtin to support NPC-style chat... //#define SVCHAT //ancient lame builtin to support NPC-style chat...
////#define SV_MASTER //Support running the server as a master server. Should probably not be used. ////#define SV_MASTER //Support running the server as a master server. Should probably not be used.
////#define WEBSERVER //outdated sv_http cvar. new stuff acts via sv_port_tcp instead (which also gives https).
////#define QUAKESPYAPI //define this if you want the engine to be usable via gamespy/quakespy, which has been dead for a long time now. forces the client to use a single port for all outgoing connections, which hurts reconnects. ////#define QUAKESPYAPI //define this if you want the engine to be usable via gamespy/quakespy, which has been dead for a long time now. forces the client to use a single port for all outgoing connections, which hurts reconnects.
#ifdef COMPILE_OPTS #ifdef COMPILE_OPTS //This is a block of hints for the makefile to decide which deps to link.
//things to configure qclib, which annoyingly doesn't include this file itself //things to configure qclib, which annoyingly doesn't include this file itself
//-DOMIT_QCC //disable the built-in qcc //-DOMIT_QCC //disable the built-in qcc
//-DSIMPLE_QCVM //disable qc debugging and 32bit opcodes //-DSIMPLE_QCVM //disable qc debugging and 32bit opcodes
#ifndef AVAIL_ZLIB #ifndef AVAIL_ZLIB
//-DNO_ZLIB //disable zlib //-DNO_ZLIB //disable zlib
#endif #endif
#ifndef FTE_TARGET_WEB
#ifdef AVAIL_PNGLIB #ifdef AVAIL_PNGLIB
-DLINK_PNG -DLINK_PNG
#endif #endif
#ifdef AVAIL_JPEGLIB #ifdef AVAIL_JPEGLIB
-DLINK_JPEG -DLINK_JPEG
#endif #endif
#endif
#if defined(PLUGINS) && (defined(Q3SERVER) || defined(Q3CLIENT)) #if defined(PLUGINS) && (defined(Q3SERVER) || defined(Q3CLIENT))
-DLINK_QUAKE3 //ask the makefile to bake the quake3 plugin into the engine itself. -DLINK_QUAKE3 //ask the makefile to bake the quake3 plugin into the engine itself.
#endif #endif
@ -217,15 +217,24 @@
#ifndef AVAIL_BOTLIB #ifndef AVAIL_BOTLIB
-DNO_BOTLIB //disable static botlib -DNO_BOTLIB //disable static botlib
#endif #endif
//-DNO_VORBISFILE //disable static vorbisfile #ifndef FTE_TARGET_WEB
-DLINK_VORBISFILE //disable static vorbisfile
#endif
//enable some staticaly linked libraries //enable some staticaly linked libraries
#ifndef FTE_TARGET_WEB
-DLINK_FREETYPE //international text requires international fonts. -DLINK_FREETYPE //international text requires international fonts.
#endif
#if defined(USE_INTERNAL_ODE) && !defined(ODE_DYNAMIC) #if defined(USE_INTERNAL_ODE) && !defined(ODE_DYNAMIC)
-DLINK_ODE -DLINK_ODE
#endif #endif
#if defined(PLUGINS)
//-DLINK_EZHUD //uncomment this line to statically link the ezhud plugin (eg for the web-rel target).
#endif
//-DLINK_OPENSSL //statically link our openssl plugin into the engine instead of being separate. NOTE: openssl<3 is a license no-go, 3 still requires gpl3 (2 prohits patent).
//-Os //optimise for size instead of speed. less cpu cache needed means that its sometimes faster anyway. //-Os //optimise for size instead of speed. less cpu cache needed means that its sometimes faster anyway.
#endif #endif

View file

@ -38,7 +38,6 @@
//#define PSET_SCRIPT //scriptable particles (both fte's and importing effectinfo) //#define PSET_SCRIPT //scriptable particles (both fte's and importing effectinfo)
//#define RTLIGHTS //#define RTLIGHTS
//#define RUNTIMELIGHTING //automatic generation of .lit files //#define RUNTIMELIGHTING //automatic generation of .lit files
//#define R_XFLIP //old silly thing
//Extra misc features. //Extra misc features.
//#define CLIENTONLY // //#define CLIENTONLY //
@ -193,7 +192,6 @@
////#define QTERM //qterm... adds a console command that allows running programs from within quake - bit like xterm. ////#define QTERM //qterm... adds a console command that allows running programs from within quake - bit like xterm.
//#define SVCHAT //ancient lame builtin to support NPC-style chat... //#define SVCHAT //ancient lame builtin to support NPC-style chat...
////#define SV_MASTER //Support running the server as a master server. Should probably not be used. ////#define SV_MASTER //Support running the server as a master server. Should probably not be used.
////#define WEBSERVER //outdated sv_http cvar. new stuff acts via sv_port_tcp instead (which also gives https).
////#define QUAKESPYAPI //define this if you want the engine to be usable via gamespy/quakespy, which has been dead for a long time now. forces the client to use a single port for all outgoing connections, which hurts reconnects. ////#define QUAKESPYAPI //define this if you want the engine to be usable via gamespy/quakespy, which has been dead for a long time now. forces the client to use a single port for all outgoing connections, which hurts reconnects.

View file

@ -36,7 +36,6 @@
#define PSET_SCRIPT //scriptable particles (both fte's and importing effectinfo) #define PSET_SCRIPT //scriptable particles (both fte's and importing effectinfo)
#define RTLIGHTS #define RTLIGHTS
//#define RUNTIMELIGHTING //automatic generation of .lit files //#define RUNTIMELIGHTING //automatic generation of .lit files
//#define R_XFLIP //old silly thing
//Extra misc features. //Extra misc features.
//#define CLIENTONLY // //#define CLIENTONLY //
@ -191,7 +190,6 @@
////#define QTERM //qterm... adds a console command that allows running programs from within quake - bit like xterm. ////#define QTERM //qterm... adds a console command that allows running programs from within quake - bit like xterm.
//#define SVCHAT //ancient lame builtin to support NPC-style chat... //#define SVCHAT //ancient lame builtin to support NPC-style chat...
////#define SV_MASTER //Support running the server as a master server. Should probably not be used. ////#define SV_MASTER //Support running the server as a master server. Should probably not be used.
////#define WEBSERVER //outdated sv_http cvar. new stuff acts via sv_port_tcp instead (which also gives https).
////#define QUAKESPYAPI //define this if you want the engine to be usable via gamespy/quakespy, which has been dead for a long time now. forces the client to use a single port for all outgoing connections, which hurts reconnects. ////#define QUAKESPYAPI //define this if you want the engine to be usable via gamespy/quakespy, which has been dead for a long time now. forces the client to use a single port for all outgoing connections, which hurts reconnects.

View file

@ -168,9 +168,7 @@
#undef Q3SERVER /* q3 server stuff */ #undef Q3SERVER /* q3 server stuff */
#undef HEXEN2 /* runs hexen2 gamecode, supports hexen2 file formats */ #undef HEXEN2 /* runs hexen2 gamecode, supports hexen2 file formats */
#undef NQPROT /* act as an nq client/server, with nq gamecode */ #undef NQPROT /* act as an nq client/server, with nq gamecode */
#undef WEBSERVER /* sv_ftp + sv_http cvars */
#undef RUNTIMELIGHTING /* automatic generation of .lit files */ #undef RUNTIMELIGHTING /* automatic generation of .lit files */
#undef R_XFLIP /* old silly thing */
#undef TEXTEDITOR /* because emacs */ #undef TEXTEDITOR /* because emacs */
#undef TCPCONNECT /* support for playing over tcp sockets, instead of just udp. compatible with qizmo */ #undef TCPCONNECT /* support for playing over tcp sockets, instead of just udp. compatible with qizmo */
#undef IRCCONNECT /* lame support for routing game packets via irc server. not a good idea */ #undef IRCCONNECT /* lame support for routing game packets via irc server. not a good idea */

View file

@ -95,6 +95,9 @@ extern conchar_t q3codemasks[MAXQ3COLOURS];
#define CON_WARNING "^&E0" #define CON_WARNING "^&E0"
#define CON_ERROR "^&C0" #define CON_ERROR "^&C0"
#define CON_NOTICE "^&-1" #define CON_NOTICE "^&-1"
#if defined(_DEBUG) || defined(FTE_TARGET_WEB)/*urgh...*/
#define CON_DEBUG CON_WARNING __FILE__":"STRINGIFY(__LINE__)" "
#endif
#define isextendedcode(x) ((x >= '0' && x <= '9') || (x >= 'A' && x <= 'F') || x == '-') #define isextendedcode(x) ((x >= '0' && x <= '9') || (x >= 'A' && x <= 'F') || x == '-')
#define ishexcode(x) ((x >= '0' && x <= '9') || (x >= 'A' && x <= 'F') || (x >= 'a' && x <= 'f')) #define ishexcode(x) ((x >= '0' && x <= '9') || (x >= 'A' && x <= 'F') || (x >= 'a' && x <= 'f'))
@ -245,7 +248,7 @@ void VARGS Con_Printf (const char *fmt, ...) LIKEPRINTF(1);
void VARGS Con_TPrintf (translation_t text, ...); void VARGS Con_TPrintf (translation_t text, ...);
void VARGS Con_DPrintf (const char *fmt, ...) LIKEPRINTF(1); //developer>=1, for stuff that's probably actually slightly useful void VARGS Con_DPrintf (const char *fmt, ...) LIKEPRINTF(1); //developer>=1, for stuff that's probably actually slightly useful
void VARGS Con_DLPrintf (int level, const char *fmt, ...) LIKEPRINTF(2); //developer>=2, for spammy stuff void VARGS Con_DLPrintf (int level, const char *fmt, ...) LIKEPRINTF(2); //developer>=2, for spammy stuff
void VARGS Con_ThrottlePrintf (float *timer, int developerlevel, const char *fmt, ...); //for spammed warnings, so they don't spam prints with every single frame/call. the timer arg should be a static local. void VARGS Con_ThrottlePrintf (float *timer, int developerlevel, const char *fmt, ...) LIKEPRINTF(3); //for spammed warnings, so they don't spam prints with every single frame/call. the timer arg should be a static local.
void VARGS Con_SafePrintf (const char *fmt, ...) LIKEPRINTF(1); void VARGS Con_SafePrintf (const char *fmt, ...) LIKEPRINTF(1);
void Con_Footerf(console_t *con, qboolean append, const char *fmt, ...) LIKEPRINTF(3); void Con_Footerf(console_t *con, qboolean append, const char *fmt, ...) LIKEPRINTF(3);
void Con_Clear_f (void); void Con_Clear_f (void);

View file

@ -474,7 +474,7 @@ showhelp:
else else
col = S_COLOR_YELLOW; //cvar is changed, but won't be saved to a config so w/e. col = S_COLOR_YELLOW; //cvar is changed, but won't be saved to a config so w/e.
if (cmd->flags & CVAR_NOUNSAFEEXPAND) if (cmd->flags & CVAR_NOUNSAFEEXPAND)
Con_Printf("^[%s%s\\type\\%s\\tip\\"S_COLOR_YELLOW"%s^]", col, cmd->name, cmd->name, cmd->description?cmd->description:""); //cvar is changed, but won't be saved to a config so w/e. Con_Printf("^[%s%s\\type\\%s\\tip\\<Current value is hidden>\n\n"S_COLOR_YELLOW"%s^]", col, cmd->name, cmd->name, cmd->description?cmd->description:""); //cvar is changed, but won't be saved to a config so w/e.
else else
Con_Printf("^[%s%s\\type\\%s %s\\tip\\Default: %s\nCurrent: %s\n\n"S_COLOR_YELLOW"%s^]", col, cmd->name, cmd->name,cmd->string, cmd->defaultstr,cmd->string, cmd->description?cmd->description:""); //cvar is changed, but won't be saved to a config so w/e. Con_Printf("^[%s%s\\type\\%s %s\\tip\\Default: %s\nCurrent: %s\n\n"S_COLOR_YELLOW"%s^]", col, cmd->name, cmd->name,cmd->string, cmd->defaultstr,cmd->string, cmd->description?cmd->description:""); //cvar is changed, but won't be saved to a config so w/e.
total++; total++;
@ -1066,6 +1066,10 @@ static cvar_t *Cvar_SetCore (cvar_t *var, const char *value, qboolean force)
} }
Z_Free (latch); // free the old value string Z_Free (latch); // free the old value string
#ifdef HAVE_SERVER
MSV_SendCvarChange(var);
#endif
} }
if (var->latched_string) //we may as well have this here. if (var->latched_string) //we may as well have this here.

File diff suppressed because it is too large Load diff

View file

@ -44,7 +44,7 @@ struct searchpathfuncs_s
void (QDECL *ReadFile)(searchpathfuncs_t *handle, flocation_t *loc, char *buffer); //reads the entire file in one go (size comes from loc, so make sure the loc is valid, this is for performance with compressed archives) void (QDECL *ReadFile)(searchpathfuncs_t *handle, flocation_t *loc, char *buffer); //reads the entire file in one go (size comes from loc, so make sure the loc is valid, this is for performance with compressed archives)
int (QDECL *EnumerateFiles)(searchpathfuncs_t *handle, const char *match, int (QDECL *func)(const char *fname, qofs_t fsize, time_t mtime, void *parm, searchpathfuncs_t *spath), void *parm); int (QDECL *EnumerateFiles)(searchpathfuncs_t *handle, const char *match, int (QDECL *func)(const char *fname, qofs_t fsize, time_t mtime, void *parm, searchpathfuncs_t *spath), void *parm);
int (QDECL *GeneratePureCRC) (searchpathfuncs_t *handle, int seed, int usepure); int (QDECL *GeneratePureCRC) (searchpathfuncs_t *handle, const int *seed);
vfsfile_t * (QDECL *OpenVFS)(searchpathfuncs_t *handle, flocation_t *loc, const char *mode); vfsfile_t * (QDECL *OpenVFS)(searchpathfuncs_t *handle, flocation_t *loc, const char *mode);
@ -73,6 +73,7 @@ void FS_UnRegisterFileSystemModule(void *module);
void FS_AddHashedPackage(searchpath_t **oldpaths, const char *parent_pure, const char *parent_logical, searchpath_t *search, unsigned int loadstuff, const char *pakpath, const char *qhash, const char *pakprefix, unsigned int packageflags); void FS_AddHashedPackage(searchpath_t **oldpaths, const char *parent_pure, const char *parent_logical, searchpath_t *search, unsigned int loadstuff, const char *pakpath, const char *qhash, const char *pakprefix, unsigned int packageflags);
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_LoadPackages(searchpath_t **oldpaths, const char *parent_pure, const char *parent_logical, searchpath_t *search, unsigned int loadstuff, int minpri, int maxpri);
qboolean PM_HandleRedirect(const char *package, char *url, size_t urlsize);
void PM_ManifestChanged(ftemanifest_t *man); void PM_ManifestChanged(ftemanifest_t *man);
void *PM_GeneratePackageFromMeta(vfsfile_t *file, char *fname, size_t fnamesize, enum fs_relative *fsroot); 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_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.
@ -85,7 +86,7 @@ unsigned int PM_MarkUpdates (void); //mark new/updated packages as needing insta
void PM_ApplyChanges(void); //for -install/-doinstall args void PM_ApplyChanges(void); //for -install/-doinstall args
qboolean PM_AreSourcesNew(qboolean doprompt); qboolean PM_AreSourcesNew(qboolean doprompt);
qboolean PM_FindUpdatedEngine(char *syspath, size_t syspathsize); //names the engine we should be running qboolean PM_FindUpdatedEngine(char *syspath, size_t syspathsize); //names the engine we should be running
void PM_AddManifestPackages(ftemanifest_t *man); void PM_AddManifestPackages(ftemanifest_t *man, qboolean mayapply);
void Menu_Download_Update(void); void Menu_Download_Update(void);
typedef struct typedef struct
@ -107,7 +108,7 @@ enum modsourcetype_e
MST_UNKNOWN, //forgot where it came from... MST_UNKNOWN, //forgot where it came from...
}; };
int FS_EnumerateKnownGames(qboolean (*callback)(void *usr, ftemanifest_t *man, enum modsourcetype_e sourcetype), void *usr); int FS_EnumerateKnownGames(qboolean (*callback)(void *usr, ftemanifest_t *man, enum modsourcetype_e sourcetype), void *usr, qboolean fixedbasedir);
struct modlist_s struct modlist_s
{ {

View file

@ -1214,7 +1214,7 @@ static int QDECL FSDZ_EnumerateFiles (searchpathfuncs_t *handle, const char *mat
return true; return true;
} }
static int QDECL FSDZ_GeneratePureCRC(searchpathfuncs_t *handle, int seed, int crctype) static int QDECL FSDZ_GeneratePureCRC(searchpathfuncs_t *handle, const int *seed)
{ {
dzarchive_t *pak = (void*)handle; dzarchive_t *pak = (void*)handle;
@ -1224,7 +1224,8 @@ static int QDECL FSDZ_GeneratePureCRC(searchpathfuncs_t *handle, int seed, int c
int i; int i;
filecrcs = BZ_Malloc((pak->numfiles+1)*sizeof(int)); filecrcs = BZ_Malloc((pak->numfiles+1)*sizeof(int));
filecrcs[numcrcs++] = seed; if (seed)
filecrcs[numcrcs++] = *seed;
for (i = 0; i < pak->numfiles; i++) for (i = 0; i < pak->numfiles; i++)
{ {
@ -1234,10 +1235,7 @@ static int QDECL FSDZ_GeneratePureCRC(searchpathfuncs_t *handle, int seed, int c
} }
} }
if (crctype)
result = CalcHashInt(&hash_md4, filecrcs, numcrcs*sizeof(int)); result = CalcHashInt(&hash_md4, filecrcs, numcrcs*sizeof(int));
else
result = CalcHashInt(&hash_md4, filecrcs+1, (numcrcs-1)*sizeof(int));
BZ_Free(filecrcs); BZ_Free(filecrcs);
return result; return result;

View file

@ -12,7 +12,7 @@ typedef struct
fsbucket_t bucket; fsbucket_t bucket;
char name[MAX_QPATH]; char name[MAX_QPATH];
int filepos, filelen; unsigned int filepos, filelen;
} mpackfile_t; } mpackfile_t;
typedef struct pack_s typedef struct pack_s
@ -24,7 +24,7 @@ typedef struct pack_s
void *mutex; void *mutex;
vfsfile_t *handle; vfsfile_t *handle;
unsigned int filepos; //the pos the subfiles left it at (to optimize calls to vfs_seek) qofs_t filepos; //the pos the subfiles left it at (to optimize calls to vfs_seek)
qatomic32_t references; //seeing as all vfiles from a pak file use the parent's vfsfile, we need to keep the parent open until all subfiles are closed. qatomic32_t references; //seeing as all vfiles from a pak file use the parent's vfsfile, we need to keep the parent open until all subfiles are closed.
} pack_t; } pack_t;
@ -34,27 +34,27 @@ typedef struct pack_s
typedef struct typedef struct
{ {
char name[56]; char name[56];
int filepos, filelen; unsigned int filepos, filelen;
} dpackfile_t; } dpackfile_t;
typedef struct typedef struct
{ {
int filepos, filelen; unsigned int filepos, filelen;
char name[8]; char name[8];
} dwadfile_t; } dwadfile_t;
typedef struct typedef struct
{ {
char id[4]; char id[4];
int dirofs; unsigned int dirofs;
int dirlen; unsigned int dirlen;
} dpackheader_t; } dpackheader_t;
typedef struct typedef struct
{ {
char id[4]; char id[4];
int dirlen; unsigned int dirlen;
int dirofs; unsigned int dirofs;
} dwadheader_t; } dwadheader_t;
#define MAX_FILES_IN_PACK 2048 #define MAX_FILES_IN_PACK 2048
@ -129,7 +129,7 @@ static unsigned int QDECL FSPAK_FLocate(searchpathfuncs_t *handle, flocation_t *
if (loc) if (loc)
{ {
loc->fhandle = pf; loc->fhandle = pf;
snprintf(loc->rawname, sizeof(loc->rawname), "%s", pak->descname); Q_snprintfz(loc->rawname, sizeof(loc->rawname), "%s", pak->descname);
loc->offset = pf->filepos; loc->offset = pf->filepos;
loc->len = pf->filelen; loc->len = pf->filelen;
} }
@ -155,7 +155,7 @@ static int QDECL FSPAK_EnumerateFiles (searchpathfuncs_t *handle, const char *ma
return true; return true;
} }
static int QDECL FSPAK_GeneratePureCRC(searchpathfuncs_t *handle, int seed, int crctype) static int QDECL FSPAK_GeneratePureCRC(searchpathfuncs_t *handle, const int *seed)
{ //this is really weak. :( { //this is really weak. :(
pack_t *pak = (void*)handle; pack_t *pak = (void*)handle;
@ -165,7 +165,8 @@ static int QDECL FSPAK_GeneratePureCRC(searchpathfuncs_t *handle, int seed, int
int i; int i;
filecrcs = BZ_Malloc((pak->numfiles+1)*sizeof(int)); filecrcs = BZ_Malloc((pak->numfiles+1)*sizeof(int));
filecrcs[numcrcs++] = seed; if (seed) //so exploiters can't cache it in purity replies.
filecrcs[numcrcs++] = *seed;
for (i = 0; i < pak->numfiles; i++) for (i = 0; i < pak->numfiles; i++)
{ {
@ -175,10 +176,7 @@ static int QDECL FSPAK_GeneratePureCRC(searchpathfuncs_t *handle, int seed, int
} }
} }
if (crctype)
result = CalcHashInt(&hash_md4, filecrcs, numcrcs*sizeof(int)); result = CalcHashInt(&hash_md4, filecrcs, numcrcs*sizeof(int));
else
result = CalcHashInt(&hash_md4, filecrcs+1, (numcrcs-1)*sizeof(int));
BZ_Free(filecrcs); BZ_Free(filecrcs);
return result; return result;
@ -307,7 +305,7 @@ of the list so they override previous pack files.
*/ */
searchpathfuncs_t *QDECL FSPAK_LoadArchive (vfsfile_t *file, searchpathfuncs_t *parent, const char *filename, const char *desc, const char *prefix) searchpathfuncs_t *QDECL FSPAK_LoadArchive (vfsfile_t *file, searchpathfuncs_t *parent, const char *filename, const char *desc, const char *prefix)
{ {
dpackheader_t header; dpackheader_t header = {};
int i; int i;
mpackfile_t *newfiles; mpackfile_t *newfiles;
int numpackfiles; int numpackfiles;
@ -327,7 +325,8 @@ searchpathfuncs_t *QDECL FSPAK_LoadArchive (vfsfile_t *file, searchpathfuncs_t *
if (read < sizeof(header) || header.id[0] != 'P' || header.id[1] != 'A' if (read < sizeof(header) || header.id[0] != 'P' || header.id[1] != 'A'
|| header.id[2] != 'C' || header.id[3] != 'K') || header.id[2] != 'C' || header.id[3] != 'K')
{ {
Con_Printf("%s is not a pak - %c%c%c%c\n", desc, header.id[0], header.id[1], header.id[2], header.id[3]); header.dirofs = 0;
Con_Printf("%s is not a pak - \"%s\"\n", desc, header.id);
return NULL; return NULL;
} }
header.dirofs = LittleLong (header.dirofs); header.dirofs = LittleLong (header.dirofs);
@ -484,7 +483,7 @@ newsection:
newfiles[i].filelen = 4; newfiles[i].filelen = 4;
break; break;
} }
if (!strncmp(filename, "gl_", 3) && ((filename[3] == 'e' && filename[5] == 'm') || !strncmp(filename+3, "map", 3))) if (!Q_strncmp(filename, "gl_", 3) && ((filename[3] == 'e' && filename[5] == 'm') || !strncmp(filename+3, "map", 3)))
{ //this is the start of a beutiful new map { //this is the start of a beutiful new map
section = 5; section = 5;
strcpy(sectionname, filename+3); strcpy(sectionname, filename+3);

View file

@ -5,7 +5,7 @@
#include <sys/stat.h> #include <sys/stat.h>
#endif #endif
#if !defined(FTE_TARGET_WEB) && (!defined(_WIN32) || defined(FTE_SDL)) #if !defined(FTE_TARGET_WEB) && (!defined(_WIN32) || defined(FTE_SDL) || defined(WEBSVONLY))
#ifdef WEBSVONLY #ifdef WEBSVONLY
#define Z_Free free #define Z_Free free

View file

@ -4,6 +4,36 @@
//#define AVAIL_BZLIB //#define AVAIL_BZLIB
//#define DYNAMIC_BZLIB //#define DYNAMIC_BZLIB
//supported ZIP features:
//zip64 for huge zips
//utf-8 encoding support (non-utf-8 is always ibm437)
//symlink flag
//compression mode: store
//compression mode: deflate (via zlib)
//compression mode: deflate64 (via zlib's unofficial extras)
//compression mode: bzip2 (via libbz2)
//bigendian cpus. everything misaligned.
//weak/original file encryption (set fs_zip_password)
//split archives (see specific notes)
//NOT supported:
//other compression modes
//strong/aes encryption
//if central dir is crypted/compressed, the archive will fail to open
//crc verification (if present then the local header must match the central dir, but the file data itself will not be verified in part because that'd require decoding the entire file upfront first)
//infozip utf-8 name override.
//other 'extra' fields.
//split archives:
//the central directory must be stored exclusively inside the initial zip/pk3 file.
//additional volumes will use the first letter of the extension and then at least two base-10 digits denoting the volume index (eg pak0.pk3 + pak0.p00 + pak0.p01).
//individual files must not be split over files (no rollover on truncation)
//fteqcc has a feature to generate versioned centraldir-only zips using external volumes for the actual data. This can be used to avoid downloading redundant data when connecting to servers using older revisions, but such revisions must be centrally managed.
#ifdef AVAIL_BZLIB #ifdef AVAIL_BZLIB
# include <bzlib.h> # include <bzlib.h>
# ifdef DYNAMIC_BZLIB # ifdef DYNAMIC_BZLIB
@ -47,14 +77,6 @@
# endif # endif
# include <zlib.h> # include <zlib.h>
# ifdef _MSC_VER
# ifdef _WIN64
# pragma comment(lib, MSVCLIBSPATH "zlib64.lib")
# else
# pragma comment(lib, MSVCLIBSPATH "zlib.lib")
# endif
# endif
# ifdef DYNAMIC_ZLIB # ifdef DYNAMIC_ZLIB
# define ZLIB_LOADED() (zlib_handle!=NULL) # define ZLIB_LOADED() (zlib_handle!=NULL)
void *zlib_handle; void *zlib_handle;
@ -801,7 +823,7 @@ static int QDECL FSZIP_EnumerateFiles (searchpathfuncs_t *handle, const char *ma
return true; return true;
} }
static int QDECL FSZIP_GeneratePureCRC(searchpathfuncs_t *handle, int seed, int crctype) static int QDECL FSZIP_GeneratePureCRC(searchpathfuncs_t *handle, const int *seed)
{ {
zipfile_t *zip = (void*)handle; zipfile_t *zip = (void*)handle;
@ -811,7 +833,8 @@ static int QDECL FSZIP_GeneratePureCRC(searchpathfuncs_t *handle, int seed, int
int i; int i;
filecrcs = BZ_Malloc((zip->numfiles+1)*sizeof(int)); filecrcs = BZ_Malloc((zip->numfiles+1)*sizeof(int));
filecrcs[numcrcs++] = seed; if (seed)
filecrcs[numcrcs++] = *seed;
for (i = 0; i < zip->numfiles; i++) for (i = 0; i < zip->numfiles; i++)
{ {
@ -819,10 +842,7 @@ static int QDECL FSZIP_GeneratePureCRC(searchpathfuncs_t *handle, int seed, int
filecrcs[numcrcs++] = zip->files[i].crc; filecrcs[numcrcs++] = zip->files[i].crc;
} }
if (crctype || numcrcs < 1)
result = CalcHashInt(&hash_md4, filecrcs, numcrcs*sizeof(int)); result = CalcHashInt(&hash_md4, filecrcs, numcrcs*sizeof(int));
else
result = CalcHashInt(&hash_md4, filecrcs+1, (numcrcs-1)*sizeof(int));
BZ_Free(filecrcs); BZ_Free(filecrcs);
return result; return result;
@ -1609,30 +1629,6 @@ static vfsfile_t *QDECL FSZIP_OpenVFS(searchpathfuncs_t *handle, flocation_t *lo
return (vfsfile_t*)vfsz; return (vfsfile_t*)vfsz;
} }
//ZIP features:
//zip64 for huge zips
//utf-8 encoding support (non-utf-8 is always ibm437)
//symlink flag
//compression mode: store
//compression mode: deflate (via zlib)
//bigendian cpus. everything misaligned.
//NOT supported:
//compression mode: deflate64
//other compression modes
//split archives
//if central dir is crypted/compressed, the archive will fail to open
//if a file is crypted/compressed, the file will (internally) be marked as corrupt
//crc verification
//infozip utf-8 name override.
//other 'extra' fields.
//split archives:
//central directory must be stored exclusively inside the initial zip.
//files on other parts will fail to load.
//individual files must not be split over files
struct zipinfo struct zipinfo
{ {
unsigned int thisdisk; //this disk number unsigned int thisdisk; //this disk number

View file

@ -231,18 +231,6 @@ static unsigned char q2_palette[256*3];
#endif #endif
/*
typedef struct q2csurface_s
{
char name[16];
int flags;
int value;
} q2csurface_t;
*/
typedef struct { typedef struct {
@ -1679,7 +1667,8 @@ static qboolean CModQ2_LoadFaces (model_t *mod, qbyte *mod_base, lump_t *l, lump
int style; int style;
struct decoupled_lm_info_s *decoupledlm; struct decoupled_lm_info_s *decoupledlm;
unsigned int dcsize, lofs; size_t dcsize;
unsigned int lofs;
unsigned short lmshift, lmscale; unsigned short lmshift, lmscale;
char buf[64]; char buf[64];
@ -4061,7 +4050,8 @@ static void CModQ3_LoadLighting (model_t *loadmodel, qbyte *mod_base, lump_t *l)
extern cvar_t gl_overbright; extern cvar_t gl_overbright;
float scale = (1<<(2-gl_overbright.ival)); float scale = (1<<(2-gl_overbright.ival));
loadmodel->lightmaps.fmt = LM_L8; loadmodel->lightmaps.fmt = LM_RGB8;
loadmodel->lightmaps.prebaked = PTI_RGB8;
//round up the samples, in case the last one is partial. //round up the samples, in case the last one is partial.
maps = ((samples+mapsize-1)&~(mapsize-1)) / mapsize; maps = ((samples+mapsize-1)&~(mapsize-1)) / mapsize;
@ -4079,8 +4069,6 @@ static void CModQ3_LoadLighting (model_t *loadmodel, qbyte *mod_base, lump_t *l)
if (!samples) if (!samples)
return; return;
loadmodel->lightmaps.fmt = LM_RGB8;
if (loadmodel->lightmaps.deluxemapping) if (loadmodel->lightmaps.deluxemapping)
maps /= 2; maps /= 2;
@ -5359,6 +5347,7 @@ static int CM_LeafArea (model_t *model, int leafnum)
//======================================================================= //=======================================================================
#define PlaneDiff(point,plane) (((plane)->type < 3 ? (point)[(plane)->type] : DotProduct((point), (plane)->normal)) - (plane)->dist) #define PlaneDiff(point,plane) (((plane)->type < 3 ? (point)[(plane)->type] : DotProduct((point), (plane)->normal)) - (plane)->dist)
#define PlaneDiffPush(point,plane,pushdist) (((plane)->type < 3 ? (point)[(plane)->type] : DotProduct((point), (plane)->normal)) - (plane)->dist - pushdist)
static mplane_t box_planes[6]; static mplane_t box_planes[6];
static model_t box_model; static model_t box_model;
@ -5660,10 +5649,14 @@ static unsigned int CM_NativeContents(struct model_s *model, int hulloverride, c
mleaf_t *leaf; mleaf_t *leaf;
q2cbrush_t *brush; q2cbrush_t *brush;
q2cbrushside_t *brushside; q2cbrushside_t *brushside;
vec3_t absmin, absmax, ofs;
int leaflist[64]; int leaflist[64];
k = CM_BoxLeafnums (model, point, point, leaflist, 64, NULL); VectorAdd(point, mins, absmin);
VectorAdd(point, maxs, absmax);
k = CM_BoxLeafnums (model, absmin, absmax, leaflist, 64, NULL);
contents = 0; contents = 0;
for (k--; k >= 0; k--) for (k--; k >= 0; k--)
@ -5680,10 +5673,18 @@ static unsigned int CM_NativeContents(struct model_s *model, int hulloverride, c
continue; continue;
} }
brushside = brush->brushside; brushside = brush->brushside;
for ( j = 0; j < brush->numsides; j++, brushside++ ) for ( j = 0; j < brush->numsides; j++, brushside++ )
{ {
if (PlaneDiff (point, brushside->plane) > 0 ) for (j=0 ; j<3 ; j++)
{
if (brushside->plane->normal[j] < 0)
ofs[j] = maxs[j];
else
ofs[j] = mins[j];
}
if (PlaneDiffPush (point, brushside->plane, DotProduct (ofs, brushside->plane->normal)) > 0)
break; break;
} }

View file

@ -1,5 +1,12 @@
#include "quakedef.h" #include "quakedef.h"
/*struct jsonparsectx_s
{
char const *const data;
const size_t size;
size_t pos;
};*/
//node destruction //node destruction
static void JSON_Orphan(json_t *t) static void JSON_Orphan(json_t *t)
{ {
@ -125,45 +132,45 @@ static json_t *JSON_CreateNode(json_t *parent, const char *namestart, const char
} }
//node parsing //node parsing
static void JSON_SkipWhite(const char *msg, int *pos, int max) static void JSON_SkipWhite(struct jsonparsectx_s *ctx)
{ {
while (*pos < max) while (ctx->pos < ctx->size)
{ {
//if its simple whitespace then keep skipping over it //if its simple whitespace then keep skipping over it
if (msg[*pos] == ' ' || if (ctx->data[ctx->pos] == ' ' ||
msg[*pos] == '\t' || ctx->data[ctx->pos] == '\t' ||
msg[*pos] == '\r' || ctx->data[ctx->pos] == '\r' ||
msg[*pos] == '\n' ) ctx->data[ctx->pos] == '\n' )
{ {
*pos+=1; ctx->pos+=1;
continue; continue;
} }
//BEGIN NON-STANDARD - Note that comments are NOT part of json, but people insist on using them anyway (c-style, like javascript). //BEGIN NON-STANDARD - Note that comments are NOT part of json, but people insist on using them anyway (c-style, like javascript).
else if (msg[*pos] == '/' && *pos+1 < max) else if (ctx->data[ctx->pos] == '/' && ctx->pos+1 < ctx->size)
{ {
if (msg[*pos+1] == '/') if (ctx->data[ctx->pos+1] == '/')
{ //C++ style single-line comments that continue till the next line break { //C++ style single-line comments that continue till the next line break
*pos+=2; ctx->pos+=2;
while (*pos < max) while (ctx->pos < ctx->size)
{ {
if (msg[*pos] == '\r' || msg[*pos] == '\n') if (ctx->data[ctx->pos] == '\r' || ctx->data[ctx->pos] == '\n')
break; //ends on first line break (the break is then whitespace will will be skipped naturally) break; //ends on first line break (the break is then whitespace will will be skipped naturally)
*pos+=1; //not yet ctx->pos+=1; //not yet
} }
continue; continue;
} }
else if (msg[*pos+1] == '*') else if (ctx->data[ctx->pos+1] == '*')
{ /*C style multi-line comment*/ { /*C style multi-line comment*/
*pos+=2; ctx->pos+=2;
while (*pos+1 < max) while (ctx->pos+1 < ctx->size)
{ {
if (msg[*pos] == '*' && msg[*pos+1] == '/') if (ctx->data[ctx->pos] == '*' && ctx->data[ctx->pos+1] == '/')
{ {
*pos+=2; //skip past the terminator ready for whitespace or trailing comments directly after ctx->pos+=2; //skip past the terminator ready for whitespace or trailing comments directly after
break; break;
} }
*pos+=1; //not yet ctx->pos+=1; //not yet
} }
continue; continue;
} }
@ -327,20 +334,20 @@ size_t JSON_ReadBody(json_t *t, char *out, size_t outsize)
return t->bodyend-t->bodystart; return t->bodyend-t->bodystart;
} }
static qboolean JSON_ParseString(char const*msg, int *pos, int max, char const**start, char const** end) static qboolean JSON_ParseString(struct jsonparsectx_s *ctx, char const**start, char const** end)
{ {
if (*pos < max && msg[*pos] == '\"') if (ctx->pos < ctx->size && ctx->data[ctx->pos] == '\"')
{ //quoted string { //quoted string
//FIXME: no handling of backslash followed by one of "\/bfnrtu //FIXME: no handling of backslash followed by one of "\/bfnrtu
*pos+=1; ctx->pos+=1;
*start = msg+*pos; *start = ctx->data+ctx->pos;
while (*pos < max) while (ctx->pos < ctx->size)
{ {
if (msg[*pos] == '\"') if (ctx->data[ctx->pos] == '\"')
break; break;
if (msg[*pos] == '\\') if (ctx->data[ctx->pos] == '\\')
{ //escapes are expanded elsewhere, we're just skipping over them here. { //escapes are expanded elsewhere, we're just skipping over them here.
switch(msg[*pos+1]) switch(ctx->data[ctx->pos+1])
{ {
case '\"': case '\"':
case '\\': case '\\':
@ -350,137 +357,137 @@ static qboolean JSON_ParseString(char const*msg, int *pos, int max, char const**
case 'n': case 'n':
case 'r': case 'r':
case 't': case 't':
*pos+=2; ctx->pos+=2;
break; break;
case 'u': case 'u':
*pos+=2; ctx->pos+=2;
//*pos+=4; //4 hex digits, not escapes so just wait till later before parsing them properly. //*pos+=4; //4 hex digits, not escapes so just wait till later before parsing them properly.
break; break;
default: default:
//unknown escape. will warn when actually reading it. //unknown escape. will warn when actually reading it.
*pos+=1; ctx->pos+=1;
break; break;
} }
} }
else else
*pos+=1; ctx->pos+=1;
} }
if (*pos < max && msg[*pos] == '\"') if (ctx->pos < ctx->size && ctx->data[ctx->pos] == '\"')
{ {
*end = msg+*pos; *end = ctx->data+ctx->pos;
*pos+=1; ctx->pos+=1;
return true; return true;
} }
} }
else else
{ //name { //name
*start = msg+*pos; *start = ctx->data+ctx->pos;
while (*pos < max while (ctx->pos < ctx->size
&& msg[*pos] != ' ' && ctx->data[ctx->pos] != ' '
&& msg[*pos] != '\t' && ctx->data[ctx->pos] != '\t'
&& msg[*pos] != '\r' && ctx->data[ctx->pos] != '\r'
&& msg[*pos] != '\n' && ctx->data[ctx->pos] != '\n'
&& msg[*pos] != ':' && ctx->data[ctx->pos] != ':'
&& msg[*pos] != ',' && ctx->data[ctx->pos] != ','
&& msg[*pos] != '}' && ctx->data[ctx->pos] != '}'
&& msg[*pos] != '{' && ctx->data[ctx->pos] != '{'
&& msg[*pos] != '[' && ctx->data[ctx->pos] != '['
&& msg[*pos] != ']') && ctx->data[ctx->pos] != ']')
{ {
*pos+=1; ctx->pos+=1;
} }
*end = msg+*pos; *end = ctx->data+ctx->pos;
if (*start != *end) if (*start != *end)
return true; return true;
} }
*end = *start; *end = *start;
return false; return false;
} }
json_t *JSON_ParseNode(json_t *t, const char *namestart, const char *nameend, const char *json, int *jsonpos, int jsonlen) json_t *JSON_ParseNode(json_t *t, const char *namestart, const char *nameend, struct jsonparsectx_s *ctx)
{ {
const char *childstart, *childend; const char *childstart, *childend;
JSON_SkipWhite(json, jsonpos, jsonlen); JSON_SkipWhite(ctx);
if (*jsonpos < jsonlen) if (ctx->pos < ctx->size)
{ {
if (json[*jsonpos] == '{') if (ctx->data[ctx->pos] == '{')
{ {
*jsonpos+=1; ctx->pos+=1;
JSON_SkipWhite(json, jsonpos, jsonlen); JSON_SkipWhite(ctx);
t = JSON_CreateNode(t, namestart, nameend, NULL, NULL, json_type_object); t = JSON_CreateNode(t, namestart, nameend, NULL, NULL, json_type_object);
while (*jsonpos < jsonlen && json[*jsonpos] == '\"') while (ctx->pos < ctx->size && ctx->data[ctx->pos] == '\"')
{ {
if (!JSON_ParseString(json, jsonpos, jsonlen, &childstart, &childend)) if (!JSON_ParseString(ctx, &childstart, &childend))
break; break;
JSON_SkipWhite(json, jsonpos, jsonlen); JSON_SkipWhite(ctx);
if (*jsonpos < jsonlen && json[*jsonpos] == ':') if (ctx->pos < ctx->size && ctx->data[ctx->pos] == ':')
{ {
*jsonpos+=1; ctx->pos+=1;
if (!JSON_ParseNode(t, childstart, childend, json, jsonpos, jsonlen)) if (!JSON_ParseNode(t, childstart, childend, ctx))
break; break;
} }
JSON_SkipWhite(json, jsonpos, jsonlen); JSON_SkipWhite(ctx);
if (*jsonpos < jsonlen && json[*jsonpos] == ',') if (ctx->pos < ctx->size && ctx->data[ctx->pos] == ',')
{ {
*jsonpos+=1; ctx->pos+=1;
JSON_SkipWhite(json, jsonpos, jsonlen); JSON_SkipWhite(ctx);
continue; continue;
} }
break; break;
} }
if (*jsonpos < jsonlen && json[*jsonpos] == '}') if (ctx->pos < ctx->size && ctx->data[ctx->pos] == '}')
{ {
*jsonpos+=1; ctx->pos+=1;
return t; return t;
} }
JSON_Destroy(t); JSON_Destroy(t);
} }
else if (json[*jsonpos] == '[') else if (ctx->data[ctx->pos] == '[')
{ {
char idxname[MAX_QPATH]; char idxname[MAX_QPATH];
unsigned int idx = 0; unsigned int idx = 0;
*jsonpos+=1; ctx->pos+=1;
JSON_SkipWhite(json, jsonpos, jsonlen); JSON_SkipWhite(ctx);
t = JSON_CreateNode(t, namestart, nameend, NULL, NULL, json_type_array); t = JSON_CreateNode(t, namestart, nameend, NULL, NULL, json_type_array);
for(;;) for(;;)
{ {
Q_snprintfz(idxname, sizeof(idxname), "%u", idx++); Q_snprintfz(idxname, sizeof(idxname), "%u", idx++);
if (!JSON_ParseNode(t, idxname, NULL, json, jsonpos, jsonlen)) if (!JSON_ParseNode(t, idxname, NULL, ctx))
break; break;
if (*jsonpos < jsonlen && json[*jsonpos] == ',') if (ctx->pos < ctx->size && ctx->data[ctx->pos] == ',')
{ {
*jsonpos+=1; ctx->pos+=1;
JSON_SkipWhite(json, jsonpos, jsonlen); JSON_SkipWhite(ctx);
continue; continue;
} }
break; break;
} }
JSON_SkipWhite(json, jsonpos, jsonlen); JSON_SkipWhite(ctx);
if (*jsonpos < jsonlen && json[*jsonpos] == ']') if (ctx->pos < ctx->size && ctx->data[ctx->pos] == ']')
{ {
*jsonpos+=1; ctx->pos+=1;
return t; return t;
} }
JSON_Destroy(t); JSON_Destroy(t);
} }
else else
{ {
if (json[*jsonpos] == '\"') if (ctx->data[ctx->pos] == '\"')
{ {
if (JSON_ParseString(json, jsonpos, jsonlen, &childstart, &childend)) if (JSON_ParseString(ctx, &childstart, &childend))
return JSON_CreateNode(t, namestart, nameend, childstart, childend, json_type_string); return JSON_CreateNode(t, namestart, nameend, childstart, childend, json_type_string);
} }
else else
{ {
if (JSON_ParseString(json, jsonpos, jsonlen, &childstart, &childend)) if (JSON_ParseString(ctx, &childstart, &childend))
{ {
if (childend-childstart == 4 && !strncasecmp(childstart, "true", 4)) if (childend-childstart == 4 && !strncasecmp(childstart, "true", 4))
return JSON_CreateNode(t, namestart, nameend, childstart, childend, json_type_true); return JSON_CreateNode(t, namestart, nameend, childstart, childend, json_type_true);
@ -498,11 +505,15 @@ json_t *JSON_ParseNode(json_t *t, const char *namestart, const char *nameend, co
} }
json_t *JSON_Parse(const char *json) json_t *JSON_Parse(const char *json)
{ {
size_t jsonlen = strlen(json); struct jsonparsectx_s ctx =
int pos = (json[0] == '\xef' && json[1] == '\xbb' && json[2] == '\xbf')?3:0; //skip a utf-8 bom, if present, to be a bit more permissive. {
json_t *n = JSON_ParseNode(NULL, NULL, NULL, json, &pos, jsonlen); json,
JSON_SkipWhite(json, &pos, jsonlen); strlen(json),
if (pos == jsonlen) (json[0] == '\xef' && json[1] == '\xbb' && json[2] == '\xbf')?3:0, //skip a utf-8 bom, if present, to be a bit more permissive.
};
json_t *n = JSON_ParseNode(NULL, NULL, NULL, &ctx);
JSON_SkipWhite(&ctx);
if (ctx.pos == ctx.size)
return n; return n;
JSON_Destroy(n); //trailing junk?... fail it. JSON_Destroy(n); //trailing junk?... fail it.
return NULL; return NULL;
@ -580,6 +591,14 @@ json_t *JSON_GetIndexed(json_t *t, unsigned int idx)
return NULL; return NULL;
} }
size_t JSON_GetCount(json_t *t)
{ //can't cope with deletions.
size_t count = 0;
while (JSON_GetIndexed(t, count))
count++;
return count;
}
//helpers... //helpers...
json_t *JSON_FindIndexedChild(json_t *t, const char *child, unsigned int idx) json_t *JSON_FindIndexedChild(json_t *t, const char *child, unsigned int idx)

View file

@ -265,8 +265,8 @@ static struct {
{"logrcon", " frags"}, {"logrcon", " frags"},
}; };
void Log_Logfile_f (void) static void Log_Logfile_f (void)
{ { //these legacy commands are just toggles. not args (other than the commandname to know which log type to toggle)
size_t logtype; size_t logtype;
const char *cmd = Cmd_Argv(0); const char *cmd = Cmd_Argv(0);
for (logtype = 0; logtype < countof(legacylog); logtype++) for (logtype = 0; logtype < countof(legacylog); logtype++)
@ -293,7 +293,7 @@ void Log_Logfile_f (void)
else else
f = va("%s.log", f); f = va("%s.log", f);
if (FS_NativePath(f, log_root, syspath, sizeof(syspath))) if (FS_DisplayPath(f, log_root, syspath, sizeof(syspath)))
Con_Printf("%s", va("Logging%s to %s\n", legacylog[logtype].desc, syspath)); Con_Printf("%s", va("Logging%s to %s\n", legacylog[logtype].desc, syspath));
else else
Con_Printf("%s", va("Logging%s to %s\n", legacylog[logtype].desc, f)); Con_Printf("%s", va("Logging%s to %s\n", legacylog[logtype].desc, f));
@ -301,44 +301,6 @@ void Log_Logfile_f (void)
} }
} }
/*
void SV_Fraglogfile_f (void)
{
char name[MAX_QPATH];
int i;
if (sv_fraglogfile)
{
Con_TPrintf ("Frag file logging off.\n");
VFS_CLOSE (sv_fraglogfile);
sv_fraglogfile = NULL;
return;
}
// find an unused name
for (i=0 ; i<1000 ; i++)
{
sprintf (name, "frag_%i.log", i);
sv_fraglogfile = FS_OpenVFS(name, "rb", FS_GAME);
if (!sv_fraglogfile)
{ // can't read it, so create this one
sv_fraglogfile = FS_OpenVFS (name, "wb", FS_GAME);
if (!sv_fraglogfile)
i=1000; // give error
break;
}
VFS_CLOSE (sv_fraglogfile);
}
if (i==1000)
{
Con_TPrintf ("Can't open any logfiles.\n");
sv_fraglogfile = NULL;
return;
}
Con_TPrintf ("Logging frags to %s.\n", name);
}
*/
#endif #endif
#ifdef IPLOG #ifdef IPLOG
@ -605,10 +567,10 @@ static int IPLog_Dump(const char *fname)
} }
static void IPLog_Dump_f(void) static void IPLog_Dump_f(void)
{ {
char native[MAX_OSPATH]; char displaypath[MAX_OSPATH];
const char *fname = Cmd_Argv(1); const char *fname = Cmd_Argv(1);
if (FS_NativePath(fname, FS_GAMEONLY, native, sizeof(native))) if (FS_DisplayPath(fname, FS_GAMEONLY, displaypath, sizeof(displaypath)))
Q_strncpyz(native, fname, sizeof(native)); Q_strncpyz(displaypath, fname, sizeof(displaypath));
IPLog_Merge_File(fname); //merge from the existing file, so that we're hopefully more robust if multiple processes are poking the same file. IPLog_Merge_File(fname); //merge from the existing file, so that we're hopefully more robust if multiple processes are poking the same file.
switch (IPLog_Dump(fname)) switch (IPLog_Dump(fname))
{ {
@ -617,7 +579,7 @@ static void IPLog_Dump_f(void)
break; break;
default: default:
case 1: case 1:
Con_Printf("wrote %s\n", native); Con_Printf("wrote %s\n", displaypath);
break; break;
case 2: case 2:
Con_Printf("nothing to write\n"); Con_Printf("nothing to write\n");
@ -814,7 +776,7 @@ qboolean CertLog_ConnectOkay(const char *hostname, void *cert, size_t certsize,
//(but do pin so we at least know when its MITMed after the fact) //(but do pin so we at least know when its MITMed after the fact)
Con_Printf(CON_WARNING"Auto-Pinning certificate for %s."CON_DEFAULT" ^[/seta %s 2^]+ for actual security.\n", hostname, net_enable_dtls.name); Con_Printf(CON_WARNING"Auto-Pinning certificate for %s."CON_DEFAULT" ^[/seta %s 2^]+ for actual security.\n", hostname, net_enable_dtls.name);
if (certsize) if (certsize)
Base64_EncodeBlockURI(digest, CalcHash(&hash_sha1, digest, sizeof(digest), cert, certsize), fp, sizeof(fp)); Base64_EncodeBlockURI(digest, CalcHash(&hash_certfp, digest, sizeof(digest), cert, certsize), fp, sizeof(fp));
else else
strcpy(fp, "<No Certificate>"); strcpy(fp, "<No Certificate>");
Con_Printf(S_COLOR_GRAY" fp: %s\n", fp); Con_Printf(S_COLOR_GRAY" fp: %s\n", fp);
@ -824,7 +786,7 @@ qboolean CertLog_ConnectOkay(const char *hostname, void *cert, size_t certsize,
else if (!l || l->certsize != certsize || memcmp(l->cert, cert, certsize) || (trusted && !l->trusted)) else if (!l || l->certsize != certsize || memcmp(l->cert, cert, certsize) || (trusted && !l->trusted))
{ //new or different { //new or different
if (certsize) if (certsize)
Base64_EncodeBlockURI(digest, CalcHash(&hash_sha1, digest, sizeof(digest), cert, certsize), fp, sizeof(fp)); Base64_EncodeBlockURI(digest, CalcHash(&hash_certfp, digest, sizeof(digest), cert, certsize), fp, sizeof(fp));
else else
strcpy(fp, "<No Certificate>"); strcpy(fp, "<No Certificate>");
if (qrenderer) if (qrenderer)
@ -1062,9 +1024,8 @@ void Log_Init(void)
Cvar_Register (&log_enable[i], CONLOGGROUP); Cvar_Register (&log_enable[i], CONLOGGROUP);
Cvar_Register (&log_name[i], CONLOGGROUP); Cvar_Register (&log_name[i], CONLOGGROUP);
log_newline[i] = true; log_newline[i] = true;
#ifdef IPLOG
Cmd_AddCommand(legacylog[i].commandname, IPLog_Merge_f); Cmd_AddCommand(legacylog[i].commandname, Log_Logfile_f);
#endif
} }
Cvar_Register (&log_dir_var, CONLOGGROUP); Cvar_Register (&log_dir_var, CONLOGGROUP);
Cvar_Register (&log_readable, CONLOGGROUP); Cvar_Register (&log_readable, CONLOGGROUP);

View file

@ -68,8 +68,6 @@ typedef enum {
NP_INVALID NP_INVALID
} netproto_t; } netproto_t;
typedef enum {NS_CLIENT, NS_SERVER} netsrc_t;
typedef struct netadr_s typedef struct netadr_s
{ {
netadrtype_t type; netadrtype_t type;
@ -91,7 +89,7 @@ typedef struct netadr_s
} irc; } irc;
#endif #endif
#ifdef SUPPORT_ICE #ifdef SUPPORT_ICE
char icename[16]; char icename[64];
#endif #endif
#ifdef HAVE_WEBSOCKCL #ifdef HAVE_WEBSOCKCL
char websocketurl[64]; char websocketurl[64];
@ -243,7 +241,7 @@ qboolean NET_RegisterCrypto(void *module, struct ftecrypto_s *driver);
#define OLD_AVG 0.99 // total = oldtotal*OLD_AVG + new*(1-OLD_AVG) #define OLD_AVG 0.99 // total = oldtotal*OLD_AVG + new*(1-OLD_AVG)
#define MAX_LATENT 32 //#define MAX_LATENT 32
#define MAX_ADR_SIZE 64 #define MAX_ADR_SIZE 64
typedef struct typedef struct
@ -256,12 +254,26 @@ typedef struct
float nqreliable_resendtime;//force nqreliable_allowed, thereby forcing a resend of anything n float nqreliable_resendtime;//force nqreliable_allowed, thereby forcing a resend of anything n
qbyte nqunreliableonly; //nq can't cope with certain reliables some times. if 2, we have a reliable that result in a block (that should be sent). if 1, we are blocking. if 0, we can send reliables freely. if 3, then we just want to ignore clc_moves qbyte nqunreliableonly; //nq can't cope with certain reliables some times. if 2, we have a reliable that result in a block (that should be sent). if 1, we are blocking. if 0, we can send reliables freely. if 3, then we just want to ignore clc_moves
#endif #endif
qboolean pext_fragmentation; //fte's packet fragmentation extension, to avoid issues with low mtus. unsigned int flags; //NCF_ bitmask
qboolean pext_stunaware; //prevent the two lead-bits of packets from being either 0(stun), so stray stun packets cannot mess things up for us. #define NCF_CLIENT (1u<<0) //clientside sends the qport.
#define NCF_SERVER (0u<<0) //serverside reads the qport.
#define NCF_FRAGABLE (1u<<1) //fte's packet fragmentation extension, to avoid issues with low mtus.
#define NCF_STUNAWARE (1u<<2) //prevent the two lead-bits of packets from being either 0(stun), so stray stun packets cannot mess things up for us.
struct netprim_s netprim; struct netprim_s netprim;
int mtu; //the path mtu, if known
int dupe; //how many times to dupe packets int dupe; //how many times to dupe packets
//Packetisation Layer Path MTU Discovery (PLPMTUD / RFC4821)
int mtu_cur; //the path mtu, if known
int mtu_min; //minimum mtu to drop to. lower values being abusive.
int mtu_max; //the size the user specified.
int mtu_resends; //number of times we had to resend a reliable.
int mtu_overhead; //extra slop vs a
int outgoing_mtu_probe; //sequence number that was a probe. if its acked we can send a new one straight away to grow fast. if its not acked, we back off.
int mtu_probes; //number of probes sent without success. give up if we get no growth.
double mtu_reprobetime; //send an extra mtu probe every 30ish secs to see if it grew
unsigned short sentsizes[64]; //to bump known mtu if an oversized packet got received.
int outgoing_sequence_last; //to detect gaps in outgoing sequences (servers get forced to match client's)
float last_received; // for timeouts float last_received; // for timeouts
// the statistics are cleared at each client begin, because // the statistics are cleared at each client begin, because
@ -270,13 +282,11 @@ typedef struct
float frame_rate; float frame_rate;
int drop_count; // dropped packets, cleared each level int drop_count; // dropped packets, cleared each level
int good_count; // cleared each level
int bytesin; int bytesin;
int bytesout; int bytesout;
netadr_t remote_address; netadr_t remote_address;
netsrc_t sock;
int qport; int qport;
int qportsize; int qportsize;
@ -307,8 +317,8 @@ typedef struct
qbyte reliable_buf[MAX_OVERALLMSGLEN]; // unacked reliable message qbyte reliable_buf[MAX_OVERALLMSGLEN]; // unacked reliable message
// time and size data to calculate bandwidth // time and size data to calculate bandwidth
int outgoing_size[MAX_LATENT]; // int outgoing_size[MAX_LATENT];
double outgoing_time[MAX_LATENT]; // double outgoing_time[MAX_LATENT];
struct huffman_s *compresstable; struct huffman_s *compresstable;
//nq servers must recieve truncated packets. //nq servers must recieve truncated packets.
@ -322,12 +332,13 @@ extern int net_drop; // packets dropped before this one
void Net_Master_Init(void); void Net_Master_Init(void);
void Netchan_Init (void); void Netchan_Init (void);
size_t Netchan_GetMaxUnreliable(netchan_t *chan);
int Netchan_Transmit (netchan_t *chan, int length, qbyte *data, int rate); int Netchan_Transmit (netchan_t *chan, int length, qbyte *data, int rate);
void Netchan_OutOfBand (netsrc_t sock, netadr_t *adr, int length, const qbyte *data); void Netchan_OutOfBand (unsigned int ncflags, netadr_t *adr, int length, const qbyte *data);
void VARGS Netchan_OutOfBandPrint (netsrc_t sock, netadr_t *adr, char *format, ...) LIKEPRINTF(3); void VARGS Netchan_OutOfBandPrint (unsigned int ncflags, netadr_t *adr, char *format, ...) LIKEPRINTF(3);
void VARGS Netchan_OutOfBandTPrintf (netsrc_t sock, netadr_t *adr, int language, translation_t text, ...); void VARGS Netchan_OutOfBandTPrintf (unsigned int ncflags, netadr_t *adr, int language, translation_t text, ...);
qboolean Netchan_Process (netchan_t *chan); qboolean Netchan_Process (netchan_t *chan);
void Netchan_Setup (netsrc_t sock, netchan_t *chan, netadr_t *adr, int qport); void Netchan_Setup (unsigned int ncflags, netchan_t *chan, netadr_t *adr, int qport, unsigned int mtu);
unsigned int Net_PextMask(unsigned int protover, qboolean fornq); unsigned int Net_PextMask(unsigned int protover, qboolean fornq);
extern cvar_t net_mtu; extern cvar_t net_mtu;

View file

@ -98,9 +98,10 @@ cvar_t pext_lerptime = CVARD("_pext_lerptime", "0", "RENAME ME WHEN STABLE. Send
cvar_t pext_infoblobs = CVARD("_pext_infoblobs", "0", "RENAME ME WHEN STABLE. Enables the use of very large infokeys containing potentially invalid chars. Note that the userinfo is still limited by sv_userinfo_bytelimit and sv_userinfo_keylimit."); cvar_t pext_infoblobs = CVARD("_pext_infoblobs", "0", "RENAME ME WHEN STABLE. Enables the use of very large infokeys containing potentially invalid chars. Note that the userinfo is still limited by sv_userinfo_bytelimit and sv_userinfo_keylimit.");
cvar_t pext_replacementdeltas = CVARD("pext_replacementdeltas", "1", "Enables the use of alternative nack-based entity deltas"); cvar_t pext_replacementdeltas = CVARD("pext_replacementdeltas", "1", "Enables the use of alternative nack-based entity deltas");
cvar_t pext_predinfo = CVARD("pext_predinfo", "1", "Enables some extra things to support prediction over NQ protocols."); cvar_t pext_predinfo = CVARD("pext_predinfo", "1", "Enables some extra things to support prediction over NQ protocols.");
extern cvar_t net_fakemtu;
#if defined(HAVE_CLIENT) && defined(HAVE_SERVER) #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) #define NET_SendPacket(c,s,d,t) NET_SendPacket((c&NCF_CLIENT)?cls.sockets:svs.sockets,s,d,t)
#elif defined(HAVE_SERVER) #elif defined(HAVE_SERVER)
#define NET_SendPacket(c,s,d,t) NET_SendPacket(svs.sockets,s,d,t) #define NET_SendPacket(c,s,d,t) NET_SendPacket(svs.sockets,s,d,t)
#else #else
@ -303,7 +304,7 @@ Netchan_OutOfBand
Sends an out-of-band datagram Sends an out-of-band datagram
================ ================
*/ */
void Netchan_OutOfBand (netsrc_t sock, netadr_t *adr, int length, const qbyte *data) void Netchan_OutOfBand (unsigned int ncflags, netadr_t *adr, int length, const qbyte *data)
{ {
sizebuf_t send; sizebuf_t send;
qbyte send_buf[MAX_QWMSGLEN + PACKET_HEADER]; qbyte send_buf[MAX_QWMSGLEN + PACKET_HEADER];
@ -322,7 +323,7 @@ void Netchan_OutOfBand (netsrc_t sock, netadr_t *adr, int length, const qbyte *d
#ifndef SERVERONLY #ifndef SERVERONLY
if (!cls.demoplayback) if (!cls.demoplayback)
#endif #endif
NET_SendPacket (sock, send.cursize, send.data, adr); NET_SendPacket (ncflags, send.cursize, send.data, adr);
} }
/* /*
@ -332,7 +333,7 @@ Netchan_OutOfBandPrint
Sends a text message in an out-of-band datagram Sends a text message in an out-of-band datagram
================ ================
*/ */
void VARGS Netchan_OutOfBandPrint (netsrc_t sock, netadr_t *adr, char *format, ...) void VARGS Netchan_OutOfBandPrint (unsigned int ncflags, netadr_t *adr, char *format, ...)
{ {
va_list argptr; va_list argptr;
static char string[8192]; // ??? why static? static char string[8192]; // ??? why static?
@ -342,10 +343,10 @@ void VARGS Netchan_OutOfBandPrint (netsrc_t sock, netadr_t *adr, char *format, .
va_end (argptr); va_end (argptr);
Netchan_OutOfBand (sock, adr, strlen(string), (qbyte *)string); Netchan_OutOfBand (ncflags, adr, strlen(string), (qbyte *)string);
} }
#ifndef CLIENTONLY #ifndef CLIENTONLY
void VARGS Netchan_OutOfBandTPrintf (netsrc_t sock, netadr_t *adr, int language, translation_t text, ...) void VARGS Netchan_OutOfBandTPrintf (unsigned int ncflags, netadr_t *adr, int language, translation_t text, ...)
{ {
va_list argptr; va_list argptr;
static char string[8192]; // ??? why static? static char string[8192]; // ??? why static?
@ -359,9 +360,44 @@ void VARGS Netchan_OutOfBandTPrintf (netsrc_t sock, netadr_t *adr, int language,
va_end (argptr); va_end (argptr);
Netchan_OutOfBand (sock, adr, strlen(string), (qbyte *)string); Netchan_OutOfBand (ncflags, adr, strlen(string), (qbyte *)string);
} }
#endif #endif
size_t Netchan_GetMaxUnreliable(netchan_t *chan)
{ //returns the maximum unreliable size we should be aiming for
#ifdef HAVE_SERVER
//debug prints
if (!(chan->flags&NCF_CLIENT) && chan == &svs.clients[0].netchan)
{
static int oldmtu;
if (oldmtu != chan->mtu_cur)
{
Con_DPrintf("Player0 MTU changed %i->%i\n", oldmtu, chan->mtu_cur);
oldmtu = chan->mtu_cur;
}
}
#endif
// if (chan->remote_address.type == NA_LOOPBACK)
// return ~0u; //our client supports big stuff. demos don't really care either so its fine.
if (chan->incoming_acknowledged > chan->last_reliable_sequence
&& chan->incoming_reliable_acknowledged != chan->reliable_sequence)
{ //we want to send a reliable...
if (chan->reliable_length) //one will be resent
return chan->mtu_cur - chan->reliable_length;
if (chan->message.cursize) //a new one will go out
return chan->mtu_cur - chan->message.cursize;
}
return chan->mtu_cur;
}
/* /*
============== ==============
Netchan_Setup Netchan_Setup
@ -369,11 +405,11 @@ Netchan_Setup
called to open a channel to a remote system called to open a channel to a remote system
============== ==============
*/ */
void Netchan_Setup (netsrc_t sock, netchan_t *chan, netadr_t *adr, int qport) void Netchan_Setup (unsigned int flags, netchan_t *chan, netadr_t *adr, int qport, unsigned int mtu)
{ {
memset (chan, 0, sizeof(*chan)); memset (chan, 0, sizeof(*chan));
chan->sock = sock; chan->flags = flags;
chan->remote_address = *adr; chan->remote_address = *adr;
chan->last_received = realtime; chan->last_received = realtime;
#ifdef NQPROT #ifdef NQPROT
@ -381,16 +417,63 @@ void Netchan_Setup (netsrc_t sock, netchan_t *chan, netadr_t *adr, int qport)
#endif #endif
chan->incoming_unreliable = -1; chan->incoming_unreliable = -1;
chan->message.data = chan->message_buf; if (flags&NCF_CLIENT)
chan->message.allowoverflow = true; chan->outgoing_sequence = 1; //so the first one doesn't get dropped.
chan->message.maxsize = MAX_QWMSGLEN;
chan->qport = qport;
if (adr->prot == NP_KEXLAN) if (adr->prot == NP_KEXLAN)
chan->qportsize = 0; chan->qportsize = 0;
else else
chan->qportsize = 2; chan->qportsize = 2;
chan->qport = qport;
//input mtu is the expected 'udp data size'
if (mtu<64 || mtu > 0xffff)
mtu = MAX_QWMSGLEN;
mtu = max(mtu, 508);
//compute the minimum mtu for the address type
if (adr->type == NA_IP)
chan->mtu_min = 508; //576 - 20..60(IP header) - 8(udp header)
else if (adr->type == NA_IPV6)
chan->mtu_min = 1200;
else if (adr->type == NA_IPX)
chan->mtu_min = 1450;
#ifdef SUPPORT_ICE
else if (adr->type == NA_ICE)
chan->mtu_min = 508; //match ipv4 here...
#endif
else if (adr->type == NA_LOOPBACK)
chan->mtu_min = 8192;
else
chan->mtu_min = 1450;
if (chan->mtu_min < 1024)
chan->mtu_min = 1200; //the internet is ethernet. if you can't deal with ipv6's limit then your connection is seriously dodgy. plus this lets us be a bit more agressive.
mtu -= PACKET_HEADER; //Note: This is not considered in vanilla - meaning net_mtu should be 1458 to match it (which will probably cause PTB issues).
if (flags&NCF_CLIENT)
mtu -= chan->qportsize;
if (flags&NCF_FRAGABLE)
mtu -= 2;
#ifdef SUPPORT_ICE
if (adr->type == NA_ICE)
mtu -= 48+12; //fixme: check if we're actually using the dtls and sctp layers or not.
else
#endif
{
if (adr->prot == NP_DTLS || adr->prot == NP_TLS)
mtu -= 48;
}
chan->mtu_min = min(mtu, chan->mtu_min);
chan->mtu_cur = mtu; //try to use the requested size to begin with. if it fails (probably on the realibles) then we'll allow it to drop
chan->mtu_max = mtu; //don't grow beyond what the user set. we're not aware of multiple paths nor are we tracking packetloss rates so if its partly wrong they'll get a load more loss, so don't be agressive here. let the user do that themselves!
chan->mtu_reprobetime = realtime; //try and grow the effective mtu after a bit (route may have changed)
chan->message.data = chan->message_buf;
chan->message.allowoverflow = true;
chan->message.maxsize = min(chan->mtu_cur, sizeof(chan->message_buf));
} }
@ -481,9 +564,8 @@ enum nqnc_packettype_e NQNetChan_Process(netchan_t *chan)
//note: its zlib rather than raw deflate (wasting a further 6 bytes...). //note: its zlib rather than raw deflate (wasting a further 6 bytes...).
net_message.cursize = ZLib_DecompressBuffer(net_message.data+8, net_message.cursize-8, tmp, 0xffff); net_message.cursize = ZLib_DecompressBuffer(net_message.data+8, net_message.cursize-8, tmp, 0xffff);
if (net_message.cursize < PACKET_HEADER) if (net_message.cursize < PACKET_HEADER)
#endif
{ {
if (chan->sock == NS_CLIENT) if (chan->flags&NCF_CLIENT)
{ //clients can just throw an error. the server will appear dead if we try to just ignore it. { //clients can just throw an error. the server will appear dead if we try to just ignore it.
Host_EndGame("QuakeEx netchan decompression error"); Host_EndGame("QuakeEx netchan decompression error");
return NQNC_IGNORED; return NQNC_IGNORED;
@ -499,6 +581,15 @@ enum nqnc_packettype_e NQNetChan_Process(netchan_t *chan)
MSG_BeginReading (&net_message, 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 header = LongSwap(MSG_ReadLong()); //re-read the now-decompressed copy of the header for the real flags
#else
if (chan->flags&NCF_CLIENT)
Host_EndGame("NQNetChan_Process: zlib not enabled at compile time");
else
Con_Printf("QuakeEx netchan decompression error");
net_message.data[8] = (chan->flags&NCF_CLIENT)?svc_disconnect:clc_disconnect;
net_message.cursize = 9;
return NQNC_RELIABLE;
#endif
} }
#endif #endif
if (net_message.cursize != (header & NETFLAG_LENGTH_MASK)) if (net_message.cursize != (header & NETFLAG_LENGTH_MASK))
@ -534,7 +625,7 @@ enum nqnc_packettype_e NQNetChan_Process(netchan_t *chan)
if (showpackets.value) if (showpackets.value)
Con_Printf ("in %s a=%i %i\n" Con_Printf ("in %s a=%i %i\n"
, chan->sock != NS_SERVER?"s2c":"c2s" , (chan->flags&NCF_CLIENT)?"s2c":"c2s"
, sequence , sequence
, 0); , 0);
@ -568,11 +659,10 @@ enum nqnc_packettype_e NQNetChan_Process(netchan_t *chan)
chan->last_received = realtime; chan->last_received = realtime;
chan->incoming_acknowledged++; chan->incoming_acknowledged++;
chan->good_count++;
if (showpackets.value) if (showpackets.value)
Con_Printf ("in %s u=%i %i\n" Con_Printf ("in %s u=%i %i\n"
, chan->sock != NS_SERVER?"s2c":"c2s" , (chan->flags&NCF_CLIENT)?"c2s":"s2c"
, chan->incoming_unreliable , chan->incoming_unreliable
, net_message.cursize); , net_message.cursize);
return NQNC_UNRELIABLE; return NQNC_UNRELIABLE;
@ -583,10 +673,10 @@ enum nqnc_packettype_e NQNetChan_Process(netchan_t *chan)
//always reply. a stale sequence probably means our ack got lost. //always reply. a stale sequence probably means our ack got lost.
runt[0] = BigLong(NETFLAG_ACK | 8); runt[0] = BigLong(NETFLAG_ACK | 8);
runt[1] = BigLong(sequence); runt[1] = BigLong(sequence);
NET_SendPacket (chan->sock, 8, runt, &net_from); NET_SendPacket (chan->flags, 8, runt, &net_from);
if (showpackets.value) if (showpackets.value)
Con_Printf ("out %s a=%i %i\n" Con_Printf ("out %s a=%i %i\n"
, chan->sock == NS_SERVER?"s2c":"c2s" , (chan->flags&NCF_CLIENT)?"c2s":"s2c"
, sequence , sequence
, 0); , 0);
@ -613,7 +703,7 @@ enum nqnc_packettype_e NQNetChan_Process(netchan_t *chan)
if (showpackets.value) if (showpackets.value)
Con_Printf ("in %s r=%i %i\n" Con_Printf ("in %s r=%i %i\n"
, chan->sock != NS_SERVER?"s2c":"c2s" , (chan->flags&NCF_CLIENT)?"s2c":"c2s"
, sequence , sequence
, net_message.cursize); , net_message.cursize);
return NQNC_RELIABLE; //we can read it now return NQNC_RELIABLE; //we can read it now
@ -648,12 +738,14 @@ int Netchan_Transmit (netchan_t *chan, int length, qbyte *data, int rate)
qbyte send_buf[MAX_OVERALLMSGLEN + PACKET_HEADER]; qbyte send_buf[MAX_OVERALLMSGLEN + PACKET_HEADER];
qboolean send_reliable; qboolean send_reliable;
char remote_adr[MAX_ADR_SIZE]; char remote_adr[MAX_ADR_SIZE];
unsigned w1, w2; unsigned w1, w2, mtuseq;
int i; int i;
neterr_t e; neterr_t e;
qboolean ismtuprobe;
int dupes = chan->dupe; int dupes = chan->dupe;
int availbytes = Netchan_CanBytes(chan, rate); int availbytes = Netchan_CanBytes(chan, rate);
int hsz;
availbytes = max(0, availbytes); //make sure it can't go negative (clientside doesn't check rate limits much) availbytes = max(0, availbytes); //make sure it can't go negative (clientside doesn't check rate limits much)
#ifdef NQPROT #ifdef NQPROT
@ -688,7 +780,7 @@ int Netchan_Transmit (netchan_t *chan, int length, qbyte *data, int rate)
MSG_WriteLong(&send, LongSwap(chan->reliable_sequence)); MSG_WriteLong(&send, LongSwap(chan->reliable_sequence));
//limit the payload length to nq's datagram max size. //limit the payload length to nq's datagram max size.
//relax the limitation if its reliable (ie: over tcp) where its assumed to have no real limit //relax the limitation if its reliable (ie: over tcp) where its assumed to have no real limit (beware tunnels)
if (i > MAX_NQDATAGRAM && !NET_AddrIsReliable(&chan->remote_address)) if (i > MAX_NQDATAGRAM && !NET_AddrIsReliable(&chan->remote_address))
i = MAX_NQDATAGRAM; i = MAX_NQDATAGRAM;
@ -711,13 +803,13 @@ int Netchan_Transmit (netchan_t *chan, int length, qbyte *data, int rate)
sentsize += send.cursize; sentsize += send.cursize;
if (showpackets.value) if (showpackets.value)
Con_Printf ("out %s r s=%i %i\n" Con_Printf ("out %s r s=%i %i\n"
, chan->sock == NS_SERVER?"s2c":"c2s" , (chan->flags&NCF_CLIENT)?"c2s":"s2c"
, chan->reliable_sequence , chan->reliable_sequence
, send.cursize); , send.cursize);
chan->nqreliable_allowed = false; chan->nqreliable_allowed = false;
chan->nqreliable_resendtime = realtime + 0.3; //resend reliables after 0.3 seconds. nq transports suck. chan->nqreliable_resendtime = realtime + 0.3; //resend reliables after 0.3 seconds. nq transports suck. FIXME: reduce to pingtime
if (NET_SendPacket (chan->sock, send.cursize, send.data, &chan->remote_address) == NETERR_SENT && ( if (NET_SendPacket (chan->flags, send.cursize, send.data, &chan->remote_address) == NETERR_SENT && (
NET_AddrIsReliable(&chan->remote_address) || chan->nqunreliableonly==3 )) NET_AddrIsReliable(&chan->remote_address) || chan->nqunreliableonly==3 ))
{ //if over tcp (or we're dropping the connection), everything is assumed to be reliable. pretend it got acked now. { //if over tcp (or we're dropping the connection), everything is assumed to be reliable. pretend it got acked now.
//if we get an ack later, then who cares. //if we get an ack later, then who cares.
@ -746,17 +838,17 @@ int Netchan_Transmit (netchan_t *chan, int length, qbyte *data, int rate)
*(int*)send_buf = BigLong(NETFLAG_UNRELIABLE | send.cursize); *(int*)send_buf = BigLong(NETFLAG_UNRELIABLE | send.cursize);
for (i = -1, e = NETERR_SENT; i < dupes && e == NETERR_SENT; i++) for (i = -1, e = NETERR_SENT; i < dupes && e == NETERR_SENT; i++)
e = NET_SendPacket (chan->sock, send.cursize, send.data, &chan->remote_address); e = NET_SendPacket (chan->flags, send.cursize, send.data, &chan->remote_address);
sentsize += send.cursize*i; sentsize += send.cursize*i;
if (e == NETERR_MTU && chan->mtu > 560) if (e == NETERR_MTU && chan->mtu_cur > chan->mtu_min)
{ { //yay, router works properly. unfortunately we don't know the exact size so keep retrying with a slightly smaller value until it goes through...
Con_Printf("Reducing MSS to %i\n", chan->mtu); chan->mtu_cur = max(chan->mtu_min, chan->mtu_cur-10);
chan->mtu -= 10; Con_Printf("Reducing MSS to %i\n", chan->mtu_cur);
} }
if (showpackets.value) if (showpackets.value)
Con_Printf ("out %s u=%i %i\n" Con_Printf ("out %s u=%i %i\n"
, chan->sock == NS_SERVER?"s2c":"c2s" , (chan->flags&NCF_CLIENT)?"c2s":"s2c"
, chan->outgoing_unreliable-1 , chan->outgoing_unreliable-1
, send.cursize); , send.cursize);
send.cursize = 0; send.cursize = 0;
@ -781,7 +873,7 @@ int Netchan_Transmit (netchan_t *chan, int length, qbyte *data, int rate)
if (chan->incoming_acknowledged > chan->last_reliable_sequence if (chan->incoming_acknowledged > chan->last_reliable_sequence
&& chan->incoming_reliable_acknowledged != chan->reliable_sequence) && chan->incoming_reliable_acknowledged != chan->reliable_sequence)
send_reliable = true; send_reliable = true; //they acked a later packet without acking the reliable...
// if the reliable transmit buffer is empty, copy the current message out // if the reliable transmit buffer is empty, copy the current message out
if (!chan->reliable_length && chan->message.cursize) if (!chan->reliable_length && chan->message.cursize)
@ -791,9 +883,11 @@ int Netchan_Transmit (netchan_t *chan, int length, qbyte *data, int rate)
chan->message.cursize = 0; chan->message.cursize = 0;
chan->reliable_sequence ^= 1; chan->reliable_sequence ^= 1;
send_reliable = true; send_reliable = true;
chan->mtu_resends=0;
} }
if (send_reliable && chan->remote_address.prot == NP_KEXLAN) if (send_reliable && chan->remote_address.prot == NP_KEXLAN) //FIXME: use with webrtc too - sctp can avoid the round-trip delay.
#ifndef SERVERONLY #ifndef SERVERONLY
if (!cls.demoplayback) if (!cls.demoplayback)
#endif #endif
@ -801,14 +895,14 @@ int Netchan_Transmit (netchan_t *chan, int length, qbyte *data, int rate)
if (chan->reliable_length) if (chan->reliable_length)
{ {
send.data = send_buf; send.data = send_buf;
send.maxsize = (chan->mtu?chan->mtu:MAX_QWMSGLEN) + PACKET_HEADER; send.maxsize = sizeof(send_buf);
send.cursize = 0; send.cursize = 0;
MSG_WriteLong (&send, 1u<<31); MSG_WriteLong (&send, 1u<<31);
MSG_WriteLong (&send, 1u<<31); MSG_WriteLong (&send, 1u<<31);
SZ_Write (&send, chan->reliable_buf, chan->reliable_length); SZ_Write (&send, chan->reliable_buf, chan->reliable_length);
if (NETERR_SENT == NET_SendPacket (chan->sock, send.cursize, send.data, &chan->remote_address)) if (NETERR_SENT == NET_SendPacket (chan->flags, send.cursize, send.data, &chan->remote_address))
chan->reliable_length = 0; //the lower layer will handle any retransmission for us. chan->reliable_length = 0; //the lower layer will handle any retransmission for us.
} }
send_reliable = 0; send_reliable = 0;
@ -817,13 +911,18 @@ int Netchan_Transmit (netchan_t *chan, int length, qbyte *data, int rate)
// write the packet header // write the packet header
send.data = send_buf; send.data = send_buf;
send.maxsize = (chan->mtu?chan->mtu:MAX_QWMSGLEN) + PACKET_HEADER; send.maxsize = PACKET_HEADER + ((chan->flags&NCF_CLIENT)?chan->qportsize:0) + ((chan->flags&NCF_FRAGABLE)?2:0);
send.maxsize += chan->mtu_cur;
send.cursize = 0; send.cursize = 0;
mtuseq = chan->outgoing_sequence&(countof(chan->sentsizes)-1);
for (; (chan->outgoing_sequence_last&(countof(chan->sentsizes)-1)) != mtuseq; chan->outgoing_sequence_last++)
chan->sentsizes[chan->outgoing_sequence_last&(countof(chan->sentsizes)-1)] = 0; //lost c2s or something, gaps now.
w1 = chan->outgoing_sequence | (send_reliable<<31); w1 = chan->outgoing_sequence | (send_reliable<<31);
w2 = chan->incoming_sequence | (chan->incoming_reliable_sequence<<31); w2 = chan->incoming_sequence | (chan->incoming_reliable_sequence<<31);
if (chan->pext_stunaware) if (chan->flags&NCF_STUNAWARE)
{ {
w1 = BigLong(w1+ANTISTUNBIAS); w1 = BigLong(w1+ANTISTUNBIAS);
w2 = BigLong(w2); w2 = BigLong(w2);
@ -833,23 +932,26 @@ int Netchan_Transmit (netchan_t *chan, int length, qbyte *data, int rate)
MSG_WriteLong (&send, w1); MSG_WriteLong (&send, w1);
MSG_WriteLong (&send, w2); MSG_WriteLong (&send, w2);
hsz = 8;
// send the qport if we are a client // send the qport if we are a client
#ifndef SERVERONLY #ifndef SERVERONLY
if (chan->sock == NS_CLIENT) if (chan->flags&NCF_CLIENT)
{ {
if (chan->qportsize == 2) if (chan->qportsize == 2)
MSG_WriteShort (&send, chan->qport); MSG_WriteShort (&send, chan->qport);
else if (chan->qportsize == 1) else if (chan->qportsize == 1)
MSG_WriteByte (&send, chan->qport&0xff); MSG_WriteByte (&send, chan->qport&0xff);
hsz += chan->qportsize;
} }
#endif #endif
if (chan->pext_fragmentation) if (chan->flags&NCF_FRAGABLE)
{ {
//allow the max size to be bigger, sending everything available //allow the max size to be bigger, sending everything available
send.maxsize = MAX_OVERALLMSGLEN + PACKET_HEADER; send.maxsize = MAX_OVERALLMSGLEN-100;
MSG_WriteShort(&send, 0); MSG_WriteShort(&send, 0);
hsz += 2;
} }
// copy the reliable message to the packet first // copy the reliable message to the packet first
@ -868,22 +970,70 @@ int Netchan_Transmit (netchan_t *chan, int length, qbyte *data, int rate)
} }
SZ_Write (&send, chan->reliable_buf, chan->reliable_length); SZ_Write (&send, chan->reliable_buf, chan->reliable_length);
chan->last_reliable_sequence = chan->outgoing_sequence; chan->last_reliable_sequence = chan->outgoing_sequence;
if (chan->mtu_resends > 5)
{ //getting blackholed?
if (chan->mtu_cur > chan->mtu_min)
{ //reset the mtu, and re-enable probes to get it back up to something usable.
chan->mtu_cur = chan->mtu_min;
// chan->mtu_cur = max(chan->mtu_min, min(send.cursize, chan->mtu_cur-16));
Con_DPrintf("Reliables Blackholed? Reducing MSS to %i\n", chan->mtu_cur);
chan->mtu_probes = 0; //and try and grow it again.
}
//chan->mtu_resends = 0;
}
chan->mtu_resends++;
}
if (chan->outgoing_sequence - chan->incoming_acknowledged > 128 && chan->mtu_cur > chan->mtu_min)
{
chan->mtu_cur = chan->mtu_min;
// chan->mtu_cur = max(chan->mtu_min, min(send.cursize, chan->mtu_cur-16));
Con_DPrintf("MTU blackhole? Reducing MSS to %i\n", chan->mtu_cur);
chan->mtu_probes = 0; //and try and grow it again.
} }
// add the unreliable part if space is available // add the unreliable part if space is available
if (send.maxsize - send.cursize >= length) if (send.maxsize - send.cursize >= length)
SZ_Write (&send, data, length); SZ_Write (&send, data, length);
ismtuprobe = false;
if (chan->mtu_reprobetime < realtime)
{
chan->mtu_probes = min(chan->mtu_probes,4);
chan->mtu_reprobetime = realtime + 30;
}
if (!send_reliable/*reliables depend on round trip times, don't risk losing them*/ &&
chan->incoming_acknowledged >= chan->outgoing_mtu_probe+chan->mtu_probes/*not still waiting for one, slow down a bit if they're dropping.*/ &&
chan->mtu_cur < chan->mtu_max && chan->mtu_probes < 5/*give up if its just not growing*/)
{
int targsize = min(chan->mtu_max, chan->mtu_cur+16);
int padsize = (hsz+targsize)-send.cursize;
if (padsize > 0 && targsize <= send.maxsize)
{
if (chan->flags&NCF_CLIENT)
Q_memset (SZ_GetSpace(&send,padsize),clc_nop,padsize);
else
Q_memset (SZ_GetSpace(&send,padsize),svc_nop,padsize);
ismtuprobe = true; //don't do our fragmentation stuff.
chan->mtu_probes++;
chan->outgoing_mtu_probe = chan->outgoing_sequence;
chan->mtu_reprobetime = realtime + 30;
Con_DPrintf("Sending mtu probe\n");
}
}
// send the datagram // send the datagram
i = chan->outgoing_sequence & (MAX_LATENT-1); // i = chan->outgoing_sequence & (MAX_LATENT-1);
chan->outgoing_size[i] = send.cursize; // chan->outgoing_size[i] = send.cursize;
chan->outgoing_time[i] = realtime; // chan->outgoing_time[i] = realtime;
#ifdef HUFFNETWORK #ifdef HUFFNETWORK
if (chan->compresstable) if (chan->compresstable)
{ {
//int oldsize = send.cursize; //int oldsize = send.cursize;
Huff_CompressPacket(chan->compresstable, &send, 8 + ((chan->sock == NS_CLIENT)?2:0) + (chan->pext_fragmentation?2:0)); Huff_CompressPacket(chan->compresstable, &send, 8 + ((chan->flags&NCF_CLIENT)?2:0) + (chan->flags&NCF_FRAGABLE?2:0));
// Con_Printf("%i becomes %i\n", oldsize, send.cursize); // Con_Printf("%i becomes %i\n", oldsize, send.cursize);
// Huff_DecompressPacket(&send, (chan->sock == NS_CLIENT)?10:8); // Huff_DecompressPacket(&send, (chan->sock == NS_CLIENT)?10:8);
} }
@ -895,23 +1045,25 @@ int Netchan_Transmit (netchan_t *chan, int length, qbyte *data, int rate)
if (!cls.demoplayback) if (!cls.demoplayback)
#endif #endif
{ {
int hsz = 10 + ((chan->sock == NS_CLIENT)?chan->qportsize:0); /*header size, if fragmentation is in use*/
dupes = min(chan->dupe, availbytes / send.cursize); dupes = min(chan->dupe, availbytes / send.cursize);
if ((!chan->pext_fragmentation))// || send.cursize < ((chan->mtu - hsz)&~7)) if (ismtuprobe || !(chan->flags&NCF_FRAGABLE))// || send.cursize < ((chan->mtu - hsz)&~7))
{ //vanilla sends { //vanilla sends
for (i = -1; i < dupes && e == NETERR_SENT; i++) for (i = -1; i < dupes && e == NETERR_SENT; i++)
e = NET_SendPacket (chan->sock, send.cursize, send.data, &chan->remote_address); e = NET_SendPacket (chan->flags, send.cursize, send.data, &chan->remote_address);
send.cursize += send.cursize * i;
//ipv4 'guarentees' mtu sizes of at least 560ish. //ipv4 'guarentees' mtu sizes of at least 560ish.
//our reliable/backbuf messages are limited to 1024 bytes. //our reliable/backbuf messages are limited to 1024 bytes.
//this means that large reliables may be unsendable. //this means that large reliables may be unsendable.
if (e == NETERR_MTU && chan->mtu > 560) if (e == NETERR_MTU && send.cursize-hsz > chan->mtu_min)
{ {
Con_Printf("Reducing MSS to %i\n", chan->mtu); chan->mtu_cur = max(chan->mtu_min, send.cursize-hsz-10);
chan->mtu -= 10; chan->mtu_max = min(chan->mtu_max, chan->mtu_cur); //don't try growing past it
Con_Printf("Reducing MSS to %i\n", chan->mtu_cur);
} }
chan->sentsizes[mtuseq] = send.cursize-hsz;
send.cursize += send.cursize * i;
} }
else else
{ //fte's fragmentaton protocol { //fte's fragmentaton protocol
@ -925,14 +1077,15 @@ int Netchan_Transmit (netchan_t *chan, int length, qbyte *data, int rate)
/*send the additional parts, adding new headers within the previous packet*/ /*send the additional parts, adding new headers within the previous packet*/
do do
{ {
no = offset + chan->mtu - hsz; no = offset + chan->mtu_cur - hsz;
if (no < send.cursize-hsz) if (no < send.cursize-hsz)
{ {
no &= ~7; no &= ~7;
more = true; more = true;
} }
else else
{ { //this is the last...
no = send.cursize-hsz; no = send.cursize-hsz;
more = false; more = false;
} }
@ -940,7 +1093,7 @@ int Netchan_Transmit (netchan_t *chan, int length, qbyte *data, int rate)
*(int*)&send.data[(offset) + 0] = LittleLong(w1); *(int*)&send.data[(offset) + 0] = LittleLong(w1);
*(int*)&send.data[(offset) + 4] = LittleLong(w2); *(int*)&send.data[(offset) + 4] = LittleLong(w2);
#ifndef SERVERONLY #ifndef SERVERONLY
if (chan->sock == NS_CLIENT) if (chan->flags&NCF_CLIENT)
{ {
if (chan->qportsize == 2) if (chan->qportsize == 2)
*(short*)&send.data[offset + hsz-4] = LittleShort(chan->qport); *(short*)&send.data[offset + hsz-4] = LittleShort(chan->qport);
@ -955,16 +1108,20 @@ int Netchan_Transmit (netchan_t *chan, int length, qbyte *data, int rate)
for (i = -1; i < dupes && e == NETERR_SENT; i++) for (i = -1; i < dupes && e == NETERR_SENT; i++)
{ {
fragbytes = (no - offset) + hsz; fragbytes = (no - offset) + hsz;
e = NET_SendPacket (chan->sock, fragbytes, send.data + offset, &chan->remote_address); e = NET_SendPacket (chan->flags, fragbytes, send.data + offset, &chan->remote_address);
outbytes += fragbytes; if (e == NETERR_MTU && !offset && chan->mtu_cur > chan->mtu_min)
if (e == NETERR_MTU && !offset && chan->mtu > 560)
{ {
chan->mtu -= 16; chan->mtu_cur = max(chan->mtu_min, chan->mtu_cur-16);
Con_Printf("Reducing MSS to %i\n", chan->mtu); chan->mtu_max = min(chan->mtu_max, chan->mtu_cur); //don't try growing past it
Con_Printf("Reducing MSS to %i\n", chan->mtu_cur);
no = offset; no = offset;
more = true; more = true;
e = NETERR_SENT; //... keep trying...
break; break;
} }
if (!offset)
chan->sentsizes[mtuseq] = fragbytes-hsz;
outbytes += fragbytes;
} }
} }
offset = no; offset = no;
@ -1000,7 +1157,7 @@ int Netchan_Transmit (netchan_t *chan, int length, qbyte *data, int rate)
} }
Con_Printf ("%f %s --> s=%i(%i) a=%i(%i) %i%s\n" Con_Printf ("%f %s --> s=%i(%i) a=%i(%i) %i%s\n"
, Sys_DoubleTime() , Sys_DoubleTime()
, chan->sock == NS_SERVER?"s2c":"c2s" , (chan->flags&NCF_CLIENT)?"c2s":"s2c"
, chan->outgoing_sequence , chan->outgoing_sequence
, send_reliable , send_reliable
, chan->incoming_sequence , chan->incoming_sequence
@ -1026,6 +1183,7 @@ qboolean Netchan_Process (netchan_t *chan)
unsigned reliable_ack, reliable_message; unsigned reliable_ack, reliable_message;
char adr[MAX_ADR_SIZE]; char adr[MAX_ADR_SIZE];
int offset; int offset;
int oob_reliable;
if ( if (
#ifndef SERVERONLY #ifndef SERVERONLY
@ -1041,7 +1199,7 @@ qboolean Netchan_Process (netchan_t *chan)
sequence = MSG_ReadLong (); sequence = MSG_ReadLong ();
sequence_ack = MSG_ReadLong (); sequence_ack = MSG_ReadLong ();
if (chan->pext_stunaware) if (chan->flags&NCF_STUNAWARE)
{ {
sequence = BigLong(sequence); sequence = BigLong(sequence);
if (!(sequence&ANTISTUNBIAS)) if (!(sequence&ANTISTUNBIAS))
@ -1050,13 +1208,15 @@ qboolean Netchan_Process (netchan_t *chan)
sequence_ack = BigLong(sequence_ack); sequence_ack = BigLong(sequence_ack);
} }
oob_reliable = (sequence == (1u<<31) && sequence_ack == (1u<<31));
// skip over the qport if we are a server (its handled elsewhere) // skip over the qport if we are a server (its handled elsewhere)
#ifndef CLIENTONLY #ifndef CLIENTONLY
if (chan->sock == NS_SERVER) if (!(chan->flags&NCF_CLIENT))
MSG_ReadSkip (chan->qportsize); MSG_ReadSkip (chan->qportsize);
#endif #endif
if (chan->pext_fragmentation) if (chan->flags&NCF_FRAGABLE)
offset = (unsigned short)MSG_ReadShort(); offset = (unsigned short)MSG_ReadShort();
else else
offset = 0; offset = 0;
@ -1070,7 +1230,7 @@ qboolean Netchan_Process (netchan_t *chan)
if (showpackets.value) if (showpackets.value)
Con_Printf ("%f %s <-- s=%i(%i) a=%i(%i) %i%s\n" Con_Printf ("%f %s <-- s=%i(%i) a=%i(%i) %i%s\n"
, Sys_DoubleTime() , Sys_DoubleTime()
, chan->sock == NS_SERVER?"c2s":"s2c" , (chan->flags&NCF_CLIENT)?"s2c":"c2s"
, sequence , sequence
, reliable_message , reliable_message
, sequence_ack , sequence_ack
@ -1111,6 +1271,21 @@ qboolean Netchan_Process (netchan_t *chan)
// //
// discard stale or duplicated packets // discard stale or duplicated packets
// //
if (oob_reliable)
{ //if its an oob reliable then its sequence numbers are screwy and bypass the dupe/etc check.
if (NET_AddrIsReliable(&chan->remote_address))
; //mostly for NP_KEXLAN.
else
{
Con_TPrintf ("%s:Unexpected out-of-band reliable at %i\n"
, NET_AdrToString (adr, sizeof(adr), &chan->remote_address)
, chan->incoming_sequence);
return false;
}
}
else
{
int ssize = 0;
if (sequence <= (unsigned)chan->incoming_sequence && if (sequence <= (unsigned)chan->incoming_sequence &&
!(reliable_message && chan->remote_address.prot == NP_KEXLAN)) //*sigh* reliables don't work properly here. !(reliable_message && chan->remote_address.prot == NP_KEXLAN)) //*sigh* reliables don't work properly here.
{ {
@ -1122,6 +1297,17 @@ qboolean Netchan_Process (netchan_t *chan)
return false; return false;
} }
if (chan->outgoing_sequence-sequence_ack < countof(chan->sentsizes)-2)
ssize = chan->sentsizes[sequence_ack&(countof(chan->sentsizes)-1)];
if (ssize && ssize > chan->mtu_cur)
{
chan->mtu_cur = ssize;
Con_DPrintf("MTU confirmed to %i\n", chan->mtu_cur);
chan->mtu_probes = 0; //start growing again.
}
}
if (offset) if (offset)
{ {
int len = net_message.cursize - MSG_GetReadCount(); int len = net_message.cursize - MSG_GetReadCount();
@ -1209,7 +1395,7 @@ qboolean Netchan_Process (netchan_t *chan)
// //
// if this message contains a reliable message, bump incoming_reliable_sequence // if this message contains a reliable message, bump incoming_reliable_sequence
// //
if (reliable_message && chan->remote_address.prot == NP_KEXLAN) //*sigh* reliables don't work properly here. if (oob_reliable) //*sigh* reliables don't work properly here.
; //don't corrupt sequences/acks/etc. ; //don't corrupt sequences/acks/etc.
else else
{ {
@ -1228,7 +1414,6 @@ qboolean Netchan_Process (netchan_t *chan)
+ (chan->outgoing_sequence-sequence_ack)*(1.0-OLD_AVG); + (chan->outgoing_sequence-sequence_ack)*(1.0-OLD_AVG);
chan->frame_rate = chan->frame_rate*OLD_AVG chan->frame_rate = chan->frame_rate*OLD_AVG
+ (realtime-chan->last_received)*(1.0-OLD_AVG); + (realtime-chan->last_received)*(1.0-OLD_AVG);
chan->good_count += 1;
chan->last_received = realtime; chan->last_received = realtime;

View file

@ -297,8 +297,10 @@ static const struct
static neterr_t ICE_Transmit(void *cbctx, const qbyte *data, size_t datasize); static neterr_t ICE_Transmit(void *cbctx, const qbyte *data, size_t datasize);
static neterr_t TURN_Encapsulate(struct icestate_s *ice, netadr_t *to, const qbyte *data, size_t datasize); static neterr_t TURN_Encapsulate(struct icestate_s *ice, netadr_t *to, const qbyte *data, size_t datasize);
static void TURN_AuthorisePeer(struct icestate_s *con, struct iceserver_s *srv, int peer); static void TURN_AuthorisePeer(struct icestate_s *con, struct iceserver_s *srv, int peer);
#ifdef HAVE_DTLS
static neterr_t SCTP_Transmit(sctp_t *sctp, const void *data, size_t length); static neterr_t SCTP_Transmit(sctp_t *sctp, const void *data, size_t length);
#endif
static qboolean ICE_SetFailed(struct icestate_s *con, const char *reasonfmt, ...) LIKEPRINTF(2);
static struct icestate_s *icelist; static struct icestate_s *icelist;
@ -2168,8 +2170,7 @@ static qboolean QDECL ICE_Set(struct icestate_s *con, const char *prop, const ch
con->dtlsstate = con->dtlsfuncs->CreateContext(&con->cred, con, ICE_Transmit, con->dtlspassive); con->dtlsstate = con->dtlsfuncs->CreateContext(&con->cred, con, ICE_Transmit, con->dtlspassive);
else if (net_enable_dtls.ival >= 3) else if (net_enable_dtls.ival >= 3)
{ //peer doesn't seem to support dtls. { //peer doesn't seem to support dtls.
con->state = ICE_FAILED; ICE_SetFailed(con, "peer does not support dtls. Set net_enable_dtls to 1 to make optional.\n");
Con_Printf(CON_WARNING"WARNING: [%s]: peer does not support dtls. Set net_enable_dtls to 1 to make optional.\n", con->friendlyname);
} }
else if (con->state == ICE_CONNECTING && net_enable_dtls.ival>=2) else if (con->state == ICE_CONNECTING && net_enable_dtls.ival>=2)
Con_Printf(CON_WARNING"WARNING: [%s]: peer does not support dtls.\n", con->friendlyname); Con_Printf(CON_WARNING"WARNING: [%s]: peer does not support dtls.\n", con->friendlyname);
@ -2189,10 +2190,7 @@ static qboolean QDECL ICE_Set(struct icestate_s *con, const char *prop, const ch
else if (!con->dtlsstate && con->cred.peer.hash) else if (!con->dtlsstate && con->cred.peer.hash)
{ {
if (!con->peersctpoptional) if (!con->peersctpoptional)
{ ICE_SetFailed(con, "peer is trying to use dtls.%s\n", net_enable_dtls.ival?"":" Set ^[/net_enable_dtls 1^].");
con->state = ICE_FAILED;
Con_Printf(CON_WARNING"WARNING: [%s]: peer is trying to use dtls.%s\n", con->friendlyname, net_enable_dtls.ival?"":" Set ^[/net_enable_dtls 1^].");
}
} }
#endif #endif
} }
@ -2248,10 +2246,7 @@ static qboolean QDECL ICE_Set(struct icestate_s *con, const char *prop, const ch
if (oldstate != con->state && con->state == ICE_CONNECTED) if (oldstate != con->state && con->state == ICE_CONNECTED)
{ {
if (con->chosenpeer.type == NA_INVALID) if (con->chosenpeer.type == NA_INVALID)
{ ICE_SetFailed(con, "ICE failed. peer not valid.\n");
con->state = ICE_FAILED;
Con_Printf(CON_WARNING"[%s]: ICE failed. peer not valid.\n", con->friendlyname);
}
#ifndef CLIENTONLY #ifndef CLIENTONLY
else if (con->proto == ICEP_QWSERVER && con->mode != ICEM_WEBRTC) else if (con->proto == ICEP_QWSERVER && con->mode != ICEM_WEBRTC)
{ {
@ -2413,6 +2408,18 @@ static qboolean QDECL ICE_Set(struct icestate_s *con, const char *prop, const ch
return false; return false;
return true; return true;
} }
static qboolean ICE_SetFailed(struct icestate_s *con, const char *reasonfmt, ...)
{
va_list argptr;
char string[256];
va_start (argptr, reasonfmt);
Q_vsnprintf (string,sizeof(string)-1, reasonfmt,argptr);
va_end (argptr);
Con_Printf(CON_WARNING"[%s]: %s\n", con->friendlyname, string);
return ICE_Set(con, "state", STRINGIFY(ICE_FAILED)); //does the disconnection stuff.
}
static char *ICE_CandidateToSDP(struct icecandidate_s *can, char *value, size_t valuelen) static char *ICE_CandidateToSDP(struct icecandidate_s *can, char *value, size_t valuelen)
{ {
Q_snprintfz(value, valuelen, "a=candidate:%i %i %s %i %s %i typ %s", Q_snprintfz(value, valuelen, "a=candidate:%i %i %s %i %s %i typ %s",
@ -2988,7 +2995,7 @@ void ICE_Tick(void)
continue; continue;
} }
else if ((signed int)(curtime-con->icetimeout) > 0) else if ((signed int)(curtime-con->icetimeout) > 0)
ICE_Set(con, "state", STRINGIFY(ICE_FAILED)); //with no broker context, if we're not trying to send anything then kill the link. ICE_SetFailed(con, S_COLOR_GRAY"[%s]: ice timeout\n", con->friendlyname);
} }
switch(con->mode) switch(con->mode)
@ -3195,6 +3202,7 @@ struct sctp_chunk_s
#define SCTP_TYPE_COOKIEECHO 10 #define SCTP_TYPE_COOKIEECHO 10
#define SCTP_TYPE_COOKIEACK 11 #define SCTP_TYPE_COOKIEACK 11
#define SCTP_TYPE_SHUTDOWNDONE 14 #define SCTP_TYPE_SHUTDOWNDONE 14
#define SCTP_TYPE_PAD 132
#define SCTP_TYPE_FORWARDTSN 192 #define SCTP_TYPE_FORWARDTSN 192
qbyte flags; qbyte flags;
quint16_t length; quint16_t length;
@ -3712,6 +3720,7 @@ void SCTP_Decode(sctp_t *sctp, ftenet_connections_t *col)
sctp->cookie = Z_Malloc(sctp->cookiesize); sctp->cookie = Z_Malloc(sctp->cookiesize);
memcpy(sctp->cookie, p+1, sctp->cookiesize); memcpy(sctp->cookie, p+1, sctp->cookiesize);
break; break;
case 32773: //Padding
case 32776: //ASCONF case 32776: //ASCONF
break; break;
case 49152: case 49152:
@ -3720,6 +3729,12 @@ void SCTP_Decode(sctp_t *sctp, ftenet_connections_t *col)
default: default:
if (net_ice_debug.ival >= 2) if (net_ice_debug.ival >= 2)
Con_Printf(S_COLOR_GRAY"[%s]: SCTP: Found unknown init parameter %i||%#x\n", sctp->friendlyname, ptype, ptype); Con_Printf(S_COLOR_GRAY"[%s]: SCTP: Found unknown init parameter %i||%#x\n", sctp->friendlyname, ptype, ptype);
if (ptype&0x4000)
; //FIXME: SCTP_TYPE_ERROR(6,"Unrecognized Chunk Type")
if (!(ptype&0x8000))
return; //'do not process nay further chunks'
//otherwise parse the next as normal.
break; break;
} }
p = (void*)((qbyte*)p + ((plen+3)&~3)); p = (void*)((qbyte*)p + ((plen+3)&~3));
@ -3811,11 +3826,11 @@ void SCTP_Decode(sctp_t *sctp, ftenet_connections_t *col)
case SCTP_TYPE_ABORT: case SCTP_TYPE_ABORT:
SCTP_ErrorChunk(sctp, "Abort", (struct sctp_errorcause_s*)(c+1), clen-sizeof(*c)); SCTP_ErrorChunk(sctp, "Abort", (struct sctp_errorcause_s*)(c+1), clen-sizeof(*c));
if (sctp->icestate) if (sctp->icestate)
ICE_Set(sctp->icestate, "state", STRINGIFY(ICE_FAILED)); ICE_SetFailed(sctp->icestate, "SCTP Abort");
break; break;
case SCTP_TYPE_SHUTDOWN: //FIXME. we should send an ack... case SCTP_TYPE_SHUTDOWN: //FIXME. we should send an ack...
if (sctp->icestate) if (sctp->icestate)
ICE_Set(sctp->icestate, "state", STRINGIFY(ICE_FAILED)); ICE_SetFailed(sctp->icestate, "SCTP Shutdown");
if (net_ice_debug.ival >= 1) if (net_ice_debug.ival >= 1)
Con_Printf(S_COLOR_GRAY"[%s]: SCTP: Shutdown\n", sctp->friendlyname); Con_Printf(S_COLOR_GRAY"[%s]: SCTP: Shutdown\n", sctp->friendlyname);
break; break;
@ -3849,6 +3864,9 @@ void SCTP_Decode(sctp_t *sctp, ftenet_connections_t *col)
case SCTP_TYPE_COOKIEACK: case SCTP_TYPE_COOKIEACK:
sctp->o.writable = true; //we know the other end is now open. sctp->o.writable = true; //we know the other end is now open.
break; break;
case SCTP_TYPE_PAD:
//don't care.
break;
case SCTP_TYPE_FORWARDTSN: case SCTP_TYPE_FORWARDTSN:
if (clen >= sizeof(struct sctp_chunk_fwdtsn_s)) if (clen >= sizeof(struct sctp_chunk_fwdtsn_s))
{ {
@ -3874,6 +3892,24 @@ void SCTP_Decode(sctp_t *sctp, ftenet_connections_t *col)
//no idea what this chunk is, just ignore it... //no idea what this chunk is, just ignore it...
if (net_ice_debug.ival >= 1) if (net_ice_debug.ival >= 1)
Con_Printf(S_COLOR_GRAY"[%s]: SCTP: Unsupported chunk %i\n", sctp->friendlyname, c->type); Con_Printf(S_COLOR_GRAY"[%s]: SCTP: Unsupported chunk %i\n", sctp->friendlyname, c->type);
switch (c->type>>6)
{
case 0:
clen = (qbyte*)msgend - (qbyte*)c; //'do not process any further chunks'
break;
case 1:
clen = (qbyte*)msgend - (qbyte*)c; //'do not process any further chunks'
/*FIXME: SCTP_TYPE_ERROR(6,"Unrecognized Chunk Type")*/
break;
case 2:
//silently ignore it
break;
case 3:
//ignore-with-error
/*FIXME: SCTP_TYPE_ERROR(6,"Unrecognized Chunk Type")*/
break;
}
break; break;
} }
c = (struct sctp_chunk_s*)((qbyte*)c + ((clen+3)&~3)); //next chunk is 4-byte aligned. c = (struct sctp_chunk_s*)((qbyte*)c + ((clen+3)&~3)); //next chunk is 4-byte aligned.
@ -5015,7 +5051,7 @@ qboolean ICE_WasStun(ftenet_connections_t *col)
case NETERR_NOROUTE: case NETERR_NOROUTE:
return false; //not a dtls packet at all. don't de-ICE it when we're meant to be using ICE. return false; //not a dtls packet at all. don't de-ICE it when we're meant to be using ICE.
case NETERR_DISCONNECTED: //dtls failure. ICE failed. case NETERR_DISCONNECTED: //dtls failure. ICE failed.
iceapi.Set(con, "state", STRINGIFY(ICE_FAILED)); ICE_SetFailed(con, "DTLS Failure");
return true; return true;
default: //some kind of failure decoding the dtls packet. drop it. default: //some kind of failure decoding the dtls packet. drop it.
return true; return true;
@ -5528,7 +5564,7 @@ handleerror:
b->serverid = cl; b->serverid = cl;
if (net_ice_debug.ival) if (net_ice_debug.ival)
Con_Printf(S_COLOR_GRAY"[%s]: Relay to server now open\n", b->ice?b->ice->friendlyname:"?"); Con_Printf(S_COLOR_GRAY"[%s]: Meta channel to game server now open\n", b->ice?b->ice->friendlyname:"?");
} }
break; break;
case ICEMSG_OFFER: //we received an offer from a client case ICEMSG_OFFER: //we received an offer from a client
@ -5604,6 +5640,10 @@ handleerror:
} }
} }
break; break;
default:
if (net_ice_debug.ival)
Con_Printf(S_COLOR_GRAY"[%s]: Broker send unknown packet: %i\n", b->ice?b->ice->friendlyname:"?", cmd);
break;
} }
break; break;
} }
@ -5765,9 +5805,9 @@ void SVC_ICE_Offer(void)
if (!sv.state) if (!sv.state)
return; //err..? return; //err..?
if (net_from.prot != NP_DTLS && net_from.prot != NP_WSS && net_from.prot != NP_TLS) if (net_from.prot != NP_DTLS && net_from.prot != NP_WSS && net_from.prot != NP_TLS)
{ //a) dtls provides a challenge. { //a) dtls provides a challenge (ensuring we can at least ban them).
//b) this contains the caller's ips. We'll be pinging them anyway, but hey. also it'll be too late at this point but it keeps the other side honest. //b) this contains the caller's ips. We'll be pinging them anyway, but hey. also it'll be too late at this point but it keeps the other side honest.
Con_ThrottlePrintf(&throttletimer, 0, CON_WARNING"%s: ice handshake via %s was unencrypted\n", NET_AdrToString (buf, sizeof(buf), &net_from)); Con_ThrottlePrintf(&throttletimer, 0, CON_WARNING"%s: ice handshake from %s was unencrypted\n", NET_AdrToString (buf, sizeof(buf), &net_from), clientaddr);
return; return;
} }

View file

@ -155,8 +155,8 @@
GNUTLS_FUNC(gnutls_certificate_set_verify_function,void,(gnutls_certificate_credentials_t cred, gnutls_certificate_verify_function *func)) \ GNUTLS_FUNC(gnutls_certificate_set_verify_function,void,(gnutls_certificate_credentials_t cred, gnutls_certificate_verify_function *func)) \
GNUTLS_FUNC(gnutls_session_get_ptr,void*,(gnutls_session_t session)) \ GNUTLS_FUNC(gnutls_session_get_ptr,void*,(gnutls_session_t session)) \
GNUTLS_FUNC(gnutls_session_set_ptr,void,(gnutls_session_t session, void *ptr)) \ GNUTLS_FUNC(gnutls_session_set_ptr,void,(gnutls_session_t session, void *ptr)) \
GNUTLS_FUNCPTR(gnutls_malloc,void*,(size_t)) \ GNUTLS_FUNCPTR(gnutls_malloc,void*,(size_t sz),(sz)) \
GNUTLS_FUNCPTR(gnutls_free,void,(void * ptr)) \ GNUTLS_FUNCPTR(gnutls_free,void,(void *ptr),(ptr)) \
GNUTLS_FUNC(gnutls_server_name_set,int,(gnutls_session_t session, gnutls_server_name_type_t type, const void * name, size_t name_length)) \ GNUTLS_FUNC(gnutls_server_name_set,int,(gnutls_session_t session, gnutls_server_name_type_t type, const void * name, size_t name_length)) \
GNUTLS_TRUSTFUNCS \ GNUTLS_TRUSTFUNCS \
GNUTLS_VERIFYFUNCS \ GNUTLS_VERIFYFUNCS \
@ -166,10 +166,10 @@
#ifdef GNUTLS_DYNAMIC #ifdef GNUTLS_DYNAMIC
#define GNUTLS_FUNC(n,ret,args) static ret (VARGS *q##n)args; #define GNUTLS_FUNC(n,ret,args) static ret (VARGS *q##n)args;
#define GNUTLS_FUNCPTR(n,ret,args) static ret (VARGS **q##n)args; #define GNUTLS_FUNCPTR(n,ret,arglist,callargs) static ret (VARGS **q##n)arglist;
#else #else
#define GNUTLS_FUNC(n,ret,args) static ret (VARGS *q##n)args = n; #define GNUTLS_FUNC(n,ret,args) static ret (VARGS *q##n)args = n;
#define GNUTLS_FUNCPTR(n,ret,args) static ret (VARGS **q##n)args = &n; #define GNUTLS_FUNCPTR(n,ret,arglist,callargs) static ret VARGS q##n arglist {return n(callargs);};
#endif #endif
#ifdef HAVE_DTLS #ifdef HAVE_DTLS
@ -198,11 +198,10 @@ static struct
static qboolean Init_GNUTLS(void) static qboolean Init_GNUTLS(void)
{ {
#ifdef GNUTLS_DYNAMIC #ifdef GNUTLS_DYNAMIC
dllfunction_t functable[] = dllfunction_t functable[] =
{ {
#define GNUTLS_FUNC(nam,ret,args) {(void**)&q##nam, #nam}, #define GNUTLS_FUNC(nam,ret,args) {(void**)&q##nam, #nam},
#define GNUTLS_FUNCPTR(nam,ret,args) {(void**)&q##nam, #nam}, #define GNUTLS_FUNCPTR(nam,ret,arglist,calllist) {(void**)&q##nam, #nam},
GNUTLS_FUNCS GNUTLS_FUNCS
#undef GNUTLS_FUNC #undef GNUTLS_FUNC
#undef GNUTLS_FUNCPTR #undef GNUTLS_FUNCPTR
@ -434,7 +433,7 @@ static int QDECL SSL_CheckCert(gnutls_session_t session)
#ifdef _DEBUG #ifdef _DEBUG
for (j = 0, offset = 0; j < certcount; j++) for (j = 0, offset = 0; j < certcount; j++)
offset += certlist[j].size; offset += certlist[j].size;
Con_Printf("%s cert %zu bytes (chain %u)\n", file->certname, offset, certcount); Con_Printf("%s cert %"PRIuSIZE" bytes (chain %u)\n", file->certname, offset, certcount);
Con_Printf("/*%s*/\"", file->certname); Con_Printf("/*%s*/\"", file->certname);
for (j = 0; file->certname[j]; j++) for (j = 0; file->certname[j]; j++)
Con_Printf("\\x%02x", file->certname[j]^0xff); Con_Printf("\\x%02x", file->certname[j]^0xff);
@ -551,8 +550,10 @@ static int QDECL SSL_CheckFingerprint(gnutls_session_t session)
if (!memcmp(digest, file->peerdigest, file->peerhashfunc->digestsize)) if (!memcmp(digest, file->peerdigest, file->peerhashfunc->digestsize))
return 0; return 0;
Con_Printf(CON_ERROR "%s: certificate chain (%i) does not match fingerprint\n", *file->certname?file->certname:"<anon>", certcount);
} }
Con_Printf(CON_ERROR "%s: rejecting certificate\n", file->certname); else
Con_Printf(CON_ERROR "%s: peer did not provide any certificate\n", *file->certname?file->certname:"<anon>");
return GNUTLS_E_CERTIFICATE_ERROR; return GNUTLS_E_CERTIFICATE_ERROR;
} }
#endif #endif
@ -822,22 +823,23 @@ static qboolean servercertfail;
static gnutls_datum_t cookie_key; static gnutls_datum_t cookie_key;
#endif #endif
static vfsfile_t *SSL_OpenPrivKey(char *nativename, size_t nativesize) static vfsfile_t *SSL_OpenPrivKey(char *displayname, size_t displaysize)
{ {
#define privname "privkey.pem" #define privname "privkey.pem"
vfsfile_t *privf; vfsfile_t *privf;
const char *mode = nativename?"wb":"rb"; const char *mode = displayname?"wb":"rb";
int i = COM_CheckParm("-privkey"); int i = COM_CheckParm("-privkey");
if (i++) if (i++)
{ {
if (nativename) if (displayname)
Q_strncpyz(nativename, com_argv[i], nativesize); if (!FS_DisplayPath(com_argv[i], FS_SYSTEM, displayname, displaysize))
Q_strncpyz(displayname, com_argv[i], displaysize);
privf = FS_OpenVFS(com_argv[i], mode, FS_SYSTEM); privf = FS_OpenVFS(com_argv[i], mode, FS_SYSTEM);
} }
else else
{ {
if (nativename) if (displayname)
if (!FS_NativePath(privname, FS_ROOT, nativename, nativesize)) if (!FS_DisplayPath(privname, FS_ROOT, displayname, displaysize))
return NULL; return NULL;
privf = FS_OpenVFS(privname, mode, FS_ROOT); privf = FS_OpenVFS(privname, mode, FS_ROOT);
@ -845,24 +847,24 @@ static vfsfile_t *SSL_OpenPrivKey(char *nativename, size_t nativesize)
return privf; return privf;
#undef privname #undef privname
} }
static vfsfile_t *SSL_OpenPubKey(char *nativename, size_t nativesize) static vfsfile_t *SSL_OpenPubKey(char *displayname, size_t displaysize)
{ {
#define fullchainname "fullchain.pem" #define fullchainname "fullchain.pem"
#define pubname "cert.pem" #define pubname "cert.pem"
vfsfile_t *pubf = NULL; vfsfile_t *pubf = NULL;
const char *mode = nativename?"wb":"rb"; const char *mode = displayname?"wb":"rb";
int i = COM_CheckParm("-pubkey"); int i = COM_CheckParm("-pubkey");
if (i++) if (i++)
{ {
if (nativename) if (displayname)
Q_strncpyz(nativename, com_argv[i], nativesize); Q_strncpyz(displayname, com_argv[i], displaysize);
pubf = FS_OpenVFS(com_argv[i], mode, FS_SYSTEM); pubf = FS_OpenVFS(com_argv[i], mode, FS_SYSTEM);
} }
else else
{ {
if (!pubf && (!nativename || FS_NativePath(fullchainname, FS_ROOT, nativename, nativesize))) if (!pubf && (!displayname || FS_DisplayPath(fullchainname, FS_ROOT, displayname, displaysize)))
pubf = FS_OpenVFS(fullchainname, mode, FS_ROOT); pubf = FS_OpenVFS(fullchainname, mode, FS_ROOT);
if (!pubf && (!nativename || FS_NativePath(pubname, FS_ROOT, nativename, nativesize))) if (!pubf && (!displayname || FS_DisplayPath(pubname, FS_ROOT, displayname, displaysize)))
pubf = FS_OpenVFS(pubname, mode, FS_ROOT); pubf = FS_OpenVFS(pubname, mode, FS_ROOT);
} }
return pubf; return pubf;
@ -957,24 +959,24 @@ static qboolean SSL_LoadPrivateCert(gnutls_certificate_credentials_t cred)
if (priv.size && pub.size) if (priv.size && pub.size)
{ {
char fullname[MAX_OSPATH]; char displayname[MAX_OSPATH];
privf = SSL_OpenPrivKey(fullname, sizeof(fullname)); privf = SSL_OpenPrivKey(displayname, sizeof(displayname));
if (privf) if (privf)
{ {
VFS_WRITE(privf, priv.data, priv.size); VFS_WRITE(privf, priv.data, priv.size);
VFS_CLOSE(privf); VFS_CLOSE(privf);
Con_Printf("Wrote %s\n", fullname); Con_Printf("Wrote %s\n", displayname);
} }
// memset(priv.data, 0, priv.size); // memset(priv.data, 0, priv.size);
(*qgnutls_free)(priv.data); (*qgnutls_free)(priv.data);
memset(&priv, 0, sizeof(priv)); memset(&priv, 0, sizeof(priv));
pubf = SSL_OpenPubKey(fullname, sizeof(fullname)); pubf = SSL_OpenPubKey(displayname, sizeof(displayname));
if (pubf) if (pubf)
{ {
VFS_WRITE(pubf, pub.data, pub.size); VFS_WRITE(pubf, pub.data, pub.size);
VFS_CLOSE(pubf); VFS_CLOSE(pubf);
Con_Printf("Wrote %s\n", fullname); Con_Printf("Wrote %s\n", displayname);
} }
(*qgnutls_free)(pub.data); (*qgnutls_free)(pub.data);
memset(&pub, 0, sizeof(pub)); memset(&pub, 0, sizeof(pub));
@ -1085,8 +1087,8 @@ qboolean SSL_InitGlobal(qboolean isserver)
char keyfile[MAX_OSPATH]; char keyfile[MAX_OSPATH];
char certfile[MAX_OSPATH]; char certfile[MAX_OSPATH];
*keyfile = *certfile = 0; *keyfile = *certfile = 0;
if (FS_NativePath("key.pem", FS_ROOT, keyfile, sizeof(keyfile))) if (FS_SystemPath("key.pem", FS_ROOT, keyfile, sizeof(keyfile)))
if (FS_NativePath("cert.pem", FS_ROOT, certfile, sizeof(certfile))) if (FS_SystemPath("cert.pem", FS_ROOT, certfile, sizeof(certfile)))
ret = qgnutls_certificate_set_x509_key_file(xcred[isserver], certfile, keyfile, GNUTLS_X509_FMT_PEM); ret = qgnutls_certificate_set_x509_key_file(xcred[isserver], certfile, keyfile, GNUTLS_X509_FMT_PEM);
if (ret < 0) if (ret < 0)
{ {
@ -1127,6 +1129,13 @@ void GnuTLS_Shutdown(void)
qgnutls_global_deinit(); //refcounted. qgnutls_global_deinit(); //refcounted.
} }
#ifdef HAVE_DTLS
if (cookie_key.data)
{
(*qgnutls_free)(cookie_key.data);
memset(&cookie_key, 0, sizeof(cookie_key));
}
#endif
#ifdef GNUTLS_DYNAMIC #ifdef GNUTLS_DYNAMIC
if (gnutls.hmod) if (gnutls.hmod)
Sys_CloseLibrary(gnutls.hmod); Sys_CloseLibrary(gnutls.hmod);

View file

@ -765,7 +765,7 @@ static PCCERT_CONTEXT SSPI_GetServerCertificate(void)
); );
} }
if (!ret) if (!ret)
Con_Printf(CON_ERROR"Certificate generation failed...\n"); Con_Printf(CON_ERROR"SChannel: Certificate generation failed...\n"); //happens in wine.
else else
{ {
//this is stupid and redundant, yet apparently still needed. //this is stupid and redundant, yet apparently still needed.

File diff suppressed because it is too large Load diff

View file

@ -394,7 +394,7 @@ typedef struct ftecrypto_s
const struct dtlsfuncs_s *(*DTLS_InitServer)(void); //returns NULL if there's no cert available. const struct dtlsfuncs_s *(*DTLS_InitServer)(void); //returns NULL if there's no cert available.
//digital signature stuff. note: uses sha2_512 //digital signature stuff. note: uses sha2_512
enum hashvalidation_e (*VerifyHash)(const qbyte *hashdata, size_t hashsize, const qbyte *certdata, size_t certsize, const qbyte *signdata, size_t signsize); enum hashvalidation_e (*VerifyHash)(const qbyte *hashdata, size_t hashsize, const qbyte *certdata, size_t certsize, const qbyte *signdata, size_t signsize); //expect the cert in PEM format.
int (*GenerateSignature)(const qbyte *hashdata, size_t hashsize, qbyte *signdata, size_t signsizemax); int (*GenerateSignature)(const qbyte *hashdata, size_t hashsize, qbyte *signdata, size_t signsizemax);
} ftecrypto_t; } ftecrypto_t;
#define cryptolib_count 6 #define cryptolib_count 6
@ -448,8 +448,8 @@ enum icemsgtype_s
ICEMSG_PEERLOST=0, //other side dropped connection ICEMSG_PEERLOST=0, //other side dropped connection
ICEMSG_GREETING=1, //master telling us our unique game name ICEMSG_GREETING=1, //master telling us our unique game name
ICEMSG_NEWPEER=2, //relay established, send an offer now. ICEMSG_NEWPEER=2, //relay established, send an offer now.
ICEMSG_OFFER=3, //peer's initial details ICEMSG_OFFER=3, //peer->peer - peer's offer or answer details
ICEMSG_CANDIDATE=4, //candidate updates. may arrive late as new ones are discovered. ICEMSG_CANDIDATE=4, //peer->peer - candidate updates. may arrive late as new ones are discovered.
ICEMSG_ACCEPT=5, //go go go (response from offer) ICEMSG_ACCEPT=5, //go go go (response from offer)
ICEMSG_SERVERINFO=6,//server->broker (for advertising the server properly) ICEMSG_SERVERINFO=6,//server->broker (for advertising the server properly)
ICEMSG_SERVERUPDATE=7,//broker->browser (for querying available server lists) ICEMSG_SERVERUPDATE=7,//broker->browser (for querying available server lists)

View file

@ -16,7 +16,6 @@ struct q3gamecode_s *q3;
static struct plugin_s *q3plug; static struct plugin_s *q3plug;
#endif #endif
#define Q_snprintf Q_snprintfz
#define Q_strlcpy Q_strncpyz #define Q_strlcpy Q_strncpyz
#define Q_strlcat Q_strncatz #define Q_strlcat Q_strncatz
#define Sys_Errorf Sys_Error #define Sys_Errorf Sys_Error
@ -28,12 +27,18 @@ static struct plugin_s *q3plug;
#include "../engine/common/com_phys_ode.c" #include "../engine/common/com_phys_ode.c"
#endif #endif
#ifdef STATIC_EZHUD //if its statically linked and loading by default then block it by default and let configs reenable it. The defaults must be maintained for deltaing configs to work, yet they're defective and should never be used in that default configuration
cvar_t plug_sbar = CVARD("plug_sbar", "0", "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).");
#else
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_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).");
#endif
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"); 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");
extern qboolean Plug_Q3_Init(void); extern qboolean Plug_Q3_Init(void);
extern qboolean Plug_Bullet_Init(void); extern qboolean Plug_Bullet_Init(void);
extern qboolean Plug_ODE_Init(void); extern qboolean Plug_ODE_Init(void);
extern qboolean Plug_EZHud_Init(void);
extern qboolean Plug_OpenSSL_Init(void);
static struct static struct
{ {
const char *name; const char *name;
@ -50,6 +55,12 @@ static struct
{"GLTF", Plug_GLTF_Init}, {"GLTF", Plug_GLTF_Init},
#endif #endif
#ifdef STATIC_OPENSSL
{"openssl_internal", Plug_OpenSSL_Init},
#endif
#ifdef STATIC_EZHUD
{"EZHud_internal", Plug_EZHud_Init},
#endif
#ifdef STATIC_Q3 #ifdef STATIC_Q3
{"quake3", Plug_Q3_Init}, {"quake3", Plug_Q3_Init},
#endif #endif
@ -229,14 +240,14 @@ static plugin_t *Plug_Load(const char *file)
{ //already postfixed, don't mess with the name given { //already postfixed, don't mess with the name given
//mandate the fteplug_ prefix (don't let them load random dlls) //mandate the fteplug_ prefix (don't let them load random dlls)
if (!Q_strncasecmp(file, PLUGINPREFIX, strlen(PLUGINPREFIX))) if (!Q_strncasecmp(file, PLUGINPREFIX, strlen(PLUGINPREFIX)))
if (FS_NativePath(file, prefixes[i], newplug->filename, sizeof(newplug->filename))) if (FS_SystemPath(file, prefixes[i], newplug->filename, sizeof(newplug->filename)))
newplug->lib = Sys_LoadLibrary(newplug->filename, funcs); newplug->lib = Sys_LoadLibrary(newplug->filename, funcs);
} }
else else
{ //otherwise scan for it { //otherwise scan for it
for (j = 0; j < countof(postfixes) && !newplug->lib; j++) for (j = 0; j < countof(postfixes) && !newplug->lib; j++)
{ {
if (FS_NativePath(va(PLUGINPREFIX"%s%s", file, postfixes[j]), prefixes[i], newplug->filename, sizeof(newplug->filename))) if (FS_SystemPath(va(PLUGINPREFIX"%s%s", file, postfixes[j]), prefixes[i], newplug->filename, sizeof(newplug->filename)))
newplug->lib = Sys_LoadLibrary(newplug->filename, funcs); newplug->lib = Sys_LoadLibrary(newplug->filename, funcs);
} }
} }
@ -1068,7 +1079,9 @@ void Plug_Net_Close_Internal(qhandle_t handle)
static int QDECL Plug_Net_Recv(qhandle_t handle, void *dest, int destlen) static int QDECL Plug_Net_Recv(qhandle_t handle, void *dest, int destlen)
{ {
#ifdef HAVE_PACKET
int read; int read;
#endif
if (handle < 0 || handle >= pluginstreamarraylen || pluginstreamarray[handle].plugin != currentplug) if (handle < 0 || handle >= pluginstreamarraylen || pluginstreamarray[handle].plugin != currentplug)
return -2; return -2;
@ -1098,7 +1111,9 @@ static int QDECL Plug_Net_Recv(qhandle_t handle, void *dest, int destlen)
} }
static int QDECL Plug_Net_Send(qhandle_t handle, void *src, int srclen) static int QDECL Plug_Net_Send(qhandle_t handle, void *src, int srclen)
{ {
#ifdef HAVE_PACKET
int written; int written;
#endif
if (handle < 0 || handle >= pluginstreamarraylen || pluginstreamarray[handle].plugin != currentplug) if (handle < 0 || handle >= pluginstreamarraylen || pluginstreamarray[handle].plugin != currentplug)
return -2; return -2;
switch(pluginstreamarray[handle].type) switch(pluginstreamarray[handle].type)
@ -1125,6 +1140,7 @@ static int QDECL Plug_Net_Send(qhandle_t handle, void *src, int srclen)
return -2; return -2;
} }
} }
#ifdef HAVE_PACKET
static int QDECL Plug_Net_SendTo(qhandle_t handle, void *src, int srclen, netadr_t *address) static int QDECL Plug_Net_SendTo(qhandle_t handle, void *src, int srclen, netadr_t *address)
{ {
int written; int written;
@ -1146,7 +1162,6 @@ static int QDECL Plug_Net_SendTo(qhandle_t handle, void *src, int srclen, netadr
return -2; return -2;
switch(pluginstreamarray[handle].type) switch(pluginstreamarray[handle].type)
{ {
#ifdef HAVE_PACKET
case STREAM_SOCKET: case STREAM_SOCKET:
written = sendto(pluginstreamarray[handle].socket, src, srclen, 0, (struct sockaddr*)&sockaddr, sizeof(sockaddr)); written = sendto(pluginstreamarray[handle].socket, src, srclen, 0, (struct sockaddr*)&sockaddr, sizeof(sockaddr));
if (written < 0) if (written < 0)
@ -1159,11 +1174,11 @@ static int QDECL Plug_Net_SendTo(qhandle_t handle, void *src, int srclen, netadr
else if (written == 0) else if (written == 0)
return -2; //closed by remote connection. return -2; //closed by remote connection.
return written; return written;
#endif
default: default:
return -2; return -2;
} }
} }
#endif
static void QDECL Plug_Net_Close(qhandle_t handle) static void QDECL Plug_Net_Close(qhandle_t handle)
{ {
if (handle < 0 || handle >= pluginstreamarraylen || pluginstreamarray[handle].plugin != currentplug) if (handle < 0 || handle >= pluginstreamarraylen || pluginstreamarray[handle].plugin != currentplug)
@ -1187,7 +1202,7 @@ void QDECL Plug_FS_EnumerateFiles(enum fs_relative fsroot, const char *match, in
} }
else else
{ {
FS_NativePath("", fsroot, base, sizeof(base)); FS_SystemPath("", fsroot, base, sizeof(base));
Sys_EnumerateFiles(base, match, callback, ctx, NULL); Sys_EnumerateFiles(base, match, callback, ctx, NULL);
} }
} }
@ -1235,7 +1250,7 @@ static void Plug_Load_f(void)
void Plug_Initialise(qboolean fromgamedir) void Plug_Initialise(qboolean fromgamedir)
{ {
char nat[MAX_OSPATH]; char sys[MAX_OSPATH], disp[MAX_OSPATH];
if (!plugfuncs) if (!plugfuncs)
{ {
@ -1260,15 +1275,15 @@ void Plug_Initialise(qboolean fromgamedir)
{ {
if (!fromgamedir) if (!fromgamedir)
{ {
if (FS_NativePath("", FS_BINARYPATH, nat, sizeof(nat))) if (FS_DisplayPath("", FS_BINARYPATH, disp, sizeof(disp)) && FS_SystemPath("", FS_BINARYPATH, sys, sizeof(sys)))
{ {
Con_DPrintf("Loading plugins from \"%s\"\n", nat); Con_DPrintf("Loading plugins from \"%s\"\n", disp);
Sys_EnumerateFiles(nat, PLUGINPREFIX"*" ARCH_CPU_POSTFIX ARCH_DL_POSTFIX, Plug_EnumeratedRoot, NULL, NULL); Sys_EnumerateFiles(sys, PLUGINPREFIX"*" ARCH_CPU_POSTFIX ARCH_DL_POSTFIX, Plug_EnumeratedRoot, NULL, NULL);
} }
if (FS_NativePath("", FS_LIBRARYPATH, nat, sizeof(nat))) if (FS_DisplayPath("", FS_LIBRARYPATH, disp, sizeof(disp)) && FS_SystemPath("", FS_BINARYPATH, sys, sizeof(sys)))
{ {
Con_DPrintf("Loading plugins from \"%s\"\n", nat); Con_DPrintf("Loading plugins from \"%s\"\n", disp);
Sys_EnumerateFiles(nat, PLUGINPREFIX"*" ARCH_CPU_POSTFIX ARCH_DL_POSTFIX, Plug_EnumeratedRoot, NULL, NULL); Sys_EnumerateFiles(sys, PLUGINPREFIX"*" ARCH_CPU_POSTFIX ARCH_DL_POSTFIX, Plug_EnumeratedRoot, NULL, NULL);
} }
} }
} }
@ -1664,7 +1679,7 @@ void Plug_Close_f(void)
for (plug = plugs; plug; plug = plug->next) for (plug = plugs; plug; plug = plug->next)
{ {
if (!strcmp(plug->name, name)) if (!Q_strcasecmp(plug->name, name))
{ {
Plug_Close(plug); Plug_Close(plug);
return; return;
@ -1674,7 +1689,7 @@ void Plug_Close_f(void)
name = va("plugins/%s", name); name = va("plugins/%s", name);
for (plug = plugs; plug; plug = plug->next) for (plug = plugs; plug; plug = plug->next)
{ {
if (!strcmp(plug->name, name)) if (!Q_strcasecmp(plug->name, name))
{ {
Plug_Close(plug); Plug_Close(plug);
return; return;
@ -1760,6 +1775,7 @@ int QDECL Plug_List_Print(const char *fname, qofs_t fsize, time_t modtime, void
void Plug_List_f(void) void Plug_List_f(void)
{ {
char displaypath[MAX_OSPATH];
char binarypath[MAX_OSPATH]; char binarypath[MAX_OSPATH];
char librarypath[MAX_OSPATH]; char librarypath[MAX_OSPATH];
char rootpath[MAX_OSPATH]; char rootpath[MAX_OSPATH];
@ -1768,6 +1784,9 @@ void Plug_List_f(void)
Con_Printf("Loaded plugins:\n"); Con_Printf("Loaded plugins:\n");
for (plug = plugs; plug; plug = plug->next) for (plug = plugs; plug; plug = plug->next)
if (plug->lib && FS_DisplayPath(plug->filename, FS_SYSTEM, displaypath, sizeof(displaypath)))
Con_Printf("^[^2%s\\type\\plug_close %s\\^]: loaded\n", displaypath, plug->name);
else
Con_Printf("^[^2%s\\type\\plug_close %s\\^]: loaded\n", plug->filename, plug->name); Con_Printf("^[^2%s\\type\\plug_close %s\\^]: loaded\n", plug->filename, plug->name);
if (staticplugins[0].name) if (staticplugins[0].name)
@ -1777,17 +1796,18 @@ void Plug_List_f(void)
Plug_List_Print(staticplugins[u].name, 0, 0, NULL, NULL); Plug_List_Print(staticplugins[u].name, 0, 0, NULL, NULL);
} }
if (FS_NativePath("", FS_BINARYPATH, binarypath, sizeof(binarypath))) if (FS_SystemPath("", FS_BINARYPATH, binarypath, sizeof(binarypath)))
{ {
#ifdef _WIN32 #ifdef _WIN32
char *mssuck; char *mssuck;
while ((mssuck=strchr(binarypath, '\\'))) while ((mssuck=strchr(binarypath, '\\')))
*mssuck = '/'; *mssuck = '/';
#endif #endif
Con_Printf("Scanning for plugins at %s:\n", binarypath); if (FS_DisplayPath(binarypath, FS_SYSTEM, displaypath, sizeof(displaypath)))
Sys_EnumerateFiles(binarypath, PLUGINPREFIX"*" ARCH_DL_POSTFIX, Plug_List_Print, binarypath, NULL); Con_Printf("Scanning for plugins at %s:\n", displaypath);
Sys_EnumerateFiles(binarypath, PLUGINPREFIX"*" ARCH_DL_POSTFIX, Plug_List_Print, displaypath, NULL);
} }
if (FS_NativePath("", FS_LIBRARYPATH, librarypath, sizeof(librarypath))) if (FS_SystemPath("", FS_LIBRARYPATH, librarypath, sizeof(librarypath)))
{ {
#ifdef _WIN32 #ifdef _WIN32
char *mssuck; char *mssuck;
@ -1796,11 +1816,12 @@ void Plug_List_f(void)
#endif #endif
if (strcmp(librarypath, rootpath)) if (strcmp(librarypath, rootpath))
{ {
Con_Printf("Scanning for plugins at %s:\n", librarypath); if (FS_DisplayPath(librarypath, FS_SYSTEM, displaypath, sizeof(displaypath)))
Sys_EnumerateFiles(librarypath, PLUGINPREFIX"*" ARCH_DL_POSTFIX, Plug_List_Print, librarypath, NULL); Con_Printf("Scanning for plugins at %s:\n", displaypath);
Sys_EnumerateFiles(librarypath, PLUGINPREFIX"*" ARCH_DL_POSTFIX, Plug_List_Print, displaypath, NULL);
} }
} }
if (FS_NativePath("", FS_ROOT, rootpath, sizeof(rootpath))) if (FS_SystemPath("", FS_ROOT, rootpath, sizeof(rootpath)))
{ {
#ifdef _WIN32 #ifdef _WIN32
char *mssuck; char *mssuck;
@ -1809,8 +1830,9 @@ void Plug_List_f(void)
#endif #endif
if (strcmp(binarypath, rootpath)) if (strcmp(binarypath, rootpath))
{ {
Con_DPrintf("Scanning for plugins at %s:\n", rootpath); if (FS_DisplayPath(rootpath, FS_SYSTEM, displaypath, sizeof(displaypath)))
Sys_EnumerateFiles(rootpath, PLUGINPREFIX"*" ARCH_DL_POSTFIX, Plug_List_Print, rootpath, NULL); Con_Printf("Scanning for plugins at %s:\n", displaypath);
Sys_EnumerateFiles(rootpath, PLUGINPREFIX"*" ARCH_DL_POSTFIX, Plug_List_Print, displaypath, NULL);
} }
} }
@ -1948,7 +1970,7 @@ static void *QDECL PlugBI_GetEngineInterface(const char *interfacename, size_t s
FS_FLocateFile, FS_FLocateFile,
FS_OpenVFS, FS_OpenVFS,
FS_NativePath, FS_SystemPath,
FS_Rename, FS_Rename,
FS_Remove, FS_Remove,
@ -2009,6 +2031,7 @@ static void *QDECL PlugBI_GetEngineInterface(const char *interfacename, size_t s
if (structsize == sizeof(funcs)) if (structsize == sizeof(funcs))
return &funcs; return &funcs;
} }
#ifdef HAVE_PACKET
if (!strcmp(interfacename, plugnetfuncs_name)) if (!strcmp(interfacename, plugnetfuncs_name))
{ {
static plugnetfuncs_t funcs = static plugnetfuncs_t funcs =
@ -2038,6 +2061,7 @@ static void *QDECL PlugBI_GetEngineInterface(const char *interfacename, size_t s
if (structsize == sizeof(funcs)) if (structsize == sizeof(funcs))
return &funcs; return &funcs;
} }
#endif
if (!strcmp(interfacename, plugworldfuncs_name)) if (!strcmp(interfacename, plugworldfuncs_name))
{ {
static plugworldfuncs_t funcs = static plugworldfuncs_t funcs =
@ -2265,6 +2289,7 @@ static void *QDECL PlugBI_GetEngineInterface(const char *interfacename, size_t s
return &funcs; return &funcs;
} }
#ifdef CL_MASTER
if (!strcmp(interfacename, plugmasterfuncs_name)) if (!strcmp(interfacename, plugmasterfuncs_name))
{ {
static plugmasterfuncs_t funcs = static plugmasterfuncs_t funcs =
@ -2285,6 +2310,7 @@ static void *QDECL PlugBI_GetEngineInterface(const char *interfacename, size_t s
if (structsize == sizeof(funcs)) if (structsize == sizeof(funcs))
return &funcs; return &funcs;
} }
#endif
if (!strcmp(interfacename, plugimagefuncs_name)) if (!strcmp(interfacename, plugimagefuncs_name))
{ {
static plugimagefuncs_t funcs = static plugimagefuncs_t funcs =
@ -2374,6 +2400,7 @@ static void *QDECL PlugBI_GetEngineInterface(const char *interfacename, size_t s
VectorAngles, VectorAngles,
AngleVectors, AngleVectors,
GenMatrixPosQuat4Scale, GenMatrixPosQuat4Scale,
QuaternionSlerp,
Alias_ForceConvertBoneData, Alias_ForceConvertBoneData,

View file

@ -1019,8 +1019,8 @@ void QCBUILTIN PF_getsurfacenormal(pubprogfuncs_t *prinst, struct globalvars_s *
model = w->Get_CModel(w, ent->v->modelindex); model = w->Get_CModel(w, ent->v->modelindex);
if (!model || model->type != mod_brush || surfnum >= model->nummodelsurfaces) if (!model || model->type != mod_brush || surfnum >= model->nummodelsurfaces || !model->surfaces[model->firstmodelsurface+surfnum].plane)
{ { //non-planar surfs don't always have a single plane... return nothing instead of breaking.
G_FLOAT(OFS_RETURN+0) = 0; G_FLOAT(OFS_RETURN+0) = 0;
G_FLOAT(OFS_RETURN+1) = 0; G_FLOAT(OFS_RETURN+1) = 0;
G_FLOAT(OFS_RETURN+2) = 0; G_FLOAT(OFS_RETURN+2) = 0;
@ -1053,12 +1053,24 @@ void QCBUILTIN PF_getsurfacetexture(pubprogfuncs_t *prinst, struct globalvars_s
if (!model || model->type != mod_brush) if (!model || model->type != mod_brush)
return; return;
if (surfnum < 0 || surfnum >= model->nummodelsurfaces) if (surfnum >= model->nummodelsurfaces)
return; return;
if (surfnum < 0)
{
surfnum = -1-surfnum;
if ((unsigned)surfnum >= (unsigned)model->numtextures)
return; //nope, outta range.
if (!model->textures[surfnum])
return; //some maps are just broken.
G_INT(OFS_RETURN) = PR_TempString(prinst, model->textures[surfnum]->name);
}
else
{
surfnum += model->firstmodelsurface; surfnum += model->firstmodelsurface;
surf = &model->surfaces[surfnum]; surf = &model->surfaces[surfnum];
G_INT(OFS_RETURN) = PR_TempString(prinst, surf->texinfo->texture->name); G_INT(OFS_RETURN) = PR_TempString(prinst, surf->texinfo->texture->name);
} }
}
#define TriangleNormal(a,b,c,n) ( \ #define TriangleNormal(a,b,c,n) ( \
(n)[0] = ((a)[1] - (b)[1]) * ((c)[2] - (b)[2]) - ((a)[2] - (b)[2]) * ((c)[1] - (b)[1]), \ (n)[0] = ((a)[1] - (b)[1]) * ((c)[2] - (b)[2]) - ((a)[2] - (b)[2]) * ((c)[1] - (b)[1]), \
(n)[1] = ((a)[2] - (b)[2]) * ((c)[0] - (b)[0]) - ((a)[0] - (b)[0]) * ((c)[2] - (b)[2]), \ (n)[1] = ((a)[2] - (b)[2]) * ((c)[0] - (b)[0]) - ((a)[0] - (b)[0]) * ((c)[2] - (b)[2]), \
@ -2040,6 +2052,28 @@ void QCBUILTIN PF_memfree (pubprogfuncs_t *prinst, struct globalvars_s *pr_globa
if (qcptr) if (qcptr)
prinst->AddressableFree(prinst, cptr); prinst->AddressableFree(prinst, cptr);
} }
void QCBUILTIN PF_memcmp (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{
int qcdst = G_INT(OFS_PARM0);
int qcsrc = G_INT(OFS_PARM1);
int size = G_INT(OFS_PARM2);
int srcoffset = (prinst->callargc>3)?G_INT(OFS_PARM3):0;
int dstoffset = (prinst->callargc>4)?G_INT(OFS_PARM4):0;
G_INT(OFS_RETURN) = 0;
if (size < 0)
PR_BIError(prinst, "PF_memcmp: invalid size\n");
else if (size)
{
void *dst = PR_PointerToNative_MoInvalidate(prinst, qcdst, dstoffset, size);
void *src = PR_PointerToNative_MoInvalidate(prinst, qcsrc, srcoffset, size);
if (!dst)
PR_BIError(prinst, "PF_memcmp: invalid dest\n");
else if (!src)
PR_BIError(prinst, "PF_memcmp: invalid source\n");
else
G_INT(OFS_RETURN) = memcmp(dst, src, size);
}
}
void QCBUILTIN PF_memcpy (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) void QCBUILTIN PF_memcpy (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals)
{ {
int qcdst = G_INT(OFS_PARM0); int qcdst = G_INT(OFS_PARM0);

View file

@ -579,6 +579,7 @@ void QCBUILTIN PF_base64decode(pubprogfuncs_t *prinst, struct globalvars_s *pr_g
void QCBUILTIN PF_memalloc (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals); void QCBUILTIN PF_memalloc (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
void QCBUILTIN PF_memfree (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals); void QCBUILTIN PF_memfree (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
void QCBUILTIN PF_memcmp (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
void QCBUILTIN PF_memcpy (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals); void QCBUILTIN PF_memcpy (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
void QCBUILTIN PF_memfill8 (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals); void QCBUILTIN PF_memfill8 (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
void QCBUILTIN PF_memgetval (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals); void QCBUILTIN PF_memgetval (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals);
@ -930,6 +931,7 @@ enum packagemanagerinfo_e
GPMI_AVAILABLE, //whether it may be downloaded or not. GPMI_AVAILABLE, //whether it may be downloaded or not.
GPMI_FILESIZE, //whether it may be downloaded or not. GPMI_FILESIZE, //whether it may be downloaded or not.
GPMI_GAMEDIR, //so you know which mod(s) its relevant for GPMI_GAMEDIR, //so you know which mod(s) its relevant for
GPMI_MAPS, //so you know which mod(s) its relevant for
}; };
#ifdef TERRAIN #ifdef TERRAIN
@ -1060,6 +1062,7 @@ enum
globalfunction(CSQC_InputEvent, "float(float evtype, float scanx, float chary, float devid)") \ globalfunction(CSQC_InputEvent, "float(float evtype, float scanx, float chary, float devid)") \
globalfunction(CSQC_Input_Frame, "void()")/*EXT_CSQC_1*/ \ globalfunction(CSQC_Input_Frame, "void()")/*EXT_CSQC_1*/ \
globalfunction(CSQC_RendererRestarted, "void(string rendererdescription)") \ globalfunction(CSQC_RendererRestarted, "void(string rendererdescription)") \
globalfunction(CSQC_GenerateMaterial, "string(string shadername)") \
globalfunction(CSQC_ConsoleCommand, "float(string cmd)") \ globalfunction(CSQC_ConsoleCommand, "float(string cmd)") \
globalfunction(CSQC_ConsoleLink, "float(string text, string info)") \ globalfunction(CSQC_ConsoleLink, "float(string text, string info)") \
globalfunction(GameCommand, "void(string cmdtext)") /*DP extension*/\ globalfunction(GameCommand, "void(string cmdtext)") /*DP extension*/\

View file

@ -74,6 +74,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#define PEXT_Q3BSP PEXT_Q3BSP_ #define PEXT_Q3BSP PEXT_Q3BSP_
#endif #endif
#define PEXT1_HIDEPROTOCOLS (PEXT_Q3BSP_|PEXT_Q2BSP_|PEXT_HLBSP) //These are hints for the server, and not useful to the client (they can figure stuff out themselves) #define PEXT1_HIDEPROTOCOLS (PEXT_Q3BSP_|PEXT_Q2BSP_|PEXT_HLBSP) //These are hints for the server, and not useful to the client (they can figure stuff out themselves)
//#define PEXT1_DEPRECATED (PEXT_SCALE|PEXT_TRANS|PEXT_ACCURATETIMINGS|PEXT_SOUNDDBL|PEXT_FATNESS|PEXT_HULLSIZE|PEXT_MODELDBL|PEXT_ENTITYDBL|PEXT_ENTITYDBL2|PEXT_COLOURMOD|PEXT_SPAWNSTATIC2|PEXT_256PACKETENTITIES|PEXT_SETATTACHMENT|PEXT_DPFLAGS) //deprecated by replacementdeltas
#define PEXT1_MVDSUPPORT (PEXT1_CLIENTSUPPORT&~PEXT1_DEPRECATED&~PEXT1_HIDEPROTOCOLS) //pext2 extensions to use when recording mvds.
#define PEXT2_PRYDONCURSOR 0x00000001 #define PEXT2_PRYDONCURSOR 0x00000001
#define PEXT2_VOICECHAT 0x00000002 #define PEXT2_VOICECHAT 0x00000002
@ -88,13 +90,27 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#define PEXT2_LERPTIME 0x00000400 //fitz-bloat parity. redefines UF_16BIT as UF_LERPEND in favour of length coding. #define PEXT2_LERPTIME 0x00000400 //fitz-bloat parity. redefines UF_16BIT as UF_LERPEND in favour of length coding.
#define PEXT2_SERVERADVERTISE ~0u #define PEXT2_SERVERADVERTISE ~0u
#define PEXT2_CLIENTSUPPORT (PEXT2_PRYDONCURSOR|PEXT2_VOICECHAT|PEXT2_SETANGLEDELTA|PEXT2_REPLACEMENTDELTAS|PEXT2_MAXPLAYERS|PEXT2_PREDINFO|PEXT2_NEWSIZEENCODING|PEXT2_INFOBLOBS|PEXT2_STUNAWARE|PEXT2_VRINPUTS|PEXT2_LERPTIME) //warn if we see bits not listed here. #define PEXT2_CLIENTSUPPORT (PEXT2_PRYDONCURSOR|PEXT2_VOICECHAT|PEXT2_SETANGLEDELTA|PEXT2_REPLACEMENTDELTAS|PEXT2_MAXPLAYERS|PEXT2_PREDINFO|PEXT2_NEWSIZEENCODING|PEXT2_INFOBLOBS|PEXT2_STUNAWARE|PEXT2_VRINPUTS|PEXT2_LERPTIME) //warn if we see bits not listed here.
#define PEXT2_DEPRECATEDORNEW (PEXT2_INFOBLOBS|PEXT2_VRINPUTS|PEXT2_LERPTIME) //extensions that are outdated
#define PEXT2_MVDSUPPORT (PEXT2_CLIENTSUPPORT&~PEXT2_DEPRECATED&~PEXT2_STUNAWARE) //pext2 extensions to use when recording mvds.
//EzQuake/Mvdsv extensions. (use ezquake name, to avoid confusion about .mvd format and its protocol differences) //EzQuake/Mvdsv extensions. (use ezquake name, to avoid confusion about .mvd format and its protocol differences)
#define EZPEXT1_FLOATENTCOORDS 0x00000001 //quirky - doesn't apply to broadcasts, just players+ents. this gives more precision, but will bug out if you try using it to increase map bounds in ways that may not be immediately apparent. iiuc this was added instead of fixing some inconsistent rounding... #define EZPEXT1_FLOATENTCOORDS 0x00000001 //quirky - doesn't apply to broadcasts, just players+ents. this gives more precision, but will bug out if you try using it to increase map bounds in ways that may not be immediately apparent. iiuc this was added instead of fixing some inconsistent rounding...
#define EZPEXT1_SETANGLEREASON 0x00000002 //specifies the reason for an svc_setangles call. the mvdsv implementation will fuck over any mods that writebyte them. we'd need to modify our preparse stuff to work around the issue. #define EZPEXT1_SETANGLEREASON 0x00000002 //specifies the reason for an svc_setangles call. the mvdsv implementation will fuck over any mods that writebyte them. we'd need to modify our preparse stuff to work around the issue.
#define EZPEXT1_SERVERADVERTISE EZPEXT1_FLOATENTCOORDS/* - implemented, but interactions with replacementdeltas is not defined*/ /*EZPEXT1_SETANGLEREASON - potentially causes compat issues with mods that stuffcmd it (common in nq)*/ //#define EZPEXT1_SERVERSIDEWEAPON 0x00000004 //looks half-baked. would be better to predict grabs clientside (oh noes! backpack knowledge!).
//#define EZPEXT1_DEBUG_WEAPON 0x00000008 //debug? not gonna bother.
//#define EZPEXT1_DEBUG_ANTILAG 0x00000010 //debug? not gonna bother.
#define EZPEXT1_HIDDEN_MESSAGES 0x00000020 //mvd bloat. shouldn't be seen on actual servers.
//#define MVD_PEXT1_SERVERSIDEWEAPON (1 << 2) // Server-side weapon selection
#define MVD_PEXT1_DEBUG_WEAPON (1 << 3) // Send weapon-choice explanation to server for logging
#define MVD_PEXT1_DEBUG_ANTILAG (1 << 4) // Send predicted positions to server (compare to antilagged positions)
#define MVD_PEXT1_HIDDEN_MESSAGES (1 << 5) // dem_multiple(0) packets are in format (<length> <type-id>+ <packet-data>)*
#define EZPEXT1_SERVERADVERTISE (EZPEXT1_FLOATENTCOORDS/* - implemented, but interactions with replacementdeltas is not defined*/ /*|EZPEXT1_SETANGLEREASON - potentially causes compat issues with mods that stuffcmd it (common in nq)*/)
#define EZPEXT1_CLIENTADVERTISE EZPEXT1_FLOATENTCOORDS //might as well ask for it, as a way around mvdsv's writecoord/PM_NudgePosition rounding difference bug. #define EZPEXT1_CLIENTADVERTISE EZPEXT1_FLOATENTCOORDS //might as well ask for it, as a way around mvdsv's writecoord/PM_NudgePosition rounding difference bug.
#define EZPEXT1_CLIENTSUPPORT (EZPEXT1_FLOATENTCOORDS|EZPEXT1_SETANGLEREASON) //ones we can support in demos. warning if other bits. #define EZPEXT1_CLIENTSUPPORT (EZPEXT1_FLOATENTCOORDS|EZPEXT1_SETANGLEREASON|EZPEXT1_HIDDEN_MESSAGES) //ones we can support in demos. warning if other bits.
//ZQuake transparent protocol extensions. //ZQuake transparent protocol extensions.
#define Z_EXT_PM_TYPE (1<<0) // basic PM_TYPE functionality (reliable jump_held) #define Z_EXT_PM_TYPE (1<<0) // basic PM_TYPE functionality (reliable jump_held)
@ -559,8 +575,8 @@ enum {
#define DLERR_PERMISSIONS -2 //server refuses to serve the file #define DLERR_PERMISSIONS -2 //server refuses to serve the file
#define DLERR_UNKNOWN -3 //server bugged out while trying to serve the request #define DLERR_UNKNOWN -3 //server bugged out while trying to serve the request
#define DLERR_REDIRECTFILE -4 //client should download the specified file instead. #define DLERR_REDIRECTFILE -4 //client should download the specified file instead.
#define DLERR_REDIRECTPACK -5 //client should download the specified package instead. #define DLERR_SV_REDIRECTPACK -5 //client should download the specified package instead. may also be an http(s):// location.
#define DLERR_PACKAGE -6 //not networked. packages require special file access. #define DLERR_SV_PACKAGE -6 //not networked. packages require special file access.
#define DLBLOCKSIZE 1024 //chunked downloads use fixed-size chunks (which I somewhat regret, but too late now I guess, really ought to use ranges.). #define DLBLOCKSIZE 1024 //chunked downloads use fixed-size chunks (which I somewhat regret, but too late now I guess, really ought to use ranges.).
@ -1854,15 +1870,15 @@ typedef struct q1usercmd_s
#define MAX_MAP_AREA_BYTES 32 #define MAX_MAP_AREA_BYTES 32
// edict->drawflags (hexen2 stuff) // edict->drawflags (hexen2 stuff)
#define MLS_MASK 7 // Model Light Style #define MLS_MASK 7
#define MLS_NONE 0 #define MLS_NONE 0
#define MLS_FULLBRIGHT 1 #define MLS_LIGHTSTYLE25 1 //indexes style 25 instead of using real lighting info
#define MLS_POWERMODE 2 #define MLS_LIGHTSTYLE26 2 //indexes style 26
#define MLS_TORCH 3 #define MLS_LIGHTSTYLE27 3 //27
#define MLS_TOTALDARK 4 #define MLS_LIGHTSTYLE28 4 //...
#define MLS_UNUSED 4 #define MLS_LIGHTSTYLE29 5 //duh
#define MLS_ADDLIGHT 6 #define MLS_ADDLIGHT 6 //adds abslight to normal lighting
#define MLS_ABSLIGHT (MLS_MASK) #define MLS_ABSLIGHT (MLS_MASK) //uses abslight specifically.
#define SCALE_TYPE_MASK (SCALE_TYPE_UNIFORM|SCALE_TYPE_XYONLY|SCALE_TYPE_ZONLY) #define SCALE_TYPE_MASK (SCALE_TYPE_UNIFORM|SCALE_TYPE_XYONLY|SCALE_TYPE_ZONLY)
#define SCALE_TYPE_UNIFORM 0 // Scale X, Y, and Z #define SCALE_TYPE_UNIFORM 0 // Scale X, Y, and Z
#define SCALE_TYPE_XYONLY 8 // Scale X and Y #define SCALE_TYPE_XYONLY 8 // Scale X and Y
@ -1873,7 +1889,7 @@ typedef struct q1usercmd_s
#define SCALE_ORIGIN_BOTTOM 32 // Scaling origin at object bottom #define SCALE_ORIGIN_BOTTOM 32 // Scaling origin at object bottom
#define SCALE_ORIGIN_TOP 64 // Scaling origin at object top #define SCALE_ORIGIN_TOP 64 // Scaling origin at object top
#define SCALE_ORIGIN_ORIGIN (SCALE_ORIGIN_TOP|SCALE_ORIGIN_BOTTOM) // Scaling origin at object origin #define SCALE_ORIGIN_ORIGIN (SCALE_ORIGIN_TOP|SCALE_ORIGIN_BOTTOM) // Scaling origin at object origin
#define DRF_TRANSLUCENT 128 #define DRF_TRANSLUCENT 128 //alpha is controlled by r_wateralpha
//TENEBRAE_GFX_DLIGHTS //TENEBRAE_GFX_DLIGHTS

View file

@ -1339,14 +1339,14 @@ static unsigned int Q1BSP_TranslateContents(enum q1contents_e contents)
case Q1CONTENTS_LAVA: return FTECONTENTS_LAVA; case Q1CONTENTS_LAVA: return FTECONTENTS_LAVA;
case Q1CONTENTS_SKY: return FTECONTENTS_SKY|FTECONTENTS_PLAYERCLIP|FTECONTENTS_MONSTERCLIP; case Q1CONTENTS_SKY: return FTECONTENTS_SKY|FTECONTENTS_PLAYERCLIP|FTECONTENTS_MONSTERCLIP;
case Q1CONTENTS_LADDER: return FTECONTENTS_LADDER; case Q1CONTENTS_LADDER: return FTECONTENTS_LADDER;
case Q1CONTENTS_CLIP: return FTECONTENTS_PLAYERCLIP|FTECONTENTS_MONSTERCLIP; case HLCONTENTS_CLIP: return FTECONTENTS_PLAYERCLIP|FTECONTENTS_MONSTERCLIP;
case Q1CONTENTS_CURRENT_0: return FTECONTENTS_WATER|Q2CONTENTS_CURRENT_0; //q2 is better than nothing, right? case HLCONTENTS_CURRENT_0: return FTECONTENTS_WATER|Q2CONTENTS_CURRENT_0; //q2 is better than nothing, right?
case Q1CONTENTS_CURRENT_90: return FTECONTENTS_WATER|Q2CONTENTS_CURRENT_90; case HLCONTENTS_CURRENT_90: return FTECONTENTS_WATER|Q2CONTENTS_CURRENT_90;
case Q1CONTENTS_CURRENT_180: return FTECONTENTS_WATER|Q2CONTENTS_CURRENT_180; case HLCONTENTS_CURRENT_180: return FTECONTENTS_WATER|Q2CONTENTS_CURRENT_180;
case Q1CONTENTS_CURRENT_270: return FTECONTENTS_WATER|Q2CONTENTS_CURRENT_270; case HLCONTENTS_CURRENT_270: return FTECONTENTS_WATER|Q2CONTENTS_CURRENT_270;
case Q1CONTENTS_CURRENT_UP: return FTECONTENTS_WATER|Q2CONTENTS_CURRENT_UP; case HLCONTENTS_CURRENT_UP: return FTECONTENTS_WATER|Q2CONTENTS_CURRENT_UP;
case Q1CONTENTS_CURRENT_DOWN: return FTECONTENTS_WATER|Q2CONTENTS_CURRENT_DOWN; case HLCONTENTS_CURRENT_DOWN: return FTECONTENTS_WATER|Q2CONTENTS_CURRENT_DOWN;
case Q1CONTENTS_TRANS: return FTECONTENTS_SOLID; case HLCONTENTS_TRANS: return FTECONTENTS_EMPTY;
case Q1CONTENTS_MONSTERCLIP: return FTECONTENTS_MONSTERCLIP; case Q1CONTENTS_MONSTERCLIP: return FTECONTENTS_MONSTERCLIP;
case Q1CONTENTS_PLAYERCLIP: return FTECONTENTS_PLAYERCLIP; case Q1CONTENTS_PLAYERCLIP: return FTECONTENTS_PLAYERCLIP;
case Q1CONTENTS_CORPSE: return FTECONTENTS_CORPSE; case Q1CONTENTS_CORPSE: return FTECONTENTS_CORPSE;
@ -1420,7 +1420,7 @@ void Q1BSP_LoadBrushes(model_t *model, bspx_header_t *bspx, void *mod_base)
q2cbrush_t *brush; q2cbrush_t *brush;
q2cbrushside_t *sides; //grr! q2cbrushside_t *sides; //grr!
mplane_t *planes; //bulky? mplane_t *planes; //bulky?
unsigned int lumpsizeremaining; size_t lumpsizeremaining;
unsigned int numplanes; unsigned int numplanes;
unsigned int srcver, srcmodelidx, modbrushes, modplanes; unsigned int srcver, srcmodelidx, modbrushes, modplanes;
@ -2560,26 +2560,30 @@ BSPX Stuff
typedef struct { typedef struct {
char lumpname[24]; // up to 23 chars, zero-padded char lumpname[24]; // up to 23 chars, zero-padded
int fileofs; // from file start unsigned int fileofs; // from file start
int filelen; unsigned int filelen;
} bspx_lump_t; } bspx_lump_t;
struct bspx_header_s { struct bspx_header_s {
char id[4]; // 'BSPX' char id[4]; // 'BSPX'
int numlumps; unsigned int numlumps;
bspx_lump_t lumps[1]; bspx_lump_t lumps[1];
}; };
//supported lumps: //supported lumps (read specs/bspx.txt for more details):
//RGBLIGHTING (.lit) //RGBLIGHTING (.lit)
//LIGHTING_E5BGR9 (hdr lit) //LIGHTING_E5BGR9 (hdr lit)
//LIGHTINGDIR (.lux) //LIGHTINGDIR (.lux)
//LMSHIFT (lightmap scaling) //LMSHIFT (lightmap scaling, obsoleted bby DECOUPLED_LM)
//LMOFFSET (lightmap scaling) //LMOFFSET (lightmap scaling, redundant without LMSHIFT)
//LMSTYLE (lightmap scaling) //LMSTYLE (for when 4 styles per face are not enough)
//LMSTYLE16 (for when you need more than 256 different lightswitches)
//VERTEXNORMALS (smooth specular) //VERTEXNORMALS (smooth specular)
//BRUSHLIST (no hull size issues) //BRUSHLIST (no hull size issues)
//ENVMAP (cubemaps) //ENVMAP (cubemaps)
//SURFENVMAP (cubemaps) //SURFENVMAP (cubemaps)
void *BSPX_FindLump(bspx_header_t *bspxheader, void *mod_base, char *lumpname, int *lumpsize) //FACENORMALS (because Quetoo's normals were rejected by ericw for some reason)
//DECOUPLED_LM (upgraded alternative to LM_SHIFT with float scaling and explicit lm sizes)
//LIGHTGRID_OCTREE (lightgrid alternative to floor-based model lighting, but still stuck with 4 8bit ldr styles)
void *BSPX_FindLump(bspx_header_t *bspxheader, void *mod_base, char *lumpname, size_t *lumpsize)
{ {
int i; int i;
*lumpsize = 0; *lumpsize = 0;
@ -2751,12 +2755,12 @@ void BSPX_RenderEnvmaps(model_t *mod)
stride = -stride; stride = -stride;
if (SCR_ScreenShot(filename, FS_GAMEONLY, &buffer, 1, stride, cubesize, cubesize, fmt)) if (SCR_ScreenShot(filename, FS_GAMEONLY, &buffer, 1, stride, cubesize, cubesize, fmt))
{ {
FS_NativePath(filename, FS_GAMEONLY, sysname, sizeof(sysname)); FS_SystemPath(filename, FS_GAMEONLY, sysname, sizeof(sysname));
Con_Printf ("Wrote %s\n", sysname); Con_Printf ("Wrote %s\n", sysname);
} }
else else
{ {
FS_NativePath(filename, FS_GAMEONLY, sysname, sizeof(sysname)); FS_SystemPath(filename, FS_GAMEONLY, sysname, sizeof(sysname));
Con_Printf ("Failed to write %s\n", sysname); Con_Printf ("Failed to write %s\n", sysname);
} }
BZ_Free(buffer); BZ_Free(buffer);
@ -2772,11 +2776,11 @@ void BSPX_RenderEnvmaps(model_t *mod)
void BSPX_LoadEnvmaps(model_t *mod, bspx_header_t *bspx, void *mod_base) void BSPX_LoadEnvmaps(model_t *mod, bspx_header_t *bspx, void *mod_base)
{ {
unsigned int *envidx, idx; unsigned int *envidx, idx;
int i; size_t i;
char base[MAX_QPATH]; char base[MAX_QPATH];
char imagename[MAX_QPATH]; char imagename[MAX_QPATH];
menvmap_t *out; menvmap_t *out;
int count; size_t count;
denvmap_t *in = BSPX_FindLump(bspx, mod_base, "ENVMAP", &count); denvmap_t *in = BSPX_FindLump(bspx, mod_base, "ENVMAP", &count);
mod->envmaps = NULL; mod->envmaps = NULL;
mod->numenvmaps = 0; mod->numenvmaps = 0;
@ -2830,6 +2834,9 @@ struct bspxrw
size_t corelumps; size_t corelumps;
size_t totallumps; size_t totallumps;
void *archivedata;
qofs_t archivesize;
struct struct
{ {
char lumpname[24]; // up to 23 chars, zero-padded char lumpname[24]; // up to 23 chars, zero-padded
@ -2837,14 +2844,14 @@ struct bspxrw
qofs_t filelen; qofs_t filelen;
} *lumps; } *lumps;
}; };
void Mod_BSPXRW_Free(struct bspxrw *ctx) static void Mod_BSPXRW_Free(struct bspxrw *ctx)
{ {
FS_FreeFile(ctx->origfile); FS_FreeFile(ctx->origfile);
Z_Free(ctx->lumps); Z_Free(ctx->lumps);
ctx->corelumps = ctx->totallumps = 0; ctx->corelumps = ctx->totallumps = 0;
ctx->origfile = NULL; ctx->origfile = NULL;
} }
void Mod_BSPXRW_Write(struct bspxrw *ctx) static void Mod_BSPXRW_Write(struct bspxrw *ctx)
{ {
#if 1 #if 1
vfsfile_t *f = FS_OpenVFS(ctx->fname, "wb", FS_GAMEONLY); vfsfile_t *f = FS_OpenVFS(ctx->fname, "wb", FS_GAMEONLY);
@ -2889,6 +2896,9 @@ void Mod_BSPXRW_Write(struct bspxrw *ctx)
VFS_WRITE(f, &paddata, pad); VFS_WRITE(f, &paddata, pad);
} }
//now reinsert any concatenated zip.
VFS_WRITE(f, ctx->archivedata, ctx->archivesize);
//now rewrite both sets of offsets. //now rewrite both sets of offsets.
VFS_SEEK(f, ctx->lumpofs); VFS_SEEK(f, ctx->lumpofs);
VFS_WRITE(f, lumps, sizeof(lumps[0])*ctx->corelumps); VFS_WRITE(f, lumps, sizeof(lumps[0])*ctx->corelumps);
@ -2901,16 +2911,18 @@ void Mod_BSPXRW_Write(struct bspxrw *ctx)
Mod_BSPXRW_Free(ctx); Mod_BSPXRW_Free(ctx);
} }
void Mod_BSPXRW_SetLump(struct bspxrw *ctx, const char *lumpname, void *data, size_t datasize) static qboolean Mod_BSPXRW_SetLump(struct bspxrw *ctx, const char *lumpname, void *data, size_t datasize)
{ {
int i; int i;
for (i = 0; i < ctx->totallumps; i++) for (i = 0; i < ctx->totallumps; i++)
{ {
if (!strcmp(ctx->lumps[i].lumpname, lumpname)) if (!strcmp(ctx->lumps[i].lumpname, lumpname))
{ //replace the existing lump { //replace the existing lump
if (ctx->lumps[i].filelen == datasize && !memcmp(ctx->lumps[i].data, data, datasize))
return false; //nothing changed.
ctx->lumps[i].data = data; ctx->lumps[i].data = data;
ctx->lumps[i].filelen = datasize; ctx->lumps[i].filelen = datasize;
return; return true;
} }
} }
@ -2918,9 +2930,10 @@ void Mod_BSPXRW_SetLump(struct bspxrw *ctx, const char *lumpname, void *data, si
Q_strncpyz(ctx->lumps[i].lumpname, lumpname, sizeof(ctx->lumps[i].lumpname)); Q_strncpyz(ctx->lumps[i].lumpname, lumpname, sizeof(ctx->lumps[i].lumpname));
ctx->lumps[i].data = data; ctx->lumps[i].data = data;
ctx->lumps[i].filelen = datasize; ctx->lumps[i].filelen = datasize;
return true;
} }
qboolean Mod_BSPXRW_Read(struct bspxrw *ctx, const char *fname) static qboolean Mod_BSPXRW_Read(struct bspxrw *ctx, const char *fname)
{ {
int i; int i;
lump_t *l; lump_t *l;
@ -2937,6 +2950,8 @@ qboolean Mod_BSPXRW_Read(struct bspxrw *ctx, const char *fname)
static const char *q2corelumpnames[Q2HEADER_LUMPS] = {"entities","planes","vertexes","visibility","nodes","texinfo","faces","lighting","leafs","leaffaces","leafbrushes","edges","surfedges","models","brushes","brushsides","pop","areas","areaportals"}; static const char *q2corelumpnames[Q2HEADER_LUMPS] = {"entities","planes","vertexes","visibility","nodes","texinfo","faces","lighting","leafs","leaffaces","leafbrushes","edges","surfedges","models","brushes","brushsides","pop","areas","areaportals"};
#endif #endif
static const char *q1corelumpnames[HEADER_LUMPS] = {"entities","planes","textures","vertexes","visibility","nodes","texinfo","faces","lighting","clipnodes","leafs","marksurfaces","edges","surfedges","models"}; static const char *q1corelumpnames[HEADER_LUMPS] = {"entities","planes","textures","vertexes","visibility","nodes","texinfo","faces","lighting","clipnodes","leafs","marksurfaces","edges","surfedges","models"};
ctx->archivedata = NULL;
ctx->archivesize = 0;
ctx->fname = fname; ctx->fname = fname;
ctx->origfile = FS_MallocFile(ctx->fname, FS_GAME, &ctx->origsize); ctx->origfile = FS_MallocFile(ctx->fname, FS_GAME, &ctx->origsize);
if (!ctx->origfile) if (!ctx->origfile)
@ -3035,7 +3050,7 @@ qboolean Mod_BSPXRW_Read(struct bspxrw *ctx, const char *fname)
return true; return true;
} }
unsigned int Mod_NearestCubeForSurf(msurface_t *surf, denvmap_t *envmap, size_t nenvmap) static unsigned int Mod_NearestCubeForSurf(msurface_t *surf, denvmap_t *envmap, size_t nenvmap)
{ //this is slow, yes. { //this is slow, yes.
size_t n, v; size_t n, v;
unsigned int best = ~0; unsigned int best = ~0;
@ -3070,7 +3085,7 @@ unsigned int Mod_NearestCubeForSurf(msurface_t *surf, denvmap_t *envmap, size_t
return best; return best;
} }
int QDECL envmapsort(const void *av, const void *bv) static int QDECL envmapsort(const void *av, const void *bv)
{ //sorts cubemaps in order of size, to make texturearrays easier, if ever. The loader can then just make runs. { //sorts cubemaps in order of size, to make texturearrays easier, if ever. The loader can then just make runs.
const denvmap_t *a=av, *b=bv; const denvmap_t *a=av, *b=bv;
if (a->cubesize == b->cubesize) if (a->cubesize == b->cubesize)
@ -3079,7 +3094,7 @@ int QDECL envmapsort(const void *av, const void *bv)
return 1; return 1;
return -1; return -1;
} }
void Mod_FindCubemaps_f(void) static void Mod_FindCubemaps_f(void)
{ {
struct bspxrw bspctx; struct bspxrw bspctx;
if (Mod_BSPXRW_Read(&bspctx, cl.worldmodel->name)) if (Mod_BSPXRW_Read(&bspctx, cl.worldmodel->name))
@ -3180,13 +3195,27 @@ void Mod_FindCubemaps_f(void)
Z_Free(envmap); Z_Free(envmap);
} }
} }
void Mod_Realign_f(void) static void Mod_Realign_f(void)
{ {
struct bspxrw bspctx; struct bspxrw bspctx;
if (Mod_BSPXRW_Read(&bspctx, cl.worldmodel->name)) if (Mod_BSPXRW_Read(&bspctx, cl.worldmodel->name))
Mod_BSPXRW_Write(&bspctx); Mod_BSPXRW_Write(&bspctx);
} }
void Mod_BSPX_List_f(void) static searchpathfuncs_t *Mod_BSPX_List_ArchiveFile_handle;
static void QDECL Mod_BSPX_List_ArchiveFile(int depth, const char *fname, fsbucket_t *filehandle, void *pathhandle)
{
searchpathfuncs_t *archive = Mod_BSPX_List_ArchiveFile_handle;
flocation_t loc;
time_t mtime;
char timestr[MAX_QPATH], sizestr[MAX_QPATH];
archive->FindFile(archive, &loc, fname, pathhandle);
archive->FileStat(archive, &loc, &mtime);
*timestr = 0;
strftime(timestr,sizeof(timestr), "%Y-%m-%d %H:%M:%S", localtime(&mtime));
Con_Printf("\t\t%20s: %-12s %s\n", fname, FS_AbbreviateSize(sizestr,sizeof(sizestr), loc.len), timestr);
}
static void Mod_BSPX_List_f(void)
{ {
int i; int i;
struct bspxrw ctx; struct bspxrw ctx;
@ -3196,10 +3225,27 @@ void Mod_BSPX_List_f(void)
if (Mod_BSPXRW_Read(&ctx, fname)) if (Mod_BSPXRW_Read(&ctx, fname))
{ {
Con_Printf("%s:\n", fname); Con_Printf("%s:\n", fname);
for (i = 0; i < ctx.corelumps; i++) for (i = 0; i < ctx.totallumps; i++)
Con_Printf("\t%20s: %-12u csum:%08x\n", ctx.lumps[i].lumpname, (unsigned int)ctx.lumps[i].filelen, LittleLong (CalcHashInt(&hash_md4, ctx.lumps[i].data, ctx.lumps[i].filelen))); Con_Printf("\t%20s: %-12"PRIuQOFS" csum:%08x\n", ctx.lumps[i].lumpname, ctx.lumps[i].filelen, LittleLong (CalcHashInt(&hash_md4, ctx.lumps[i].data, ctx.lumps[i].filelen)));
for ( ; i < ctx.totallumps; i++) if (ctx.archivesize)
Con_Printf("\t%20s: %-12u csum:%08x\n", ctx.lumps[i].lumpname, (unsigned int)ctx.lumps[i].filelen, LittleLong (CalcHashInt(&hash_md4, ctx.lumps[i].data, ctx.lumps[i].filelen))); {
searchpathfuncs_t *f;
vfsfile_t *tmp = VFSPIPE_Open(1,true);
if (tmp)
{
VFS_WRITE(tmp, ctx.archivedata, ctx.archivesize);
f = FSZIP_LoadArchive(tmp, NULL, ctx.fname, ctx.fname, NULL);
if (!f)
VFS_CLOSE(tmp);
else
{
Con_Printf("\t%20s: %-12"PRIuQOFS"\n", "archive", ctx.archivesize);
Mod_BSPX_List_ArchiveFile_handle = f;
f->BuildHash(f, 0, Mod_BSPX_List_ArchiveFile);
f->ClosePath(f);
}
}
}
Mod_BSPXRW_Free(&ctx); Mod_BSPXRW_Free(&ctx);
} }
} }
@ -3230,6 +3276,83 @@ void Mod_BSPX_Strip_f(void)
} }
} }
static qbyte *Mod_BSPX_Injest_Read(qofs_t *sz, char *name, char *fnamefmt, ...)
{
va_list argptr;
char fname[MAX_QPATH];
int i;
va_start (argptr, fnamefmt);
if (Q_vsnprintfz (fname,sizeof(fname), fnamefmt,argptr))
*fname = 0;
va_end (argptr);
if (!*fname)
return NULL;
for (i = 2; i < Cmd_Argc(); i++)
{
if (!Q_strcasecmp(Cmd_Argv(i), "all") || !Q_strcasecmp(Cmd_Argv(i), name))
return FS_MallocFile(fname, FS_GAME, sz);
}
Con_Printf("%s not requested\n", name);
return NULL;
}
static void Mod_BSPX_Injest_f(void)
{
qbyte *tmp;
struct bspxrw ctx;
qboolean found = false;
qofs_t sz;
if (Cmd_Argc() <= 2)
Con_Printf("%s FILENAME <all|LUMPNAMELIST>: inserts external supplementary resources into the bsp. "CON_WARNING"REMEMBER TO BACK-UP FIRST!\n", Cmd_Argv(0));
else if (Mod_BSPXRW_Read(&ctx, Cmd_Argv(1)))
{
char noext[MAX_QPATH];
COM_StripExtension(ctx.fname, noext,sizeof(noext));
if (ctx.fg == fg_quake)
{
tmp = Mod_BSPX_Injest_Read(&sz, "lit", "%s.lit", noext);
if (tmp)
{
if (sz == 8+ctx.lumps[LUMP_LIGHTING].filelen*3 && !memcmp(tmp, "QLIT\0x01\x00\x00\x00", 8))
Con_Printf("Injesting sdr lit file\n"), found|=Mod_BSPXRW_SetLump(&ctx, "RGBLIGHTING", tmp+8, sz-8); //ldr
else if (sz == 8+ctx.lumps[LUMP_LIGHTING].filelen*4 && !memcmp(tmp, "QLIT\0x01\x00\x01\x00", 8))
Con_Printf("Injesting hdr lit file\n"), found|=Mod_BSPXRW_SetLump(&ctx, "LIGHTING_E5BGR9", tmp+8, sz-8); //hdr
FS_FreeFile(tmp);
}
tmp = Mod_BSPX_Injest_Read(&sz, "lux", "%s.lux", noext);
if (tmp)
{
if (sz == 8+ctx.lumps[LUMP_LIGHTING].filelen*3 && !memcmp(tmp, "QLIT\0x01\x00\x00\x00", 8))
Con_Printf("Injesting lux file\n"), found|=Mod_BSPXRW_SetLump(&ctx, "LIGHTINGDIR", tmp+8, sz-8);
FS_FreeFile(tmp);
}
tmp = Mod_BSPX_Injest_Read(&sz, "ent", "%s.ent", noext);
if (tmp)
{
if (sz)
Con_Printf("Injesting ent file\n"), found|=Mod_BSPXRW_SetLump(&ctx, "entities", tmp, sz);
FS_FreeFile(tmp);
}
// tmp = Mod_BSPX_Injest_Read(&sz, "vis", "%s.vis", noext);
// tmp = Mod_BSPX_Injest_Read(&sz, "rtlights", "%s.rtlights", noext);
// tmp = Mod_BSPX_Injest_Read(&sz, "way", "%s.way", noext);
//fixme: cubemaps
}
if (found)
Mod_BSPXRW_Write(&ctx);
else
{
Mod_BSPXRW_Free(&ctx);
Con_Printf("%s \"%s\": nothing changed.\n", Cmd_Argv(0), Cmd_Argv(1));
}
}
}
image_t *Mod_CubemapForOrigin(model_t *wmodel, vec3_t org) image_t *Mod_CubemapForOrigin(model_t *wmodel, vec3_t org)
{ {
int i; int i;
@ -3252,4 +3375,13 @@ image_t *Mod_CubemapForOrigin(model_t *wmodel, vec3_t org)
return ret; return ret;
} }
void Mod_BSPX_Init(void)
{
Cmd_AddCommandD("mod_findcubemaps", Mod_FindCubemaps_f, "Scans the entities of a map to find reflection env_cubemap sites and determines the nearest one to each surface.");
Cmd_AddCommandD("mod_realign", Mod_Realign_f, "Reads the named bsp and writes it back out with only alignment changes.");
Cmd_AddCommandD("mod_bspx_list", Mod_BSPX_List_f, "Lists all lumps (and their sizes) in the specified bsp.");
Cmd_AddCommandD("mod_bspx_strip", Mod_BSPX_Strip_f, "Strips a named extension lump from a bsp file.");
Cmd_AddCommandD("mod_bspx_injest", Mod_BSPX_Injest_f, "Injests supplemental files (like .lits) into a new bspx file. "CON_WARNING"REMEMBER TO BACK-UP FIRST!");
}
#endif #endif

View file

@ -80,6 +80,7 @@ qboolean QVM_LoadDLL(vm_t *vm, const char *name, qboolean binroot, void **vmMain
char fname[MAX_OSPATH*2]; char fname[MAX_OSPATH*2];
char gpath[MAX_OSPATH]; char gpath[MAX_OSPATH];
char displaypath[MAX_OSPATH*2];
void *iterator; void *iterator;
dllfunction_t funcs[] = dllfunction_t funcs[] =
@ -102,49 +103,53 @@ qboolean QVM_LoadDLL(vm_t *vm, const char *name, qboolean binroot, void **vmMain
while (!hVM && COM_IteratePaths(&iterator, NULL, 0, gpath, sizeof(gpath))) while (!hVM && COM_IteratePaths(&iterator, NULL, 0, gpath, sizeof(gpath)))
{ {
#ifndef ANDROID #ifndef ANDROID
if (!hVM && FS_NativePath(va("%s_%s_"ARCH_CPU_POSTFIX ARCH_DL_POSTFIX, name, gpath), FS_BINARYPATH, fname, sizeof(fname))) if (!hVM && FS_SystemPath(va("%s_%s_"ARCH_CPU_POSTFIX ARCH_DL_POSTFIX, name, gpath), FS_BINARYPATH, fname, sizeof(fname)))
{ {
Con_DLPrintf(2, "Loading native: %s\n", fname); if (FS_DisplayPath(fname, FS_SYSTEM, displaypath, sizeof(displaypath)))
Con_DLPrintf(2, "Loading native: %s\n", displaypath);
hVM = Sys_LoadLibrary(fname, funcs); hVM = Sys_LoadLibrary(fname, funcs);
} }
#endif #endif
if (!hVM && FS_NativePath(va("%s_%s"ARCH_DL_POSTFIX, name, gpath), FS_BINARYPATH, fname, sizeof(fname))) if (!hVM && FS_SystemPath(va("%s_%s"ARCH_DL_POSTFIX, name, gpath), FS_BINARYPATH, fname, sizeof(fname)))
{ {
Con_DLPrintf(2, "Loading native: %s\n", fname); if (FS_DisplayPath(fname, FS_SYSTEM, displaypath, sizeof(displaypath)))
Con_DLPrintf(2, "Loading native: %s\n", displaypath);
hVM = Sys_LoadLibrary(fname, funcs); hVM = Sys_LoadLibrary(fname, funcs);
} }
#ifndef ANDROID #ifndef ANDROID
if (!hVM && FS_NativePath(va("%s_%s_"ARCH_CPU_POSTFIX ARCH_DL_POSTFIX, name, gpath), FS_ROOT, fname, sizeof(fname))) if (!hVM && FS_SystemPath(va("%s_%s_"ARCH_CPU_POSTFIX ARCH_DL_POSTFIX, name, gpath), FS_ROOT, fname, sizeof(fname)))
{ {
Con_DLPrintf(2, "Loading native: %s\n", fname); if (FS_DisplayPath(fname, FS_SYSTEM, displaypath, sizeof(displaypath)))
Con_DLPrintf(2, "Loading native: %s\n", displaypath);
hVM = Sys_LoadLibrary(fname, funcs); hVM = Sys_LoadLibrary(fname, funcs);
} }
#endif #endif
if (!hVM && FS_NativePath(va("%s_%s"ARCH_DL_POSTFIX, name, gpath), FS_ROOT, fname, sizeof(fname))) if (!hVM && FS_SystemPath(va("%s_%s"ARCH_DL_POSTFIX, name, gpath), FS_ROOT, fname, sizeof(fname)))
{ {
Con_DLPrintf(2, "Loading native: %s\n", fname); if (FS_DisplayPath(fname, FS_SYSTEM, displaypath, sizeof(displaypath)))
Con_DLPrintf(2, "Loading native: %s\n", displaypath);
hVM = Sys_LoadLibrary(fname, funcs); hVM = Sys_LoadLibrary(fname, funcs);
} }
} }
#ifdef ANDROID #ifdef ANDROID
if (!hVM && FS_NativePath(va("%s" ARCH_DL_POSTFIX, name), FS_BINARYPATH, fname, sizeof(fname))) if (!hVM && FS_SystemPath(va("%s" ARCH_DL_POSTFIX, name), FS_BINARYPATH, fname, sizeof(fname)))
hVM = Sys_LoadLibrary(fname, funcs); hVM = Sys_LoadLibrary(fname, funcs);
#else #else
if (!hVM && FS_NativePath(va("%s_"ARCH_CPU_POSTFIX ARCH_DL_POSTFIX, name), FS_BINARYPATH, fname, sizeof(fname))) if (!hVM && FS_SystemPath(va("%s_"ARCH_CPU_POSTFIX ARCH_DL_POSTFIX, name), FS_BINARYPATH, fname, sizeof(fname)))
hVM = Sys_LoadLibrary(fname, funcs); hVM = Sys_LoadLibrary(fname, funcs);
if (!hVM && FS_NativePath(va("%s"ARCH_CPU_POSTFIX ARCH_DL_POSTFIX, name), FS_BINARYPATH, fname, sizeof(fname))) if (!hVM && FS_SystemPath(va("%s"ARCH_CPU_POSTFIX ARCH_DL_POSTFIX, name), FS_BINARYPATH, fname, sizeof(fname)))
hVM = Sys_LoadLibrary(fname, funcs); hVM = Sys_LoadLibrary(fname, funcs);
if (!hVM && FS_NativePath(va("%s" ARCH_DL_POSTFIX, name), FS_BINARYPATH, fname, sizeof(fname))) if (!hVM && FS_SystemPath(va("%s" ARCH_DL_POSTFIX, name), FS_BINARYPATH, fname, sizeof(fname)))
hVM = Sys_LoadLibrary(fname, funcs); hVM = Sys_LoadLibrary(fname, funcs);
if (!hVM && FS_NativePath(va("%s_"ARCH_CPU_POSTFIX ARCH_DL_POSTFIX, name), FS_ROOT, fname, sizeof(fname))) if (!hVM && FS_SystemPath(va("%s_"ARCH_CPU_POSTFIX ARCH_DL_POSTFIX, name), FS_ROOT, fname, sizeof(fname)))
hVM = Sys_LoadLibrary(fname, funcs); hVM = Sys_LoadLibrary(fname, funcs);
if (!hVM && FS_NativePath(va("%s"ARCH_CPU_POSTFIX ARCH_DL_POSTFIX, name), FS_ROOT, fname, sizeof(fname))) if (!hVM && FS_SystemPath(va("%s"ARCH_CPU_POSTFIX ARCH_DL_POSTFIX, name), FS_ROOT, fname, sizeof(fname)))
hVM = Sys_LoadLibrary(fname, funcs); hVM = Sys_LoadLibrary(fname, funcs);
if (!hVM && FS_NativePath(va("%s" ARCH_DL_POSTFIX, name), FS_ROOT, fname, sizeof(fname))) if (!hVM && FS_SystemPath(va("%s" ARCH_DL_POSTFIX, name), FS_ROOT, fname, sizeof(fname)))
hVM = Sys_LoadLibrary(fname, funcs); hVM = Sys_LoadLibrary(fname, funcs);
#endif #endif
} }
@ -160,13 +165,15 @@ qboolean QVM_LoadDLL(vm_t *vm, const char *name, qboolean binroot, void **vmMain
if (!hVM) if (!hVM)
{ {
snprintf (fname, sizeof(fname), "%s%s_"ARCH_CPU_POSTFIX ARCH_DL_POSTFIX, gpath, name); snprintf (fname, sizeof(fname), "%s%s_"ARCH_CPU_POSTFIX ARCH_DL_POSTFIX, gpath, name);
Con_DLPrintf(2, "Loading native: %s\n", fname); if (FS_DisplayPath(fname, FS_SYSTEM, displaypath, sizeof(displaypath)))
Con_DLPrintf(2, "Loading native: %s\n", displaypath);
hVM = Sys_LoadLibrary(fname, funcs); hVM = Sys_LoadLibrary(fname, funcs);
} }
if (!hVM) if (!hVM)
{ {
snprintf (fname, sizeof(fname), "%s%s"ARCH_CPU_POSTFIX ARCH_DL_POSTFIX, gpath, name); snprintf (fname, sizeof(fname), "%s%s"ARCH_CPU_POSTFIX ARCH_DL_POSTFIX, gpath, name);
Con_DLPrintf(2, "Loading native: %s\n", fname); if (FS_DisplayPath(fname, FS_SYSTEM, displaypath, sizeof(displaypath)))
Con_DLPrintf(2, "Loading native: %s\n", displaypath);
hVM = Sys_LoadLibrary(fname, funcs); hVM = Sys_LoadLibrary(fname, funcs);
} }
@ -174,13 +181,15 @@ qboolean QVM_LoadDLL(vm_t *vm, const char *name, qboolean binroot, void **vmMain
if (!hVM) if (!hVM)
{ {
snprintf (fname, sizeof(fname), "%s%s_"ARCH_ALTCPU_POSTFIX ARCH_DL_POSTFIX, gpath, name); snprintf (fname, sizeof(fname), "%s%s_"ARCH_ALTCPU_POSTFIX ARCH_DL_POSTFIX, gpath, name);
Con_DLPrintf(2, "Loading native: %s\n", fname); if (FS_DisplayPath(fname, FS_SYSTEM, displaypath, sizeof(displaypath)))
Con_DLPrintf(2, "Loading native: %s\n", displaypath);
hVM = Sys_LoadLibrary(fname, funcs); hVM = Sys_LoadLibrary(fname, funcs);
} }
if (!hVM) if (!hVM)
{ {
snprintf (fname, sizeof(fname), "%s%s"ARCH_ALTCPU_POSTFIX ARCH_DL_POSTFIX, gpath, name); snprintf (fname, sizeof(fname), "%s%s"ARCH_ALTCPU_POSTFIX ARCH_DL_POSTFIX, gpath, name);
Con_DLPrintf(2, "Loading native: %s\n", fname); if (FS_DisplayPath(fname, FS_SYSTEM, displaypath, sizeof(displaypath)))
Con_DLPrintf(2, "Loading native: %s\n", displaypath);
hVM = Sys_LoadLibrary(fname, funcs); hVM = Sys_LoadLibrary(fname, funcs);
} }
#endif #endif
@ -188,7 +197,8 @@ qboolean QVM_LoadDLL(vm_t *vm, const char *name, qboolean binroot, void **vmMain
if (!hVM) if (!hVM)
{ {
snprintf (fname, sizeof(fname), "%s%s"ARCH_DL_POSTFIX, gpath, name); snprintf (fname, sizeof(fname), "%s%s"ARCH_DL_POSTFIX, gpath, name);
Con_DLPrintf(2, "Loading native: %s\n", fname); if (FS_DisplayPath(fname, FS_SYSTEM, displaypath, sizeof(displaypath)))
Con_DLPrintf(2, "Loading native: %s\n", displaypath);
hVM = Sys_LoadLibrary(fname, funcs); hVM = Sys_LoadLibrary(fname, funcs);
} }
} }

View file

@ -21,7 +21,7 @@ static void QDECL TL_LanguageChanged(struct cvar_s *var, char *oldvalue)
com_language = TL_FindLanguage(var->string); com_language = TL_FindLanguage(var->string);
} }
cvar_t language = CVARAFC("lang", sys_language, "prvm_language", CVAR_USERINFO|CVAR_NORESET/*otherwise gamedir switches will be annoying*/, TL_LanguageChanged); cvar_t language = CVARAFCD("lang", sys_language, "prvm_language", CVAR_USERINFO|CVAR_NORESET/*otherwise gamedir switches will be annoying*/, TL_LanguageChanged, "This cvar contains the language_dialect code of your language, used to find localisation strings.");
void TranslateInit(void) void TranslateInit(void)
{ {

View file

@ -829,6 +829,10 @@ void Memory_Init (void)
mainzone = Hunk_AllocName ( zonesize, "zone" ); mainzone = Hunk_AllocName ( zonesize, "zone" );
Z_ClearZone (mainzone, zonesize); Z_ClearZone (mainzone, zonesize);
#endif #endif
#ifdef MULTITHREAD
Sys_ThreadsInit();
#endif
} }
void Memory_DeInit(void) void Memory_DeInit(void)

View file

@ -1234,6 +1234,13 @@ static void D3D9_SetupViewPortProjection(void)
Matrix4x4_CM_ModelViewMatrixFromAxis(r_refdef.m_view, vpn, vright, vup, r_refdef.vieworg); Matrix4x4_CM_ModelViewMatrixFromAxis(r_refdef.m_view, vpn, vright, vup, r_refdef.vieworg);
d3d9error(IDirect3DDevice9_SetTransform(pD3DDev9, D3DTS_VIEW, (D3DMATRIX*)r_refdef.m_view)); d3d9error(IDirect3DDevice9_SetTransform(pD3DDev9, D3DTS_VIEW, (D3DMATRIX*)r_refdef.m_view));
if (r_xflip.ival)
{
fov_x *= -1;
r_refdef.flipcull ^= SHADER_CULL_FLIP;
fovv_x *= -1;
}
if (r_refdef.maxdist) if (r_refdef.maxdist)
{ {
/*d3d projection matricies scale depth to 0 to 1*/ /*d3d projection matricies scale depth to 0 to 1*/
@ -1258,6 +1265,7 @@ static void (D3D9_R_RenderView) (void)
{ {
if (!r_norefresh.value) if (!r_norefresh.value)
{ {
int cull = r_refdef.flipcull;
Surf_SetupFrame(); Surf_SetupFrame();
if (!r_refdef.globalfog.density) if (!r_refdef.globalfog.density)
@ -1293,13 +1301,14 @@ static void (D3D9_R_RenderView) (void)
R_SetFrustum (r_refdef.m_projection_std, r_refdef.m_view); R_SetFrustum (r_refdef.m_projection_std, r_refdef.m_view);
RQ_BeginFrame(); RQ_BeginFrame();
if (!(r_refdef.flags & RDF_NOWORLDMODEL)) // if (!(r_refdef.flags & RDF_NOWORLDMODEL))
{ // {
if (cl.worldmodel) // if (!r_refdef.recurse && !(r_refdef.flags & RDF_DISABLEPARTICLES))
P_DrawParticles (); // P_DrawParticles ();
} // }
Surf_DrawWorld(); Surf_DrawWorld();
RQ_RenderBatchClear(); RQ_RenderBatchClear();
r_refdef.flipcull = cull;
} }
D3D9_Set2D (); D3D9_Set2D ();
} }

View file

@ -840,7 +840,10 @@ static qboolean initD3D11Device(HWND hWnd, rendererstate_t *info, PFN_D3D11_CREA
Con_Printf("D3D11 Adaptor: %S\n", adesc.Description); Con_Printf("D3D11 Adaptor: %S\n", adesc.Description);
} }
else else
{
adapt = NULL; adapt = NULL;
Con_Printf("D3D11 Adaptor: %s\n", "Unspecified");
}
if (FAILED(func(adapt, drivertype, NULL, flags, if (FAILED(func(adapt, drivertype, NULL, flags,
flevels, sizeof(flevels)/sizeof(flevels[0]), flevels, sizeof(flevels)/sizeof(flevels[0]),
@ -1018,6 +1021,9 @@ static void initD3D11(HWND hWnd, rendererstate_t *info)
Con_Printf("CreateDXGIFactory1 failed: %s\n", D3D_NameForResult(hr)); Con_Printf("CreateDXGIFactory1 failed: %s\n", D3D_NameForResult(hr));
if (fact) if (fact)
{ {
ULONGLONG devid = strtoull(info->subrenderer, NULL, 16);
vrsetup.deviceid[0] = (devid )&0xffffffff;
vrsetup.deviceid[1] = (devid>>32)&0xffffffff;
if (info->vr) if (info->vr)
{ {
if (!info->vr->Prepare(&vrsetup)) if (!info->vr->Prepare(&vrsetup))
@ -1025,7 +1031,9 @@ static void initD3D11(HWND hWnd, rendererstate_t *info)
info->vr->Shutdown(); info->vr->Shutdown();
info->vr = NULL; info->vr = NULL;
} }
else }
if (vrsetup.deviceid[0] || vrsetup.deviceid[1])
{ {
int id = 0; int id = 0;
while (S_OK==IDXGIFactory1_EnumAdapters(fact, id++, &adapt)) while (S_OK==IDXGIFactory1_EnumAdapters(fact, id++, &adapt))
@ -1038,9 +1046,7 @@ static void initD3D11(HWND hWnd, rendererstate_t *info)
adapt = NULL; adapt = NULL;
} }
} }
} else
if (!adapt)
IDXGIFactory1_EnumAdapters(fact, 0, &adapt); IDXGIFactory1_EnumAdapters(fact, 0, &adapt);
} }
} }
@ -1061,6 +1067,54 @@ static void initD3D11(HWND hWnd, rendererstate_t *info)
} }
} }
static qboolean D3D11_VID_EnumerateDevices(void *usercontext, void(*callback)(void *context, const char *devicename, const char *outputname, const char *desc))
{
static dllhandle_t *dxgi;
static HRESULT (WINAPI *pCreateDXGIFactory1)(IID *riid, void **ppFactory);
static IID factiid = {0x770aae78, 0xf26f, 0x4dba, {0xa8, 0x29, 0x25, 0x3c, 0x83, 0xd1, 0xb3, 0x87}};
IDXGIFactory1 *fact = NULL;
dllfunction_t dxgifuncs[] =
{
{(void**)&pCreateDXGIFactory1, "CreateDXGIFactory1"},
{NULL}
};
if (!dxgi)
dxgi = Sys_LoadLibrary("dxgi", dxgifuncs);
if (!dxgi)
return true;
if (pCreateDXGIFactory1)
{
HRESULT hr;
hr = pCreateDXGIFactory1(&factiid, (void**)&fact);
if (FAILED(hr))
Con_Printf("CreateDXGIFactory1 failed: %s\n", D3D_NameForResult(hr));
if (fact)
{
IDXGIAdapter *adapt = NULL;
int id = 0;
char devname[128*4];
char dev[128*4];
DXGI_ADAPTER_DESC desc;
while (S_OK==IDXGIFactory1_EnumAdapters(fact, id++, &adapt))
{
IDXGIAdapter_GetDesc(adapt, &desc);
Q_snprintfz(devname,sizeof(devname), "Direct3D11 - %s", narrowen(dev,sizeof(dev), desc.Description));
Q_snprintfz(dev,sizeof(dev), "%"PRIx64, ((ULONGLONG)desc.AdapterLuid.HighPart<<32)|desc.AdapterLuid.LowPart);
callback(usercontext, dev, ""/*FIXME*/, devname);
IDXGIAdapter_Release(adapt);
adapt = NULL;
}
IDXGIFactory1_Release(fact);
}
}
return true;
}
static qboolean D3D11_VID_Init(rendererstate_t *info, unsigned char *palette) static qboolean D3D11_VID_Init(rendererstate_t *info, unsigned char *palette)
{ {
DWORD width = info->width; DWORD width = info->width;
@ -1556,18 +1610,19 @@ static void D3D11_SetupViewPort(void)
fovv_y *= 1 + (((sin(cl.time * 3.0) + 1) * 0.015) * r_waterwarp.value); fovv_y *= 1 + (((sin(cl.time * 3.0) + 1) * 0.015) * r_waterwarp.value);
} }
if (r_xflip.ival)
{
fov_x *= -1;
r_refdef.flipcull ^= SHADER_CULL_FLIP;
fovv_x *= -1;
}
/*view matrix*/ /*view matrix*/
Matrix4x4_CM_ModelViewMatrixFromAxis(r_refdef.m_view, vpn, vright, vup, r_refdef.vieworg); Matrix4x4_CM_ModelViewMatrixFromAxis(r_refdef.m_view, vpn, vright, vup, r_refdef.vieworg);
if (r_refdef.maxdist)
{ /*projection matricies (main game, and viewmodel)*/
Matrix4x4_CM_Projection_Far(r_refdef.m_projection_std, fov_x, fov_y, r_refdef.mindist, r_refdef.maxdist, false); Matrix4x4_CM_Projection_Offset(r_refdef.m_projection_std, -fov_x/2, fov_x/2, -fov_y/2, fov_y/2, r_refdef.mindist, r_refdef.maxdist, true);
Matrix4x4_CM_Projection_Far(r_refdef.m_projection_view, fovv_x, fovv_y, r_refdef.mindist, r_refdef.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, r_refdef.maxdist, true);
}
else
{
Matrix4x4_CM_Projection_Inf(r_refdef.m_projection_std, fov_x, fov_y, r_refdef.mindist, false);
Matrix4x4_CM_Projection_Inf(r_refdef.m_projection_view, fovv_x, fovv_y, r_refdef.mindist, false);
}
} }
static void (D3D11_R_RenderView) (void) static void (D3D11_R_RenderView) (void)
@ -1575,6 +1630,7 @@ static void (D3D11_R_RenderView) (void)
float x, x2, y, y2; float x, x2, y, y2;
double time1 = 0, time2 = 0; double time1 = 0, time2 = 0;
qboolean dofbo = *r_refdef.rt_destcolour[0].texname || *r_refdef.rt_depth.texname; qboolean dofbo = *r_refdef.rt_destcolour[0].texname || *r_refdef.rt_depth.texname;
int cull = r_refdef.flipcull;
// texid_t colourrt[1]; // texid_t colourrt[1];
if (!r_norefresh.value) if (!r_norefresh.value)
@ -1623,11 +1679,6 @@ static void (D3D11_R_RenderView) (void)
R_SetFrustum (r_refdef.m_projection_std, r_refdef.m_view); R_SetFrustum (r_refdef.m_projection_std, r_refdef.m_view);
RQ_BeginFrame(); RQ_BeginFrame();
// if (!(r_refdef.flags & Q2RDF_NOWORLDMODEL))
// {
// if (cl.worldmodel)
// P_DrawParticles ();
// }
if (!(r_refdef.flags & RDF_NOWORLDMODEL)) if (!(r_refdef.flags & RDF_NOWORLDMODEL))
if (!r_worldentity.model || r_worldentity.model->loadstate != MLS_LOADED || !cl.worldmodel) if (!r_worldentity.model || r_worldentity.model->loadstate != MLS_LOADED || !cl.worldmodel)
@ -1637,13 +1688,21 @@ static void (D3D11_R_RenderView) (void)
R2D_FillBlock(r_refdef.vrect.x, r_refdef.vrect.y, r_refdef.vrect.width, r_refdef.vrect.height); R2D_FillBlock(r_refdef.vrect.x, r_refdef.vrect.y, r_refdef.vrect.width, r_refdef.vrect.height);
R2D_ImageColours(1, 1, 1, 1); R2D_ImageColours(1, 1, 1, 1);
r_refdef.flipcull = cull;
if (dofbo) if (dofbo)
D3D11_ApplyRenderTargets(false); D3D11_ApplyRenderTargets(false);
return; return;
} }
// if (!(r_refdef.flags & RDF_NOWORLDMODEL))
// {
// if (!r_refdef.recurse && !(r_refdef.flags & RDF_DISABLEPARTICLES))
// P_DrawParticles ();
// }
Surf_DrawWorld(); Surf_DrawWorld();
RQ_RenderBatchClear(); RQ_RenderBatchClear();
r_refdef.flipcull = cull;
if (r_speeds.ival) if (r_speeds.ival)
{ {
time2 = Sys_DoubleTime(); time2 = Sys_DoubleTime();
@ -1739,6 +1798,9 @@ rendererinfo_t d3d11rendererinfo =
D3D11BE_RenderToTextureUpdate2d, D3D11BE_RenderToTextureUpdate2d,
"no more" "no more",
NULL, //VID_GetPriority
NULL, //VID_EnumerateVideoModes
D3D11_VID_EnumerateDevices
}; };
#endif #endif

View file

@ -37,14 +37,14 @@ typedef struct
extern cvar_t gl_part_flame, r_fullbrightSkins, r_fb_models, ruleset_allow_fbmodels; extern cvar_t gl_part_flame, r_fullbrightSkins, r_fb_models, ruleset_allow_fbmodels, gl_overbright_models;
extern cvar_t r_noaliasshadows; extern cvar_t r_noaliasshadows;
extern cvar_t r_lodscale, r_lodbias; extern cvar_t r_lodscale, r_lodbias;
extern cvar_t gl_ati_truform; extern cvar_t gl_ati_truform;
extern cvar_t r_vertexdlights; extern cvar_t r_vertexdlights;
extern cvar_t mod_md3flags; extern cvar_t mod_md3flags;
extern cvar_t r_skin_overlays; //extern cvar_t r_skin_overlays;
extern cvar_t r_globalskin_first, r_globalskin_count; extern cvar_t r_globalskin_first, r_globalskin_count;
#ifndef SERVERONLY #ifndef SERVERONLY
@ -1373,25 +1373,27 @@ qboolean R_CalcModelLighting(entity_t *e, model_t *clmodel)
return e->light_known-1; return e->light_known-1;
e->light_dir[0] = 0; e->light_dir[1] = 1; e->light_dir[2] = 0; e->light_dir[0] = 0; e->light_dir[1] = 1; e->light_dir[2] = 0;
if ((clmodel->engineflags & MDLF_FLAME) || r_fullbright.ival)
{
e->light_avg[0] = e->light_avg[1] = e->light_avg[2] = 1;
e->light_range[0] = e->light_range[1] = e->light_range[2] = 0;
e->light_known = 2;
return e->light_known-1;
}
if (
#ifdef HEXEN2 #ifdef HEXEN2
(e->drawflags & MLS_MASK) == MLS_FULLBRIGHT || if ((e->drawflags & MLS_MASK) == MLS_ABSLIGHT)
#endif { //per-entity fixed lighting
(e->flags & RF_FULLBRIGHT)) e->light_range[0] = e->light_range[1] = e->light_range[2] =
{ e->light_avg[0] = e->light_avg[1] = e->light_avg[2] = e->abslight/255.f;
e->light_avg[0] = e->light_avg[1] = e->light_avg[2] = 1;
e->light_range[0] = e->light_range[1] = e->light_range[2] = 0;
e->light_known = 2; e->light_known = 2;
return e->light_known-1; return e->light_known-1;
} }
if (r_fb_models.ival == 1 && ruleset_allow_fbmodels.ival && (clmodel->engineflags & MDLF_EZQUAKEFBCHEAT) && cls.protocol == CP_QUAKEWORLD && cl.deathmatch) if ((e->drawflags & MLS_MASK) && (e->drawflags & MLS_MASK) != MLS_ADDLIGHT)
{ //these use some qc-defined lightstyles.
i = 24 + (e->drawflags & MLS_MASK); //saves knowing the proper patterns at least.
VectorScale(cl_lightstyle[i].colours, d_lightstylevalue[i]/255.f, e->light_range);
VectorScale(cl_lightstyle[i].colours, d_lightstylevalue[i]/255.f, e->light_avg);
e->light_known = 2;
return e->light_known-1;
}
#endif
if ((clmodel->engineflags & MDLF_FLAME) || //stuff on fire should generally have enough light...
r_fullbright.ival || //vanila cheat
(e->flags & RF_FULLBRIGHT) || //DP feature
(r_fb_models.ival == 1 && ruleset_allow_fbmodels.ival && (clmodel->engineflags & MDLF_EZQUAKEFBCHEAT) && cls.protocol == CP_QUAKEWORLD && cl.deathmatch)) //ezquake cheat
{ {
e->light_avg[0] = e->light_avg[1] = e->light_avg[2] = 1; e->light_avg[0] = e->light_avg[1] = e->light_avg[2] = 1;
e->light_range[0] = e->light_range[1] = e->light_range[2] = 0; e->light_range[0] = e->light_range[1] = e->light_range[2] = 0;
@ -1432,12 +1434,15 @@ qboolean R_CalcModelLighting(entity_t *e, model_t *clmodel)
} }
#ifdef HEXEN2 #ifdef HEXEN2
if ((e->drawflags & MLS_MASK) == MLS_ABSLIGHT) if ((e->drawflags & MLS_MASK) == MLS_ADDLIGHT)
{ {
shadelight[0] = shadelight[1] = shadelight[2] = e->abslight; ambientlight[0] += e->abslight;
ambientlight[0] = ambientlight[1] = ambientlight[2] = e->abslight; ambientlight[1] += e->abslight;
ambientlight[2] += e->abslight;
shadelight[0] += e->abslight;
shadelight[1] += e->abslight;
shadelight[2] += e->abslight;
} }
else
#endif #endif
if (r_softwarebanding) if (r_softwarebanding)
@ -1445,8 +1450,8 @@ qboolean R_CalcModelLighting(entity_t *e, model_t *clmodel)
//mimic software rendering as closely as possible //mimic software rendering as closely as possible
lightdir[2] = 0; //horizontal light only. lightdir[2] = 0; //horizontal light only.
VectorMA(vec3_origin, 0.5, shadelight, ambientlight); // VectorMA(vec3_origin, 0.5, shadelight, ambientlight);
VectorCopy(ambientlight, shadelight); // VectorCopy(ambientlight, shadelight);
if (!r_vertexdlights.ival && r_dynamic.ival > 0) if (!r_vertexdlights.ival && r_dynamic.ival > 0)
{ {
@ -1495,17 +1500,6 @@ qboolean R_CalcModelLighting(entity_t *e, model_t *clmodel)
} }
else 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) if (!r_vertexdlights.ival && r_dynamic.ival > 0)
{ {
float *org = e->origin; float *org = e->origin;
@ -1621,6 +1615,20 @@ qboolean R_CalcModelLighting(entity_t *e, model_t *clmodel)
} }
#if 1 //match quakespasm here.
if (gl_overbright_models.value > 0.f && ruleset_allow_fbmodels.ival)
{
m = (96*6) / (shadelight[0]+shadelight[1]+shadelight[2]+ambientlight[0]+ambientlight[1]+ambientlight[2]);
if (m > 1.0)
m = 1; //we only want to let it darken here.
m *= 1 + min(1,gl_overbright_models.value);
}
else
m = 1;
m /= 200.0/255; //a legacy quake fudge-factor.
VectorScale(shadelight, m, shadelight);
VectorScale(ambientlight, m, ambientlight);
#else
for (i = 0; i < 3; i++) for (i = 0; i < 3; i++)
{ {
if (ambientlight[i] > 128) if (ambientlight[i] > 128)
@ -1629,6 +1637,7 @@ qboolean R_CalcModelLighting(entity_t *e, model_t *clmodel)
shadelight[i] /= 200.0/255; shadelight[i] /= 200.0/255;
ambientlight[i] /= 200.0/255; ambientlight[i] /= 200.0/255;
} }
#endif
if ((e->model->flags & MF_ROTATE) && cl.hexen2pickups) if ((e->model->flags & MF_ROTATE) && cl.hexen2pickups)
{ {
@ -1675,6 +1684,11 @@ qboolean R_CalcModelLighting(entity_t *e, model_t *clmodel)
VectorScale(ambientlight, 2, e->light_avg); VectorScale(ambientlight, 2, e->light_avg);
VectorScale(shadelight, 2, e->light_range); VectorScale(shadelight, 2, e->light_range);
} }
else if (1)
{ //calculate average and range, to allow for negative lighting dotproducts
VectorCopy(shadelight, e->light_avg);
VectorCopy(ambientlight, e->light_range);
}
else else
{ //calculate average and range, to allow for negative lighting dotproducts { //calculate average and range, to allow for negative lighting dotproducts
VectorMA(ambientlight, 0.5, shadelight, e->light_avg); VectorMA(ambientlight, 0.5, shadelight, e->light_avg);

View file

@ -221,8 +221,6 @@ static void BE_PrintDrawCall(const char *msg)
{ {
char shadername[512]; char shadername[512];
char modelname[512]; char modelname[512];
int num;
Q_snprintfz(shadername, sizeof(shadername), "^[%-16s\\tipimg\\%s\\tipimgtype\\%i\\tip\\%s^]", Q_snprintfz(shadername, sizeof(shadername), "^[%-16s\\tipimg\\%s\\tipimgtype\\%i\\tip\\%s^]",
shaderstate.curshader->name, shaderstate.curshader->name,
shaderstate.curshader->name,shaderstate.curshader->usageflags, shaderstate.curshader->name,shaderstate.curshader->usageflags,
@ -230,7 +228,9 @@ static void BE_PrintDrawCall(const char *msg)
if (shaderstate.curbatch && shaderstate.curbatch->ent) if (shaderstate.curbatch && shaderstate.curbatch->ent)
{ {
num = shaderstate.curbatch->ent->keynum; #ifdef HAVE_SERVER
int num = shaderstate.curbatch->ent->keynum;
#endif
if (shaderstate.curbatch->ent->model) if (shaderstate.curbatch->ent->model)
Q_snprintfz(modelname, sizeof(modelname), " - ^[%s\\modelviewer\\%s^]", Q_snprintfz(modelname, sizeof(modelname), " - ^[%s\\modelviewer\\%s^]",
shaderstate.curbatch->ent->model->name, shaderstate.curbatch->ent->model->name); shaderstate.curbatch->ent->model->name, shaderstate.curbatch->ent->model->name);

View file

@ -2615,6 +2615,11 @@ struct font_s *Font_LoadFont(const char *fontfilename, float vheight, float scal
success = false; success = false;
if (!success && !TEXLOADED(f->singletexture) && *start) if (!success && !TEXLOADED(f->singletexture) && *start)
{
const char *ext = COM_GetFileExtension(start, NULL);
if (!Q_strcasecmp(ext, ".ttf") || !Q_strcasecmp(ext, ".otf"))
; //no, don't try loading it as an image-based font. just let it fail.
else
{ {
f->singletexture = R_LoadHiResTexture(start, "fonts:charsets", IF_PREMULTIPLYALPHA|(r_font_linear.ival?IF_LINEAR:IF_NEAREST)|IF_UIPIC|IF_NOPICMIP|IF_NOMIPMAP|IF_NOPURGE|IF_LOADNOW); f->singletexture = R_LoadHiResTexture(start, "fonts:charsets", IF_PREMULTIPLYALPHA|(r_font_linear.ival?IF_LINEAR:IF_NEAREST)|IF_UIPIC|IF_NOPICMIP|IF_NOMIPMAP|IF_NOPURGE|IF_LOADNOW);
if (f->singletexture->status == TEX_LOADING) if (f->singletexture->status == TEX_LOADING)
@ -2623,6 +2628,7 @@ struct font_s *Font_LoadFont(const char *fontfilename, float vheight, float scal
if (!TEXLOADED(f->singletexture) && f->faces < MAX_FACES) if (!TEXLOADED(f->singletexture) && f->faces < MAX_FACES)
Font_LoadFontLump(f, start); Font_LoadFontLump(f, start);
} }
}
if (end) if (end)
{ {

View file

@ -86,22 +86,18 @@ void validatelinks2(link_t *firstnode, link_t *panic)
} }
#ifndef SERVERONLY
static void ted_dorelight(model_t *m, heightmap_t *hm);
static void Terr_WorkerLoadedSectionLightmap(void *ctx, void *data, size_t a, size_t b);
static qboolean Terr_Collect(heightmap_t *hm);
#endif
static hmsection_t *QDECL Terr_GetSection(heightmap_t *hm, int x, int y, unsigned int flags); static hmsection_t *QDECL Terr_GetSection(heightmap_t *hm, int x, int y, unsigned int flags);
static void Terr_LoadSectionWorker(void *ctx, void *data, size_t a, size_t b); static void Terr_LoadSectionWorker(void *ctx, void *data, size_t a, size_t b);
static void Terr_WorkerLoadedSection(void *ctx, void *data, size_t a, size_t b); static void Terr_WorkerLoadedSection(void *ctx, void *data, size_t a, size_t b);
static void Terr_WorkerFailedSection(void *ctx, void *data, size_t a, size_t b); static void Terr_WorkerFailedSection(void *ctx, void *data, size_t a, size_t b);
static void Terr_Brush_DeleteIdx(heightmap_t *hm, size_t idx); static void Terr_Brush_DeleteIdx(heightmap_t *hm, size_t idx);
#ifndef SERVERONLY #ifdef HAVE_CLIENT
static void ted_dorelight(model_t *m, heightmap_t *hm);
static void Terr_WorkerLoadedSectionLightmap(void *ctx, void *data, size_t a, size_t b);
static qboolean Terr_Collect(heightmap_t *hm);
static void Terr_Brush_Draw(heightmap_t *hm, batch_t **batches, entity_t *e); static void Terr_Brush_Draw(heightmap_t *hm, batch_t **batches, entity_t *e);
#endif
#ifndef SERVERONLY
static texid_t Terr_LoadTexture(char *name) static texid_t Terr_LoadTexture(char *name)
{ {
extern texid_t missing_texture; extern texid_t missing_texture;
@ -121,9 +117,9 @@ static texid_t Terr_LoadTexture(char *name)
} }
#endif #endif
static void QDECL Terr_LoadSectionTextures(hmsection_t *s) static void Terr_LoadSectionTextures(hmsection_t *s)
{ {
#ifndef SERVERONLY #ifdef HAVE_CLIENT
extern texid_t missing_texture; extern texid_t missing_texture;
struct hmwater_s *w; struct hmwater_s *w;
if (isDedicated) if (isDedicated)
@ -161,7 +157,7 @@ static void QDECL Terr_LoadSectionTextures(hmsection_t *s)
static qboolean QDECL Terr_InitLightmap(hmsection_t *s, qboolean initialise) static qboolean QDECL Terr_InitLightmap(hmsection_t *s, qboolean initialise)
{ {
#ifdef SERVERONLY #ifndef HAVE_CLIENT
return false; return false;
#else #else
heightmap_t *hm = s->hmmod; heightmap_t *hm = s->hmmod;
@ -283,7 +279,7 @@ static char *Terr_DiskSectionName(heightmap_t *hm, int sx, int sy, char *out, si
Q_snprintfz(out, outsize, "maps/%s/sect_%03x_%03x.hms", hm->path, sx, sy); Q_snprintfz(out, outsize, "maps/%s/sect_%03x_%03x.hms", hm->path, sx, sy);
return out; return out;
} }
#ifndef SERVERONLY #ifdef HAVE_CLIENT
static char *Terr_TempDiskSectionName(heightmap_t *hm, int sx, int sy) static char *Terr_TempDiskSectionName(heightmap_t *hm, int sx, int sy)
{ {
sx -= CHUNKBIAS; sx -= CHUNKBIAS;
@ -295,6 +291,7 @@ static char *Terr_TempDiskSectionName(heightmap_t *hm, int sx, int sy)
} }
#endif #endif
#ifdef HAVE_SERVER
static int dehex_e(int i, qboolean *error) static int dehex_e(int i, qboolean *error)
{ {
if (i >= '0' && i <= '9') if (i >= '0' && i <= '9')
@ -357,6 +354,7 @@ static qboolean Terr_IsSectionFName(heightmap_t *hm, const char *fname, int *sx,
return false; return false;
return true; return true;
} }
#endif
static int QDECL Terr_GenerateSections(heightmap_t *hm, int sx, int sy, int count, hmsection_t **sects) static int QDECL Terr_GenerateSections(heightmap_t *hm, int sx, int sy, int count, hmsection_t **sects)
{ {
@ -381,7 +379,7 @@ static int QDECL Terr_GenerateSections(heightmap_t *hm, int sx, int sy, int coun
{ {
s = Z_Malloc(sizeof(*s)); s = Z_Malloc(sizeof(*s));
s->loadstate = TSLS_LOADING0; s->loadstate = TSLS_LOADING0;
#ifndef SERVERONLY #ifdef HAVE_CLIENT
s->lightmap = -1; s->lightmap = -1;
#endif #endif
s->numents = 0; s->numents = 0;
@ -395,7 +393,7 @@ static int QDECL Terr_GenerateSections(heightmap_t *hm, int sx, int sy, int coun
hm->loadingsections+=1; hm->loadingsections+=1;
} }
#ifndef SERVERONLY #ifdef HAVE_CLIENT
else if (s->loadstate == TSLS_LOADED && s->lightmap < 0) else if (s->loadstate == TSLS_LOADED && s->lightmap < 0)
; //it lost its lightmap. the main thread won't be drawing with it, nor do any loaders. ; //it lost its lightmap. the main thread won't be drawing with it, nor do any loaders.
//FIXME: might be used by tracelines on a worker (eg lightmap generation) //FIXME: might be used by tracelines on a worker (eg lightmap generation)
@ -438,11 +436,8 @@ static hmsection_t *QDECL Terr_GenerateSection(heightmap_t *hm, int sx, int sy,
#endif #endif
return NULL; return NULL;
} }
#ifndef SERVERONLY #ifdef HAVE_CLIENT
s->lightmap = -1; s->lightmap = -1;
#endif
#ifndef SERVERONLY
s->numents = 0; s->numents = 0;
#endif #endif
@ -508,7 +503,7 @@ static void *QDECL Terr_GenerateWater(hmsection_t *s, float maxheight)
//embeds a mesh //embeds a mesh
static void QDECL Terr_AddMesh(heightmap_t *hm, int loadflags, model_t *mod, const char *modelname, vec3_t epos, vec3_t axis[3], float scale) static void QDECL Terr_AddMesh(heightmap_t *hm, int loadflags, model_t *mod, const char *modelname, vec3_t epos, vec3_t axis[3], float scale)
{ {
#ifndef SERVERONLY #ifdef HAVE_CLIENT
struct hmentity_s *e, *f = NULL; struct hmentity_s *e, *f = NULL;
hmsection_t *s; hmsection_t *s;
int min[2], max[2], coord[2]; int min[2], max[2], coord[2];
@ -639,7 +634,7 @@ static void QDECL Terr_AddMesh(heightmap_t *hm, int loadflags, model_t *mod, con
static void *Terr_ReadV1(heightmap_t *hm, hmsection_t *s, void *ptr, int len) static void *Terr_ReadV1(heightmap_t *hm, hmsection_t *s, void *ptr, int len)
{ {
#ifndef SERVERONLY #ifdef HAVE_CLIENT
dsmesh_v1_t *dm; dsmesh_v1_t *dm;
float *colours; float *colours;
qbyte *lmstart; qbyte *lmstart;
@ -670,7 +665,7 @@ static void *Terr_ReadV1(heightmap_t *hm, hmsection_t *s, void *ptr, int len)
ptr = ds+1; ptr = ds+1;
#ifndef SERVERONLY #ifdef HAVE_CLIENT
/*deal with textures*/ /*deal with textures*/
Q_strncpyz(s->texname[0], ds->texname[0], sizeof(s->texname[0])); Q_strncpyz(s->texname[0], ds->texname[0], sizeof(s->texname[0]));
Q_strncpyz(s->texname[1], ds->texname[1], sizeof(s->texname[1])); Q_strncpyz(s->texname[1], ds->texname[1], sizeof(s->texname[1]));
@ -760,7 +755,7 @@ static char *Terr_Read_String(struct terrstream_s *strm, char *val, int maxlen)
strm->pos += len+1; strm->pos += len+1;
return val; return val;
} }
#ifndef SERVERONLY #ifdef HAVE_CLIENT
static void Terr_Write_SInt(struct terrstream_s *strm, int val) static void Terr_Write_SInt(struct terrstream_s *strm, int val)
{ {
val = LittleLong(val); val = LittleLong(val);
@ -998,7 +993,7 @@ static void Terr_SaveV2(heightmap_t *hm, hmsection_t *s, vfsfile_t *f, int sx, i
VFS_WRITE(f, strm.buffer, strm.pos); VFS_WRITE(f, strm.buffer, strm.pos);
strm.pos = 0; strm.pos = 0;
} }
#ifndef SERVERONLY #ifdef HAVE_CLIENT
static void Terr_WorkerLoadedSectionLightmap(void *ctx, void *data, size_t a, size_t b) static void Terr_WorkerLoadedSectionLightmap(void *ctx, void *data, size_t a, size_t b)
{ {
heightmap_t *hm = ctx; heightmap_t *hm = ctx;
@ -1027,7 +1022,7 @@ static void Terr_WorkerLoadedSectionLightmap(void *ctx, void *data, size_t a, si
#endif #endif
static void *Terr_ReadV2(heightmap_t *hm, hmsection_t *s, void *ptr, int len) static void *Terr_ReadV2(heightmap_t *hm, hmsection_t *s, void *ptr, int len)
{ {
#ifndef SERVERONLY #ifdef HAVE_CLIENT
char modelname[MAX_QPATH]; char modelname[MAX_QPATH];
qbyte last; qbyte last;
int y; int y;
@ -1100,7 +1095,7 @@ static void *Terr_ReadV2(heightmap_t *hm, hmsection_t *s, void *ptr, int len)
//dedicated server can stop reading here. //dedicated server can stop reading here.
#ifndef SERVERONLY #ifdef HAVE_CLIENT
if (flags & TSF_HASCOLOURS) if (flags & TSF_HASCOLOURS)
{ {
for (i = 0; i < SECTHEIGHTSIZE*SECTHEIGHTSIZE; i++) for (i = 0; i < SECTHEIGHTSIZE*SECTHEIGHTSIZE; i++)
@ -1226,7 +1221,7 @@ static void Terr_GenerateDefault(heightmap_t *hm, hmsection_t *s)
memset(s->holes, 0, sizeof(s->holes)); memset(s->holes, 0, sizeof(s->holes));
#ifndef SERVERONLY #ifdef HAVE_CLIENT
Q_strncpyz(s->texname[0], "", sizeof(s->texname[0])); Q_strncpyz(s->texname[0], "", sizeof(s->texname[0]));
Q_strncpyz(s->texname[1], "", sizeof(s->texname[1])); Q_strncpyz(s->texname[1], "", sizeof(s->texname[1]));
Q_strncpyz(s->texname[2], "", sizeof(s->texname[2])); Q_strncpyz(s->texname[2], "", sizeof(s->texname[2]));
@ -1416,7 +1411,7 @@ static hmsection_t *Terr_ReadSection(heightmap_t *hm, hmsection_t *s, int ver, v
return s; return s;
} }
#ifndef SERVERONLY #ifdef HAVE_CLIENT
qboolean Terr_DownloadedSection(char *fname) qboolean Terr_DownloadedSection(char *fname)
{ {
/* /*
@ -1450,7 +1445,7 @@ qboolean Terr_DownloadedSection(char *fname)
} }
#endif #endif
#ifndef SERVERONLY #ifdef HAVE_CLIENT
static void Terr_LoadSection(heightmap_t *hm, hmsection_t *s, int sx, int sy, unsigned int flags) static void Terr_LoadSection(heightmap_t *hm, hmsection_t *s, int sx, int sy, unsigned int flags)
{ {
//when using networked terrain, the client will never load a section from disk, but will only load it from the server //when using networked terrain, the client will never load a section from disk, but will only load it from the server
@ -1561,7 +1556,7 @@ static void Terr_LoadSectionWorker(void *ctx, void *data, size_t a, size_t b)
Terr_ReadSection(hm, s, 0, NULL, 0); Terr_ReadSection(hm, s, 0, NULL, 0);
} }
#ifndef SERVERONLY #ifdef HAVE_CLIENT
static void Terr_SaveV1(heightmap_t *hm, hmsection_t *s, vfsfile_t *f, int sx, int sy) static void Terr_SaveV1(heightmap_t *hm, hmsection_t *s, vfsfile_t *f, int sx, int sy)
{ {
int i; int i;
@ -1681,7 +1676,7 @@ static void Terr_Save(heightmap_t *hm, hmsection_t *s, vfsfile_t *f, int sx, int
//doesn't clear edited/dirty flags or anything //doesn't clear edited/dirty flags or anything
static qboolean Terr_SaveSection(heightmap_t *hm, hmsection_t *s, int sx, int sy, qboolean blocksave) static qboolean Terr_SaveSection(heightmap_t *hm, hmsection_t *s, int sx, int sy, qboolean blocksave)
{ {
#ifdef SERVERONLY #ifndef HAVE_CLIENT
return true; return true;
#else #else
vfsfile_t *f; vfsfile_t *f;
@ -1804,7 +1799,7 @@ static hmsection_t *QDECL Terr_GetSection(heightmap_t *hm, int x, int y, unsigne
section = Terr_GenerateSection(hm, x, y, true); section = Terr_GenerateSection(hm, x, y, true);
} }
} }
#ifndef SERVERONLY #ifdef HAVE_CLIENT
//when using networked terrain, the client will never load a section from disk, but only loading it from the server //when using networked terrain, the client will never load a section from disk, but only loading it from the server
//this means we need to send a new request to download the section if it was flagged as modified. //this means we need to send a new request to download the section if it was flagged as modified.
if (!(flags & TGS_NODOWNLOAD)) if (!(flags & TGS_NODOWNLOAD))
@ -1893,7 +1888,7 @@ int Heightmap_Save(heightmap_t *hm)
return sectionssaved; return sectionssaved;
} }
#ifndef CLIENTONLY #ifdef HAVE_SERVER
//on servers, we can get requests to download current map sections. if so, give them it. //on servers, we can get requests to download current map sections. if so, give them it.
qboolean Terrain_LocateSection(const char *name, flocation_t *loc) qboolean Terrain_LocateSection(const char *name, flocation_t *loc)
{ {
@ -1958,7 +1953,7 @@ void Terr_DestroySection(heightmap_t *hm, hmsection_t *s, qboolean lightmapreusa
Terr_ClearSection(s); Terr_ClearSection(s);
#ifndef SERVERONLY #ifdef HAVE_CLIENT
if (s->lightmap >= 0) if (s->lightmap >= 0)
{ {
struct lmsect_s *lms; struct lmsect_s *lms;
@ -2014,14 +2009,14 @@ void Terr_DestroySection(heightmap_t *hm, hmsection_t *s, qboolean lightmapreusa
validatelinks(&hm->recycle); validatelinks(&hm->recycle);
} }
#ifndef SERVERONLY #ifdef HAVE_CLIENT
//dedicated servers do not support editing. no lightmap info causes problems. //dedicated servers do not support editing. no lightmap info causes problems.
//when a terrain section has the notify flag set on the server, the server needs to go through and set out notifications to replicate it to the various clients //when a terrain section has the notify flag set on the server, the server needs to go through and set out notifications to replicate it to the various clients
//so the clients know to re-download the section. //so the clients know to re-download the section.
static void Terr_DoEditNotify(heightmap_t *hm) static void Terr_DoEditNotify(heightmap_t *hm)
{ {
#ifndef CLIENTONLY #ifdef HAVE_SERVER
int i; int i;
char *cmd; char *cmd;
hmsection_t *s; hmsection_t *s;
@ -2141,7 +2136,7 @@ validatelinks(&hm->recycle);
else if (lightmapsonly) else if (lightmapsonly)
{ {
numremaining++; numremaining++;
#ifndef SERVERONLY #ifdef HAVE_CLIENT
s->lightmap = -1; s->lightmap = -1;
#endif #endif
} }
@ -2160,7 +2155,7 @@ validatelinks(&hm->recycle);
} }
} }
validatelinks(&hm->recycle); validatelinks(&hm->recycle);
#ifndef SERVERONLY #ifdef HAVE_CLIENT
if (!lightmapreusable) if (!lightmapreusable)
{ {
while (hm->unusedlmsects) while (hm->unusedlmsects)
@ -2196,7 +2191,7 @@ void Terr_FreeModel(model_t *mod)
while(hm->brushtextures) while(hm->brushtextures)
{ {
brushtex_t *bt = hm->brushtextures; brushtex_t *bt = hm->brushtextures;
#ifndef SERVERONLY #ifdef HAVE_CLIENT
brushbatch_t *bb; brushbatch_t *bb;
while((bb = bt->batches)) while((bb = bt->batches))
{ {
@ -2211,7 +2206,7 @@ void Terr_FreeModel(model_t *mod)
} }
#ifdef RUNTIMELIGHTING #ifdef RUNTIMELIGHTING
if (hm->relightcontext) if (hm->relightcontext)
LightShutdown(hm->relightcontext); LightShutdown(hm->relightcontext, mod);
if (hm->lightthreadmem && !hm->inheritedlightthreadmem) if (hm->lightthreadmem && !hm->inheritedlightthreadmem)
BZ_Free(hm->lightthreadmem); BZ_Free(hm->lightthreadmem);
#endif #endif
@ -2230,7 +2225,7 @@ void Terr_FreeModel(model_t *mod)
} }
} }
#ifndef SERVERONLY #ifdef HAVE_CLIENT
void Terr_DrawTerrainWater(heightmap_t *hm, float *mins, float *maxs, struct hmwater_s *w) void Terr_DrawTerrainWater(heightmap_t *hm, float *mins, float *maxs, struct hmwater_s *w)
{ {
scenetris_t *t; scenetris_t *t;
@ -3451,6 +3446,38 @@ typedef struct {
#endif #endif
} hmtrace_t; } hmtrace_t;
#ifdef HAVE_CLIENT
shader_t *Terr_GetShader(model_t *mod, trace_t *trace)
{
heightmap_t *hm = mod?mod->terrain:NULL;
unsigned int brushid = trace->brush_id;
unsigned int fa, i;
brushes_t *br;
if (!brushid)
return NULL;
if (!hm)
return NULL;
for (i = 0; i < hm->numbrushes; i++)
{
br = &hm->wbrushes[i];
if (br->id == trace->brush_id)
{
if (br->patch)
return br->patch->tex->shader;
fa = trace->brush_face-1;
if (fa >= br->numplanes)
return NULL;
return br->faces[fa].tex->shader;
}
}
return NULL;
}
#endif
static int Heightmap_Trace_Brush(hmtrace_t *tr, vec4_t *planes, int numplanes, brushes_t *brushinfo) static int Heightmap_Trace_Brush(hmtrace_t *tr, vec4_t *planes, int numplanes, brushes_t *brushinfo)
{ {
qboolean startout; qboolean startout;
@ -4405,7 +4432,7 @@ unsigned int Heightmap_FatPVS (model_t *mod, const vec3_t org, pvsbuffer_t *fte
return sizeof(*hmpvs); return sizeof(*hmpvs);
} }
#ifndef CLIENTONLY #ifdef HAVE_SERVER
qboolean Heightmap_EdictInFatPVS (model_t *mod, const struct pvscache_s *edict, const qbyte *pvsdata, const int *areas) qboolean Heightmap_EdictInFatPVS (model_t *mod, const struct pvscache_s *edict, const qbyte *pvsdata, const int *areas)
{ {
heightmap_t *hm = mod->terrain; heightmap_t *hm = mod->terrain;
@ -4472,7 +4499,7 @@ int Heightmap_ClusterForPoint (model_t *model, const vec3_t point, int *area)
return -1; return -1;
} }
#ifndef SERVERONLY #ifdef HAVE_CLIENT
static unsigned char *QDECL Terr_GetLightmap(hmsection_t *s, int idx, qboolean edit) static unsigned char *QDECL Terr_GetLightmap(hmsection_t *s, int idx, qboolean edit)
{ {
int x = idx % SECTTEXSIZE, y = idx / SECTTEXSIZE; int x = idx % SECTTEXSIZE, y = idx / SECTTEXSIZE;
@ -5070,7 +5097,7 @@ void QCBUILTIN PF_terrain_edit(pubprogfuncs_t *prinst, struct globalvars_s *pr_g
mod->entityinfo[idx].id = 0; mod->entityinfo[idx].id = 0;
} }
#ifndef CLIENTONLY #ifdef HAVE_SERVER
if (sv_state && modelindex > 0) if (sv_state && modelindex > 0)
{ {
MSG_WriteByte(&sv.multicast, svcfte_brushedit); MSG_WriteByte(&sv.multicast, svcfte_brushedit);
@ -5086,7 +5113,7 @@ void QCBUILTIN PF_terrain_edit(pubprogfuncs_t *prinst, struct globalvars_s *pr_g
} }
else else
#endif #endif
#ifndef SERVERONLY #ifdef HAVE_CLIENT
if (cls.state && modelindex > 0) if (cls.state && modelindex > 0)
{ {
MSG_WriteByte(&cls.netchan.message, clcfte_brushedit); MSG_WriteByte(&cls.netchan.message, clcfte_brushedit);
@ -5494,7 +5521,7 @@ void Terr_ParseEntityLump(model_t *mod, heightmap_t *heightmap)
void Terr_FinishTerrain(model_t *mod) void Terr_FinishTerrain(model_t *mod)
{ {
#ifndef SERVERONLY #ifdef HAVE_CLIENT
heightmap_t *hm = mod->terrain; heightmap_t *hm = mod->terrain;
if (qrenderer != QR_NONE) if (qrenderer != QR_NONE)
{ {
@ -5595,7 +5622,7 @@ void Terr_FinishTerrain(model_t *mod)
#endif #endif
} }
#ifndef SERVERONLY #ifdef HAVE_CLIENT
void Terr_Brush_Draw(heightmap_t *hm, batch_t **batches, entity_t *e) void Terr_Brush_Draw(heightmap_t *hm, batch_t **batches, entity_t *e)
{ {
batch_t *b; batch_t *b;
@ -6401,7 +6428,7 @@ static brushes_t *Terr_Brush_Insert(model_t *model, heightmap_t *hm, brushes_t *
do do
{ {
out->id = (++hm->brushidseq)&0x00ffffff; out->id = (++hm->brushidseq)&0x00ffffff;
#ifndef SERVERONLY #ifdef HAVE_CLIENT
if (cls.state) //avoid networking conflicts by having each node generating its own private ids if (cls.state) //avoid networking conflicts by having each node generating its own private ids
out->id |= (cl.playerview[0].playernum+1)<<24; out->id |= (cl.playerview[0].playernum+1)<<24;
#endif #endif
@ -6687,7 +6714,7 @@ static qboolean Brush_Deserialise(heightmap_t *hm, brushes_t *br, void *mem)
} }
#ifndef SERVERONLY #ifdef HAVE_CLIENT
heightmap_t *CL_BrushEdit_ForceContext(model_t *mod) heightmap_t *CL_BrushEdit_ForceContext(model_t *mod)
{ {
heightmap_t *hm = mod?mod->terrain:NULL; heightmap_t *hm = mod?mod->terrain:NULL;
@ -6719,10 +6746,10 @@ void CL_Parse_BrushEdit(void)
model_t *mod = (modelindex<countof(cl.model_precache))?cl.model_precache[modelindex]:NULL; model_t *mod = (modelindex<countof(cl.model_precache))?cl.model_precache[modelindex]:NULL;
heightmap_t *hm = mod?mod->terrain:NULL; heightmap_t *hm = mod?mod->terrain:NULL;
#ifdef CLIENTONLY #ifdef HAVE_SERVER
const qboolean ignore = false;
#else
const qboolean ignore = (sv_state>=ss_loading); //if we're the server then we already have this info. don't break anything (this info is present for demos). const qboolean ignore = (sv_state>=ss_loading); //if we're the server then we already have this info. don't break anything (this info is present for demos).
#else
const qboolean ignore = false;
#endif #endif
if (cmd == hmcmd_brush_delete) if (cmd == hmcmd_brush_delete)
@ -6828,7 +6855,7 @@ void CL_Parse_BrushEdit(void)
Host_EndGame("CL_Parse_BrushEdit: unknown command %i\n", cmd); Host_EndGame("CL_Parse_BrushEdit: unknown command %i\n", cmd);
} }
#endif #endif
#ifndef CLIENTONLY #ifdef HAVE_SERVER
qboolean SV_Prespawn_Brushes(sizebuf_t *msg, unsigned int *modelindex, unsigned int *lastid) qboolean SV_Prespawn_Brushes(sizebuf_t *msg, unsigned int *modelindex, unsigned int *lastid)
{ {
//lastid starts at 0 //lastid starts at 0
@ -7268,7 +7295,7 @@ void QCBUILTIN PF_brush_create(pubprogfuncs_t *prinst, struct globalvars_s *pr_g
//if we're creating one that already exists, then assume that its a move. //if we're creating one that already exists, then assume that its a move.
if (brushid && Terr_Brush_DeleteId(hm, brushid)) if (brushid && Terr_Brush_DeleteId(hm, brushid))
{ {
#ifndef CLIENTONLY #ifdef HAVE_SERVER
if (sv.state && modelindex > 0) if (sv.state && modelindex > 0)
{ {
MSG_WriteByte(&sv.multicast, svcfte_brushedit); MSG_WriteByte(&sv.multicast, svcfte_brushedit);
@ -7279,7 +7306,7 @@ void QCBUILTIN PF_brush_create(pubprogfuncs_t *prinst, struct globalvars_s *pr_g
} }
else else
#endif #endif
#ifndef SERVERONLY #ifdef HAVE_CLIENT
if (cls.state && modelindex > 0) if (cls.state && modelindex > 0)
{ {
MSG_WriteByte(&cls.netchan.message, clcfte_brushedit); MSG_WriteByte(&cls.netchan.message, clcfte_brushedit);
@ -7306,6 +7333,10 @@ void QCBUILTIN PF_brush_create(pubprogfuncs_t *prinst, struct globalvars_s *pr_g
faces[i].stdir[0][3] = in_faces[i].sbias; faces[i].stdir[0][3] = in_faces[i].sbias;
VectorCopy(in_faces[i].tdir, faces[i].stdir[1]); VectorCopy(in_faces[i].tdir, faces[i].stdir[1]);
faces[i].stdir[1][3] = in_faces[i].tbias; faces[i].stdir[1][3] = in_faces[i].tbias;
//these are for compat with (q2/)q3 so as to not be lossy even if they're not really used.
faces[i].surfaceflags = 0;
faces[i].surfacevalue = 0;
} }
//now emit it //now emit it
@ -7321,7 +7352,7 @@ void QCBUILTIN PF_brush_create(pubprogfuncs_t *prinst, struct globalvars_s *pr_g
if (nb) if (nb)
{ {
G_INT(OFS_RETURN) = nb->id; G_INT(OFS_RETURN) = nb->id;
#ifndef CLIENTONLY #ifdef HAVE_SERVER
if (sv.state && modelindex > 0) if (sv.state && modelindex > 0)
{ {
MSG_WriteByte(&sv.multicast, svcfte_brushedit); MSG_WriteByte(&sv.multicast, svcfte_brushedit);
@ -7332,7 +7363,7 @@ void QCBUILTIN PF_brush_create(pubprogfuncs_t *prinst, struct globalvars_s *pr_g
return; return;
} }
#endif #endif
#ifndef SERVERONLY #ifdef HAVE_CLIENT
if (cls.state && modelindex > 0) if (cls.state && modelindex > 0)
{ {
MSG_WriteByte(&cls.netchan.message, clcfte_brushedit); MSG_WriteByte(&cls.netchan.message, clcfte_brushedit);
@ -7383,7 +7414,7 @@ void QCBUILTIN PF_patch_create(pubprogfuncs_t *prinst, struct globalvars_s *pr_g
//if we're creating one that already exists, then assume that its a move. //if we're creating one that already exists, then assume that its a move.
if (brushid && Terr_Brush_DeleteId(hm, brushid)) if (brushid && Terr_Brush_DeleteId(hm, brushid))
{ {
#ifndef CLIENTONLY #ifdef HAVE_SERVER
if (sv.state && modelindex > 0) if (sv.state && modelindex > 0)
{ {
MSG_WriteByte(&sv.multicast, svcfte_brushedit); MSG_WriteByte(&sv.multicast, svcfte_brushedit);
@ -7394,7 +7425,7 @@ void QCBUILTIN PF_patch_create(pubprogfuncs_t *prinst, struct globalvars_s *pr_g
} }
else else
#endif #endif
#ifndef SERVERONLY #ifdef HAVE_CLIENT
if (cls.state && modelindex > 0) if (cls.state && modelindex > 0)
{ {
MSG_WriteByte(&cls.netchan.message, clcfte_brushedit); MSG_WriteByte(&cls.netchan.message, clcfte_brushedit);
@ -7435,7 +7466,7 @@ void QCBUILTIN PF_patch_create(pubprogfuncs_t *prinst, struct globalvars_s *pr_g
if (nb) if (nb)
{ {
G_INT(OFS_RETURN) = nb->id; G_INT(OFS_RETURN) = nb->id;
#ifndef CLIENTONLY #ifdef HAVE_SERVER
if (sv.state && modelindex > 0) if (sv.state && modelindex > 0)
{ {
MSG_WriteByte(&sv.multicast, svcfte_brushedit); MSG_WriteByte(&sv.multicast, svcfte_brushedit);
@ -7446,7 +7477,7 @@ void QCBUILTIN PF_patch_create(pubprogfuncs_t *prinst, struct globalvars_s *pr_g
return; return;
} }
#endif #endif
#ifndef SERVERONLY #ifdef HAVE_CLIENT
if (cls.state && modelindex > 0) if (cls.state && modelindex > 0)
{ {
MSG_WriteByte(&cls.netchan.message, clcfte_brushedit); MSG_WriteByte(&cls.netchan.message, clcfte_brushedit);
@ -7473,7 +7504,7 @@ void QCBUILTIN PF_brush_delete(pubprogfuncs_t *prinst, struct globalvars_s *pr_g
Terr_Brush_DeleteId(hm, brushid); Terr_Brush_DeleteId(hm, brushid);
#ifndef CLIENTONLY #ifdef HAVE_SERVER
if (sv.state && modelindex > 0) if (sv.state && modelindex > 0)
{ {
MSG_WriteByte(&sv.multicast, svcfte_brushedit); MSG_WriteByte(&sv.multicast, svcfte_brushedit);
@ -7484,7 +7515,7 @@ void QCBUILTIN PF_brush_delete(pubprogfuncs_t *prinst, struct globalvars_s *pr_g
return; return;
} }
#endif #endif
#ifndef SERVERONLY #ifdef HAVE_CLIENT
if (cls.state && modelindex > 0) if (cls.state && modelindex > 0)
{ {
MSG_WriteByte(&cls.netchan.message, clcfte_brushedit); MSG_WriteByte(&cls.netchan.message, clcfte_brushedit);
@ -7919,6 +7950,7 @@ void Terr_WriteMapFile(vfsfile_t *file, model_t *mod)
else else
entities = COM_ParseOut(entities, token, sizeof(token)); entities = COM_ParseOut(entities, token, sizeof(token));
} }
if (entities)
VFS_WRITE(file, start, entities - start); VFS_WRITE(file, start, entities - start);
start = entities; start = entities;
} }
@ -7936,7 +7968,7 @@ void Mod_Terrain_Save_f(void)
} }
if (*mapname) if (*mapname)
mod = Mod_FindName(va("maps/%s", mapname)); mod = Mod_FindName(va("maps/%s", mapname));
#ifndef SERVERONLY #ifdef HAVE_CLIENT
else if (cls.state) else if (cls.state)
mod = cl.worldmodel; mod = cl.worldmodel;
#endif #endif
@ -8030,7 +8062,16 @@ qboolean Terr_ReformEntitiesLump(model_t *mod, heightmap_t *hm, char *entities)
{ {
start = entities; start = entities;
entities = COM_ParseTokenOut(entities, brushpunct, token, sizeof(token), NULL); entities = COM_ParseTokenOut(entities, brushpunct, token, sizeof(token), NULL);
if (token[0] == '}' && token[1] == 0) if (!entities)
{
if (inbrush || nest)
{
Con_Printf(CON_ERROR "%s: File truncated?\n", mod->name);
return false;
}
break;
}
else if (token[0] == '}' && token[1] == 0)
{ {
nest--; nest--;
if (inbrush) if (inbrush)
@ -8076,6 +8117,7 @@ qboolean Terr_ReformEntitiesLump(model_t *mod, heightmap_t *hm, char *entities)
if (submodelnum) if (submodelnum)
{ {
Q_snprintfz(token, sizeof(token), "*%i", submodelnum); Q_snprintfz(token, sizeof(token), "*%i", submodelnum);
*out++ = '\n';
*out++ = 'm'; *out++ = 'm';
*out++ = 'o'; *out++ = 'o';
*out++ = 'd'; *out++ = 'd';
@ -8108,7 +8150,7 @@ qboolean Terr_ReformEntitiesLump(model_t *mod, heightmap_t *hm, char *entities)
submod->funcs.MarkLights = Heightmap_MarkLights; submod->funcs.MarkLights = Heightmap_MarkLights;
submod->funcs.ClusterForPoint = Heightmap_ClusterForPoint; submod->funcs.ClusterForPoint = Heightmap_ClusterForPoint;
submod->funcs.ClusterPVS = Heightmap_ClusterPVS; submod->funcs.ClusterPVS = Heightmap_ClusterPVS;
#ifndef CLIENTONLY #ifdef HAVE_SERVER
submod->funcs.FindTouchedLeafs = Heightmap_FindTouchedLeafs; submod->funcs.FindTouchedLeafs = Heightmap_FindTouchedLeafs;
submod->funcs.EdictInFatPVS = Heightmap_EdictInFatPVS; submod->funcs.EdictInFatPVS = Heightmap_EdictInFatPVS;
submod->funcs.FatPVS = Heightmap_FatPVS; submod->funcs.FatPVS = Heightmap_FatPVS;
@ -8117,6 +8159,7 @@ qboolean Terr_ReformEntitiesLump(model_t *mod, heightmap_t *hm, char *entities)
submod->pvsbytes = sizeof(hmpvs_t); submod->pvsbytes = sizeof(hmpvs_t);
#ifdef RUNTIMELIGHTING #ifdef RUNTIMELIGHTING
if (hm->relightcontext)
subhm->relightcontext = LightStartup(hm->relightcontext, submod, false, false); subhm->relightcontext = LightStartup(hm->relightcontext, submod, false, false);
subhm->lightthreadmem = hm->lightthreadmem; subhm->lightthreadmem = hm->lightthreadmem;
subhm->inheritedlightthreadmem = true; subhm->inheritedlightthreadmem = true;
@ -8136,6 +8179,11 @@ qboolean Terr_ReformEntitiesLump(model_t *mod, heightmap_t *hm, char *entities)
continue; continue;
} }
} }
else if (!nest)
{
Con_Printf(CON_ERROR "%s: junk found\n", mod->name);
return false;
}
else if (inbrush && (!strcmp(token, "patchDef2") || !strcmp(token, "patchDef3") || else if (inbrush && (!strcmp(token, "patchDef2") || !strcmp(token, "patchDef3") ||
!strcmp(token, "patchDef2WS") || !strcmp(token, "patchDef3WS"))) !strcmp(token, "patchDef2WS") || !strcmp(token, "patchDef3WS")))
{ {
@ -8247,11 +8295,11 @@ qboolean Terr_ReformEntitiesLump(model_t *mod, heightmap_t *hm, char *entities)
//Quake: ( -0 -0 16 ) ( -0 -0 32 ) ( 64 -0 16 ) texname soffset toffset rotation sscale tscale //Quake: ( -0 -0 16 ) ( -0 -0 32 ) ( 64 -0 16 ) texname soffset toffset rotation sscale tscale
//Hexen2: ( -0 -0 16 ) ( -0 -0 32 ) ( 64 -0 16 ) texname soffset toffset rotation sscale tscale surfvalue //Hexen2: ( -0 -0 16 ) ( -0 -0 32 ) ( 64 -0 16 ) texname soffset toffset rotation sscale tscale surfvalue
//Valve: ( -0 -0 16 ) ( -0 -0 32 ) ( 64 -0 16 ) texname [x y z d] [x y z d] rotation sscale tscale //Valve: ( -0 -0 16 ) ( -0 -0 32 ) ( 64 -0 16 ) texname [x y z d] [x y z d] rotation sscale tscale
//FTE : ( px py pz pd ) texname [x y z d] [x y z d] rotation sscale tscale //FTE : ( px py pz pd ) texname [x y z d] [x y z d] rotation sscale tscale contents surfflags surfvalue
//Quake2: ( -0 -0 16 ) ( -0 -0 32 ) ( 64 -0 16 ) texname soffset toffset rotation sscale tscale contents surfflags surfvalue //Quake2: ( -0 -0 16 ) ( -0 -0 32 ) ( 64 -0 16 ) texname soffset toffset rotation sscale tscale contents surfflags surfvalue
//Quake3: ( -0 -0 16 ) ( -0 -0 32 ) ( 64 -0 16 ) texname soffset toffset rotation sscale tscale contents surfflags surfvalue //Quake3: ( -0 -0 16 ) ( -0 -0 32 ) ( 64 -0 16 ) texname soffset toffset rotation sscale tscale detailfl surfflags surfvalue
//Q3 BP: brushDef { ( -0 -0 16 ) ( -0 -0 32 ) ( 64 -0 16 ) ( ( x y o ) ( x y o ) ) texname contents surfflags surfvalue } //generate tangent+bitangent from the normal to generate base texcoords, then transform by the given 2*3 matrix. I prefer valve's way - it rotates more cleanly. //Q3 BP: brushDef { ( -0 -0 16 ) ( -0 -0 32 ) ( 64 -0 16 ) ( ( x y o ) ( x y o ) ) texname detailfl surfflags surfvalue } //generate tangent+bitangent from the normal to generate base texcoords, then transform by the given 2*3 matrix. I prefer valve's way - it rotates more cleanly.
//Doom3: brushDef3 { ( px py pz pd ) ( ( x y o ) ( x y o ) ) texname contents surfflags surfvalue } //Doom3: brushDef3 { ( px py pz pd ) ( ( x y o ) ( x y o ) ) texname detailfl surfflags surfvalue }
//hexen2's extra surfvalue is completely unused, and should normally be -1 //hexen2's extra surfvalue is completely unused, and should normally be -1
//q3 ignores all contents except detail, as well surfaceflags and surfacevalue //q3 ignores all contents except detail, as well surfaceflags and surfacevalue
//220 ignores rotation, provided only for UI info, scale is still used //220 ignores rotation, provided only for UI info, scale is still used
@ -8346,25 +8394,6 @@ qboolean Terr_ReformEntitiesLump(model_t *mod, heightmap_t *hm, char *entities)
} }
bt = Terr_Brush_FindTexture(subhm, token); bt = Terr_Brush_FindTexture(subhm, token);
if (*token == '*')
{
if (!Q_strncasecmp(token, "*lava", 5))
brushcontents = FTECONTENTS_LAVA;
else if (!Q_strncasecmp(token, "*slime", 5))
brushcontents = FTECONTENTS_SLIME;
else
brushcontents = FTECONTENTS_WATER;
}
else if (!Q_strncasecmp(token, "*sky", 4))
brushcontents = FTECONTENTS_SKY;
else if (!Q_strcasecmp(token, "clip"))
brushcontents = FTECONTENTS_PLAYERCLIP|FTECONTENTS_MONSTERCLIP;
else if (!Q_strcasecmp(token, "hint"))
brushcontents = 0;
else if (!Q_strcasecmp(token, "skip"))
;//brushcontents = 0;
else
brushcontents = FTECONTENTS_SOLID;
if (textype != TEXTYPE_BP) if (textype != TEXTYPE_BP)
{ {
@ -8424,6 +8453,7 @@ qboolean Terr_ReformEntitiesLump(model_t *mod, heightmap_t *hm, char *entities)
//The contents conveys only CONTENTS_DETAIL. which is awkward as it varies somewhat by game, but we assume q2/q3. //The contents conveys only CONTENTS_DETAIL. which is awkward as it varies somewhat by game, but we assume q2/q3.
faces[numplanes].surfaceflags = 0; faces[numplanes].surfaceflags = 0;
faces[numplanes].surfacevalue = 0; faces[numplanes].surfacevalue = 0;
while (*entities == ' ' || *entities == '\t') while (*entities == ' ' || *entities == '\t')
entities++; entities++;
if (*entities == '-' || (*entities >= '0' && *entities <= '9')) if (*entities == '-' || (*entities >= '0' && *entities <= '9'))
@ -8448,10 +8478,8 @@ qboolean Terr_ReformEntitiesLump(model_t *mod, heightmap_t *hm, char *entities)
ex3 = atoi(token); ex3 = atoi(token);
//if we got this far, then its q3 format. //if we got this far, then its q3 format.
//q3 is weird. the first extra arg is contents. but only the detail contents is used. //q3 is weird. the first extra arg is contents. but only the detail contents is used.
if (ex1 & Q3CONTENTS_DETAIL) //ex1 &= Q3CONTENTS_DETAIL;
{ brushcontents |= ex1;
brushcontents |= Q3CONTENTS_DETAIL;
}
//propagate these, in case someone tries editing a q2bsp. //propagate these, in case someone tries editing a q2bsp.
faces[numplanes].surfaceflags = ex2; faces[numplanes].surfaceflags = ex2;
@ -8475,6 +8503,39 @@ qboolean Terr_ReformEntitiesLump(model_t *mod, heightmap_t *hm, char *entities)
} }
faces[numplanes].tex = bt; faces[numplanes].tex = bt;
/*
shader_t *shader = R_RegisterCustom(NULL, bt->shadername, SUF_LIGHTMAP, NULL, NULL);
if (shader)
{
brushcontents &= Q3CONTENTS_DETAIL;
brushcontents |= shader->contentbits&~Q3CONTENTS_DETAIL;
faces[numplanes].surfaceflags = shader->surfacebits;
}
else
*/
if (bt && !numplanes)
{
if (*bt->shadername == '*')
{
if (!Q_strncasecmp(bt->shadername, "*lava", 5))
brushcontents |= FTECONTENTS_LAVA;
else if (!Q_strncasecmp(bt->shadername, "*slime", 5))
brushcontents |= FTECONTENTS_SLIME;
else
brushcontents |= FTECONTENTS_WATER;
}
else if (!Q_strncasecmp(bt->shadername, "*sky", 4))
brushcontents |= FTECONTENTS_SKY;
else if (!Q_strcasecmp(bt->shadername, "clip"))
brushcontents |= FTECONTENTS_PLAYERCLIP|FTECONTENTS_MONSTERCLIP;
else if (!Q_strcasecmp(bt->shadername, "hint"))
brushcontents |= 0;
else if (!Q_strcasecmp(bt->shadername, "skip")) //skip should not force content values if paired with lava etc.
;//brushcontents = 0;
else
brushcontents |= FTECONTENTS_SOLID;
}
if (textype == TEXTYPE_BP) if (textype == TEXTYPE_BP)
{ {
float *norm = planes[numplanes]; float *norm = planes[numplanes];
@ -8540,9 +8601,9 @@ qboolean Terr_ReformEntitiesLump(model_t *mod, heightmap_t *hm, char *entities)
} }
else else
{ {
if (!strcmp(token, "classname")) /*if (!strcmp(token, "classname"))
entities = COM_ParseTokenOut(entities, brushpunct, token, sizeof(token), NULL); entities = COM_ParseTokenOut(entities, brushpunct, token, sizeof(token), NULL);
else else*/
entities = COM_ParseTokenOut(entities, brushpunct, token, sizeof(token), NULL); entities = COM_ParseTokenOut(entities, brushpunct, token, sizeof(token), NULL);
} }
while(start < entities) while(start < entities)
@ -8642,7 +8703,7 @@ qboolean QDECL Terr_LoadTerrainModel (model_t *mod, void *buffer, size_t bufsize
mod->funcs.ClusterForPoint = Heightmap_ClusterForPoint; mod->funcs.ClusterForPoint = Heightmap_ClusterForPoint;
mod->funcs.ClusterPVS = Heightmap_ClusterPVS; mod->funcs.ClusterPVS = Heightmap_ClusterPVS;
#ifndef CLIENTONLY #ifdef HAVE_SERVER
mod->funcs.FindTouchedLeafs = Heightmap_FindTouchedLeafs; mod->funcs.FindTouchedLeafs = Heightmap_FindTouchedLeafs;
mod->funcs.EdictInFatPVS = Heightmap_EdictInFatPVS; mod->funcs.EdictInFatPVS = Heightmap_EdictInFatPVS;
mod->funcs.FatPVS = Heightmap_FatPVS; mod->funcs.FatPVS = Heightmap_FatPVS;
@ -8725,7 +8786,7 @@ void *Mod_LoadTerrainInfo(model_t *mod, char *loadname, qboolean force)
return hm; return hm;
} }
#ifndef SERVERONLY #ifdef HAVE_CLIENT
#if 0 //not yet ready #if 0 //not yet ready
struct ted_import_s struct ted_import_s
{ {
@ -9020,7 +9081,7 @@ void Mod_Terrain_Create_f(void)
//reads in the terrain a tile at a time, and writes it out again. //reads in the terrain a tile at a time, and writes it out again.
//the new version will match our current format version. //the new version will match our current format version.
//this is mostly so I can strip out old format revisions... //this is mostly so I can strip out old format revisions...
#ifndef SERVERONLY #ifdef HAVE_CLIENT
void Mod_Terrain_Convert_f(void) void Mod_Terrain_Convert_f(void)
{ {
model_t *mod; model_t *mod;
@ -9097,7 +9158,7 @@ void Mod_Terrain_Reload_f(void)
heightmap_t *hm; heightmap_t *hm;
if (Cmd_Argc() >= 2) if (Cmd_Argc() >= 2)
mod = Mod_FindName(va("maps/%s.hmp", Cmd_Argv(1))); mod = Mod_FindName(va("maps/%s.hmp", Cmd_Argv(1)));
#ifndef SERVERONLY #ifdef HAVE_CLIENT
else if (cls.state) else if (cls.state)
mod = cl.worldmodel; mod = cl.worldmodel;
#endif #endif
@ -9131,10 +9192,10 @@ plugterrainfuncs_t *Terr_GetTerrainFuncs(size_t structsize)
{ {
if (structsize != sizeof(plugterrainfuncs_t)) if (structsize != sizeof(plugterrainfuncs_t))
return NULL; return NULL;
#ifdef SERVERONLY #ifdef HAVE_CLIENT
return NULL; //dedicated server builds have all the visual stuff stripped, which makes APIs too inconsistent. Generate then save. Or fix up the API...
#else
return &terrainfuncs; return &terrainfuncs;
#else
return NULL; //dedicated server builds have all the visual stuff stripped, which makes APIs too inconsistent. Generate then save. Or fix up the API...
#endif #endif
} }
@ -9153,7 +9214,7 @@ void Terr_Init(void)
Cvar_Register(&mod_terrain_savever, "Terrain"); Cvar_Register(&mod_terrain_savever, "Terrain");
Cmd_AddCommand("mod_terrain_save", Mod_Terrain_Save_f); Cmd_AddCommand("mod_terrain_save", Mod_Terrain_Save_f);
Cmd_AddCommand("mod_terrain_reload", Mod_Terrain_Reload_f); Cmd_AddCommand("mod_terrain_reload", Mod_Terrain_Reload_f);
#ifndef SERVERONLY #ifdef HAVE_CLIENT
// Cmd_AddCommandD("mod_terrain_export", Mod_Terrain_Export_f, "Export a raw heightmap"); // Cmd_AddCommandD("mod_terrain_export", Mod_Terrain_Export_f, "Export a raw heightmap");
// Cmd_AddCommandD("mod_terrain_import", Mod_Terrain_Import_f, "Import a raw heightmap"); // Cmd_AddCommandD("mod_terrain_import", Mod_Terrain_Import_f, "Import a raw heightmap");
Cmd_AddCommand("mod_terrain_create", Mod_Terrain_Create_f); Cmd_AddCommand("mod_terrain_create", Mod_Terrain_Create_f);

View file

@ -222,6 +222,8 @@ static void Mod_TextureList_f(void)
char *cr; char *cr;
while ((cr = strchr(body, '\r'))) while ((cr = strchr(body, '\r')))
*cr = ' '; *cr = ' ';
if (strlen(body) > 3000)
body[3000] = 0; //arbitrary cut off, to avoid console glitches with big shaders.
} }
if (preview) if (preview)
@ -634,10 +636,7 @@ void Mod_SetModifier(const char *modifier)
} }
#ifndef SERVERONLY #ifndef SERVERONLY
void Mod_FindCubemaps_f(void); void Mod_BSPX_Init(void);
void Mod_Realign_f(void);
void Mod_BSPX_List_f(void);
void Mod_BSPX_Strip_f(void);
#endif #endif
/* /*
@ -689,10 +688,7 @@ void Mod_Init (qboolean initial)
Cvar_Register (&r_sprite_backfacing, NULL); Cvar_Register (&r_sprite_backfacing, NULL);
#endif #endif
#ifndef SERVERONLY #ifndef SERVERONLY
Cmd_AddCommandD("mod_findcubemaps", Mod_FindCubemaps_f, "Scans the entities of a map to find reflection env_cubemap sites and determines the nearest one to each surface."); Mod_BSPX_Init();
Cmd_AddCommandD("mod_realign", Mod_Realign_f, "Reads the named bsp and writes it back out with only alignment changes.");
Cmd_AddCommandD("mod_bspx_list", Mod_BSPX_List_f, "Lists all lumps (and their sizes) in the specified bsp.");
Cmd_AddCommandD("mod_bspx_strip", Mod_BSPX_Strip_f, "Strips a named extension lump from a bsp file.");
#endif #endif
} }
@ -1629,7 +1625,7 @@ void Mod_LoadLighting (model_t *loadmodel, bspx_header_t *bspx, qbyte *mod_base,
qbyte *litdata = NULL; //xyz8 qbyte *litdata = NULL; //xyz8
qbyte *lumdata = NULL; //l8 qbyte *lumdata = NULL; //l8
qbyte *out; qbyte *out;
unsigned int samples; size_t samples;
#ifdef RUNTIMELIGHTING #ifdef RUNTIMELIGHTING
qboolean relighting = false; qboolean relighting = false;
#endif #endif
@ -1851,7 +1847,7 @@ void Mod_LoadLighting (model_t *loadmodel, bspx_header_t *bspx, qbyte *mod_base,
exptmp = littmp = false; exptmp = littmp = false;
if (!litdata && !expdata) if (!litdata && !expdata)
{ {
int size; size_t size;
/*FIXME: bspx support for extents+lmscale, may require style+offset lumps too, not sure what to do here*/ /*FIXME: bspx support for extents+lmscale, may require style+offset lumps too, not sure what to do here*/
expdata = BSPX_FindLump(bspx, mod_base, "LIGHTING_E5BGR9", &size); expdata = BSPX_FindLump(bspx, mod_base, "LIGHTING_E5BGR9", &size);
exptmp = true; exptmp = true;
@ -1943,7 +1939,7 @@ void Mod_LoadLighting (model_t *loadmodel, bspx_header_t *bspx, qbyte *mod_base,
} }
if (!luxdata) if (!luxdata)
{ {
int size; size_t size;
luxdata = BSPX_FindLump(bspx, mod_base, "LIGHTINGDIR", &size); luxdata = BSPX_FindLump(bspx, mod_base, "LIGHTINGDIR", &size);
if (size != samples*3) if (size != samples*3)
luxdata = NULL; luxdata = NULL;
@ -2038,28 +2034,28 @@ void Mod_LoadLighting (model_t *loadmodel, bspx_header_t *bspx, qbyte *mod_base,
if (overrides && !overrides->shifts) if (overrides && !overrides->shifts)
{ {
int size; size_t size;
//if we have shifts, then we probably also have legacy data in the surfaces that we want to override //if we have shifts, then we probably also have legacy data in the surfaces that we want to override
if (!overrides->offsets) if (!overrides->offsets)
{ {
int size; size_t size;
overrides->offsets = BSPX_FindLump(bspx, mod_base, "LMOFFSET", &size); overrides->offsets = BSPX_FindLump(bspx, mod_base, "LMOFFSET", &size);
if (size != loadmodel->numsurfaces * sizeof(int)) if (size != loadmodel->numsurfaces * sizeof(int))
{ {
if (size) if (size)
Con_Printf(CON_ERROR"BSPX LMOFFSET lump is wrong size, expected %u entries, found %u\n", loadmodel->numsurfaces, size/(unsigned int)sizeof(int)); Con_Printf(CON_ERROR"BSPX LMOFFSET lump is wrong size, expected %u entries, found %"PRIuSIZE"\n", loadmodel->numsurfaces, size/(unsigned int)sizeof(int));
overrides->offsets = NULL; overrides->offsets = NULL;
} }
} }
if (!overrides->styles8 && !overrides->styles16) if (!overrides->styles8 && !overrides->styles16)
{ //16bit per-face lightmap styles index { //16bit per-face lightmap styles index
int size; size_t size;
overrides->styles16 = BSPX_FindLump(bspx, mod_base, "LMSTYLE16", &size); overrides->styles16 = BSPX_FindLump(bspx, mod_base, "LMSTYLE16", &size);
overrides->stylesperface = size / (sizeof(*overrides->styles16)*loadmodel->numsurfaces); //rounding issues will be caught on the next line... overrides->stylesperface = size / (sizeof(*overrides->styles16)*loadmodel->numsurfaces); //rounding issues will be caught on the next line...
if (!overrides->stylesperface || size != loadmodel->numsurfaces * sizeof(*overrides->styles16)*overrides->stylesperface) if (!overrides->stylesperface || size != loadmodel->numsurfaces * sizeof(*overrides->styles16)*overrides->stylesperface)
{ {
if (size) if (size)
Con_Printf(CON_ERROR"BSPX LMSTYLE16 lump is wrong size, expected %u*%u entries, found %u\n", loadmodel->numsurfaces, overrides->stylesperface, size/(unsigned int)sizeof(*overrides->styles16)); Con_Printf(CON_ERROR"BSPX LMSTYLE16 lump is wrong size, expected %u*%u entries, found %"PRIuSIZE"\n", loadmodel->numsurfaces, overrides->stylesperface, size/(unsigned int)sizeof(*overrides->styles16));
overrides->styles16 = NULL; overrides->styles16 = NULL;
} }
else if (overrides->stylesperface > MAXCPULIGHTMAPS) else if (overrides->stylesperface > MAXCPULIGHTMAPS)
@ -2067,13 +2063,13 @@ void Mod_LoadLighting (model_t *loadmodel, bspx_header_t *bspx, qbyte *mod_base,
} }
if (!overrides->styles8 && !overrides->styles16) if (!overrides->styles8 && !overrides->styles16)
{ //16bit per-face lightmap styles index { //16bit per-face lightmap styles index
int size; size_t size;
overrides->styles8 = BSPX_FindLump(bspx, mod_base, "LMSTYLE", &size); overrides->styles8 = BSPX_FindLump(bspx, mod_base, "LMSTYLE", &size);
overrides->stylesperface = size / (sizeof(*overrides->styles8)*loadmodel->numsurfaces); //rounding issues will be caught on the next line... overrides->stylesperface = size / (sizeof(*overrides->styles8)*loadmodel->numsurfaces); //rounding issues will be caught on the next line...
if (!overrides->stylesperface || size != loadmodel->numsurfaces * sizeof(*overrides->styles8)*overrides->stylesperface) if (!overrides->stylesperface || size != loadmodel->numsurfaces * sizeof(*overrides->styles8)*overrides->stylesperface)
{ {
if (size) if (size)
Con_Printf(CON_ERROR"BSPX LMSTYLE16 lump is wrong size, expected %u*%u entries, found %u\n", loadmodel->numsurfaces, overrides->stylesperface, size/(unsigned int)sizeof(*overrides->styles8)); Con_Printf(CON_ERROR"BSPX LMSTYLE16 lump is wrong size, expected %u*%u entries, found %"PRIuSIZE"\n", loadmodel->numsurfaces, overrides->stylesperface, size/(unsigned int)sizeof(*overrides->styles8));
overrides->styles8 = NULL; overrides->styles8 = NULL;
} }
else if (overrides->stylesperface > MAXCPULIGHTMAPS) else if (overrides->stylesperface > MAXCPULIGHTMAPS)
@ -2085,7 +2081,7 @@ void Mod_LoadLighting (model_t *loadmodel, bspx_header_t *bspx, qbyte *mod_base,
{ {
if (size) if (size)
{ //ericw-tools is screwing up again. don't leave things screwed. { //ericw-tools is screwing up again. don't leave things screwed.
Con_Printf(CON_ERROR"BSPX LMSHIFT lump is wrong size, expected %u entries, found %u\n", loadmodel->numsurfaces, size); Con_Printf(CON_ERROR"BSPX LMSHIFT lump is wrong size, expected %u entries, found %"PRIuSIZE"\n", loadmodel->numsurfaces, size);
overrides->styles16 = NULL; overrides->styles16 = NULL;
overrides->styles8 = NULL; overrides->styles8 = NULL;
overrides->offsets = NULL; overrides->offsets = NULL;
@ -2290,7 +2286,7 @@ static void Mod_SaveEntFile_f(void)
if (COM_WriteFile(fname, FS_GAMEONLY, ents, strlen(ents))) if (COM_WriteFile(fname, FS_GAMEONLY, ents, strlen(ents)))
{ {
if (FS_NativePath(fname, FS_GAMEONLY, nname, sizeof(nname))) if (FS_DisplayPath(fname, FS_GAMEONLY, nname, sizeof(nname)))
Con_Printf("Wrote %s\n", nname); Con_Printf("Wrote %s\n", nname);
} }
else else
@ -2425,7 +2421,7 @@ qboolean Mod_LoadVertexNormals (model_t *loadmodel, bspx_header_t *bspx, qbyte *
{ {
float *in; float *in;
float *out; float *out;
int i, count; size_t i, count;
if (l) if (l)
{ {
@ -2442,7 +2438,7 @@ qboolean Mod_LoadVertexNormals (model_t *loadmodel, bspx_header_t *bspx, qbyte *
} }
else else
{ //ericw's thing { //ericw's thing
unsigned int size; size_t size;
quint32_t t; quint32_t t;
int *normcount; int *normcount;
struct surfedgenormals_s *sen; struct surfedgenormals_s *sen;
@ -3687,7 +3683,7 @@ static void Mod_LoadMiptex(model_t *loadmodel, texture_t *tx, miptex_t *mt, int
} }
if (extsize != 16+sz) if (extsize != 16+sz)
{ {
Con_Printf("miptex %s has incomplete mipchain\n", Image_FormatName(newfmt)); Con_Printf(CON_WARNING"miptex %s (%s) has incomplete mipchain\n", tx->name, Image_FormatName(newfmt));
continue; continue;
} }
@ -3767,7 +3763,7 @@ static void Mod_LoadMiptex(model_t *loadmodel, texture_t *tx, miptex_t *mt, int
legacysize = 0; legacysize = 0;
for (m = 0; m < 4; m++) for (m = 0; m < 4; m++)
{ {
if (mt->offsets[m]) if (mt->offsets[m] && (mt->offsets[m]+(mt->width>>m)*(mt->height>>m)<=miptexsize))
memcpy(tx->srcdata+legacysize, ptr + mt->offsets[m], (mt->width>>m)*(mt->height>>m)); memcpy(tx->srcdata+legacysize, ptr + mt->offsets[m], (mt->width>>m)*(mt->height>>m));
else else
memset(tx->srcdata+legacysize, 0, (mt->width>>m)*(mt->height>>m)); memset(tx->srcdata+legacysize, 0, (mt->width>>m)*(mt->height>>m));
@ -3837,6 +3833,7 @@ TRACE(("dbg: Mod_LoadTextures: inittexturedescs\n"));
o = LittleLong(m->dataofs[i]); o = LittleLong(m->dataofs[i]);
if (o >= l->filelen) //e1m2, this happens if (o >= l->filelen) //e1m2, this happens
{ {
badmip:
tx = ZG_Malloc(&loadmodel->memgroup, sizeof(texture_t)); tx = ZG_Malloc(&loadmodel->memgroup, sizeof(texture_t));
memcpy(tx, r_notexture_mip, sizeof(texture_t)); memcpy(tx, r_notexture_mip, sizeof(texture_t));
sprintf(tx->name, "unnamed%i", i); sprintf(tx->name, "unnamed%i", i);
@ -3870,6 +3867,12 @@ TRACE(("dbg: Mod_LoadTextures: inittexturedescs\n"));
TRACE(("dbg: Mod_LoadTextures: texture %s\n", mt->name)); TRACE(("dbg: Mod_LoadTextures: texture %s\n", mt->name));
if (mt->offsets[0] && (mt->width > 0xffff|| mt->height > 0xffff))
{
Con_Printf(CON_WARNING "%s: miptex %i is excessively large. probably corrupt\n", loadmodel->name, i);
goto badmip;
}
if (!*mt->name) //I HATE MAPPERS! if (!*mt->name) //I HATE MAPPERS!
{ {
Q_snprintfz(mt->name, sizeof(mt->name), "unnamed%i", i); Q_snprintfz(mt->name, sizeof(mt->name), "unnamed%i", i);
@ -4269,7 +4272,7 @@ static qboolean Mod_LoadFaces (model_t *loadmodel, bspx_header_t *bspx, qbyte *m
qboolean lightmapusable = false; qboolean lightmapusable = false;
struct decoupled_lm_info_s *decoupledlm; struct decoupled_lm_info_s *decoupledlm;
unsigned int dcsize; size_t dcsize;
memset(&overrides, 0, sizeof(overrides)); memset(&overrides, 0, sizeof(overrides));
@ -4406,8 +4409,20 @@ static qboolean Mod_LoadFaces (model_t *loadmodel, bspx_header_t *bspx, qbyte *m
lofs = LittleLong(decoupledlm->lmoffset); lofs = LittleLong(decoupledlm->lmoffset);
out->texturemins[0] = out->texturemins[1] = 0; // should be handled by the now-per-surface vecs[][3] value. out->texturemins[0] = out->texturemins[1] = 0; // should be handled by the now-per-surface vecs[][3] value.
out->lmshift = 0; //redundant. out->lmshift = 0; //redundant.
out->extents[0] = (unsigned short)LittleShort(decoupledlm->lmsize[0]) - 1; if (!decoupledlm->lmsize[0] || !decoupledlm->lmsize[1])
{
decoupledlm->lmsize[0] = decoupledlm->lmsize[1] = 0;
if (lofs != (unsigned int)-1)
{ //we'll silently allow these buggy surfaces for now... but only if they've got no lightmap data at all. unsafe if they're the last otherwise.
lofs = -1;
Con_Printf(CON_WARNING"%s: Face %i has invalid extents\n", loadmodel->name, surfnum);
}
}
else
{
out->extents[0] = (unsigned short)LittleShort(decoupledlm->lmsize[0]) - 1; //surfaces should NEVER have an extent of 0. even if the surface is omitted it should still have some padding...
out->extents[1] = (unsigned short)LittleShort(decoupledlm->lmsize[1]) - 1; out->extents[1] = (unsigned short)LittleShort(decoupledlm->lmsize[1]) - 1;
}
loadmodel->facelmvecs[surfnum].lmvecs[0][0] = LittleFloat(decoupledlm->lmvecs[0][0]); loadmodel->facelmvecs[surfnum].lmvecs[0][0] = LittleFloat(decoupledlm->lmvecs[0][0]);
loadmodel->facelmvecs[surfnum].lmvecs[0][1] = LittleFloat(decoupledlm->lmvecs[0][1]); loadmodel->facelmvecs[surfnum].lmvecs[0][1] = LittleFloat(decoupledlm->lmvecs[0][1]);
loadmodel->facelmvecs[surfnum].lmvecs[0][2] = LittleFloat(decoupledlm->lmvecs[0][2]); loadmodel->facelmvecs[surfnum].lmvecs[0][2] = LittleFloat(decoupledlm->lmvecs[0][2]);

View file

@ -209,9 +209,11 @@ m*_t structures are in-memory
#define QWEF_FLAG1 (1<<4) //only applies to qw player entities #define QWEF_FLAG1 (1<<4) //only applies to qw player entities
#define NQEF_NODRAW (1<<4) //so packet entities are free to get this instead #define NQEF_NODRAW (1<<4) //so packet entities are free to get this instead
#define REEF_QUADLIGHT (1<<4) #define REEF_QUADLIGHT (1<<4)
#define TENEBRAEEF_FULLDYNAMIC (1<<4)
#define QWEF_FLAG2 (1<<5) //only applies to qw player entities #define QWEF_FLAG2 (1<<5) //only applies to qw player entities
#define NQEF_ADDITIVE (1<<5) //so packet entities are free to get this instead #define NQEF_ADDITIVE (1<<5) //so packet entities are free to get this instead
#define REEF_PENTLIGHT (1<<5) #define REEF_PENTLIGHT (1<<5)
#define TENEBRAEEF_GREEN (1<<5)
#define EF_BLUE (1<<6) #define EF_BLUE (1<<6)
#define REEF_CANDLELIGHT (1<<6) #define REEF_CANDLELIGHT (1<<6)
#define EF_RED (1<<7) #define EF_RED (1<<7)
@ -602,7 +604,7 @@ void Q1BSP_GenerateShadowMesh(struct model_s *model, struct dlight_s *dl, const
void BSPX_LightGridLoad(struct model_s *model, bspx_header_t *bspx, qbyte *mod_base); //for q1 or q2 models. void BSPX_LightGridLoad(struct model_s *model, bspx_header_t *bspx, qbyte *mod_base); //for q1 or q2 models.
void BSPX_LoadEnvmaps(struct model_s *mod, bspx_header_t *bspx, void *mod_base); void BSPX_LoadEnvmaps(struct model_s *mod, bspx_header_t *bspx, void *mod_base);
void *BSPX_FindLump(bspx_header_t *bspxheader, void *mod_base, char *lumpname, int *lumpsize); void *BSPX_FindLump(bspx_header_t *bspxheader, void *mod_base, char *lumpname, size_t *lumpsize);
bspx_header_t *BSPX_Setup(struct model_s *mod, char *filebase, size_t filelen, lump_t *lumps, size_t numlumps); bspx_header_t *BSPX_Setup(struct model_s *mod, char *filebase, size_t filelen, lump_t *lumps, size_t numlumps);
typedef struct fragmentdecal_s fragmentdecal_t; typedef struct fragmentdecal_s fragmentdecal_t;
@ -1107,8 +1109,9 @@ typedef struct model_s
//internally, we still use integers for lighting, with .7 bits of extra precision. //internally, we still use integers for lighting, with .7 bits of extra precision.
LM_L8, LM_L8,
LM_RGB8, LM_RGB8,
LM_E5BGR9 LM_E5BGR9,
} fmt; } fmt;
enum uploadfmt prebaked;
qboolean deluxemapping; //lightmaps are interleaved with deluxemap data (lightmap indicies should only be even values) qboolean deluxemapping; //lightmaps are interleaved with deluxemap data (lightmap indicies should only be even values)
qboolean deluxemapping_modelspace; //deluxemaps are in modelspace - we need different glsl. qboolean deluxemapping_modelspace; //deluxemaps are in modelspace - we need different glsl.
} lightmaps; } lightmaps;
@ -1180,6 +1183,7 @@ unsigned int Heightmap_PointContents(model_t *model, const vec3_t axis[3], const
struct fragmentdecal_s; struct fragmentdecal_s;
void Terrain_ClipDecal(struct fragmentdecal_s *dec, float *center, float radius, model_t *model); void Terrain_ClipDecal(struct fragmentdecal_s *dec, float *center, float radius, model_t *model);
qboolean Terr_DownloadedSection(char *fname); qboolean Terr_DownloadedSection(char *fname);
shader_t *Terr_GetShader(struct model_s *mod, struct trace_s *trace);
void CL_Parse_BrushEdit(void); void CL_Parse_BrushEdit(void);
qboolean SV_Parse_BrushEdit(void); qboolean SV_Parse_BrushEdit(void);

Some files were not shown because too many files have changed in this diff Show more