Merge branch SRB2:next into fix-opengl-saturation-console

This commit is contained in:
Alam Ed Arias 2023-10-23 18:36:50 +00:00
commit a4dc67cba7
94 changed files with 7279 additions and 6848 deletions

4
.gitattributes vendored
View file

@ -1,15 +1,17 @@
#Source code #Source code
/Makefile text=auto
/src/*.c text=auto /src/*.c text=auto
/src/*.h text=auto /src/*.h text=auto
/src/*.s text=auto /src/*.s text=auto
/src/*.m text=auto /src/*.m text=auto
/src/*.xpm text=auto /src/*.xpm text=auto
/src/Makefile text=auto /src/Makefile text=auto
/tools/Makefile text=auto
/src/Make*.cfg text=auto /src/Make*.cfg text=auto
/src/CMakeLists.txt text=auto /src/CMakeLists.txt text=auto
*.mk -whitespace text=auto
# Windows EOL # Windows EOL
*.cs -crlf -whitespace *.cs -crlf -whitespace
*.mk -crlf -whitespace
*.bat -crlf -whitespace *.bat -crlf -whitespace
*.dev -crlf -whitespace *.dev -crlf -whitespace
*.dsp -crlf -whitespace *.dsp -crlf -whitespace

434
.gitlab-ci.yml Normal file
View file

@ -0,0 +1,434 @@
variables:
GIT_STRATEGY: clone
GIT_CLONE_PATH: $CI_BUILDS_DIR/$CI_CONCURRENT_ID/$CI_PROJECT_PATH
default:
image: debian:stable-slim
cache:
- key: ccache-$CI_PROJECT_PATH_SLUG-$CI_JOB_NAME_SLUG
fallback_keys:
- cache-$CI_PROJECT_PATH_SLUG-$CI_DEFAULT_BRANCH
- cache-$CI_PROJECT_PATH_SLUG-default
paths:
- ccache
- ccache_statslog
- key: apt-$CI_JOB_IMAGE
paths:
- apt-cache
unprotect: true
before_script:
- - |
# debconf
echo -e "\e[0Ksection_start:`date +%s`:debconf[collapsed=true]\r\e[0KSetup debconf's environment"
- export DEBIAN_FRONTEND="noninteractive"
- export DEBIAN_PRIORITY="low"
- export DEBCONF_NONINTERACTIVE_SEEN="true"
- |
# debconf
echo -e "\e[0Ksection_end:`date +%s`:debconf\r\e[0K"
- - |
# dpkg_aa
echo -e "\e[0Ksection_start:`date +%s`:dpkg_aa[collapsed=true]\r\e[0KAdding architectures to dpkg"
- dpkg --add-architecture i386
- dpkg --add-architecture amd64
- dpkg --add-architecture arm64
- |
# dpkg_aa
echo -e "\e[0Ksection_end:`date +%s`:dpkg_aa\r\e[0K"
- - |
# apt_conf
echo -e "\e[0Ksection_start:`date +%s`:apt_conf[collapsed=true]\r\e[0KSetting up APT conf"
- export APT_CACHE_DIR=`pwd`/apt-cache
- mkdir --parents --verbose $APT_CACHE_DIR/partial/
- touch /etc/apt/apt.conf.d/99build
- |
# apt.conf
echo Adding options to apt.conf':'
- |
# APT::Install-Recommends
echo APT::Install-Recommends "false"\; | tee --append /etc/apt/apt.conf.d/99build
- |
# quit
echo quiet "1"\; | tee --append /etc/apt/apt.conf.d/99build
- |
# APT::Get::Assume-Yes
echo APT::Get::Assume-Yes "true"\; | tee --append /etc/apt/apt.conf.d/99build
- |
# Dir::Cache::Archives
echo Dir::Cache::Archives "$APT_CACHE_DIR"\; | tee --append /etc/apt/apt.conf.d/99build
- |
# apt_conf
echo -e "\e[0Ksection_end:`date +%s`:apt_conf\r\e[0K"
- - |
# apt_update
echo -e "\e[0Ksection_start:`date +%s`:apt_update[collapsed=true]\r\e[0KUpdating APT listing"
- apt-get update
- |
# apt_update
echo -e "\e[0Ksection_end:`date +%s`:apt_update\r\e[0K"
- - |
# apt_pre
echo -e "\e[0Ksection_start:`date +%s`:apt_pre[collapsed=true]\r\e[0KInstalling pre packages"
- apt-get install apt-utils
- |
# apt_pre
echo -e "\e[0Ksection_end:`date +%s`:apt_pre\r\e[0K"
- - |
# apt_upgrade
echo -e "\e[0Ksection_start:`date +%s`:apt_upgrade[collapsed=true]\r\e[0KUpdating existing packages"
- apt-get upgrade
- |
# apt_update
echo -e "\e[0Ksection_end:`date +%s`:apt_upgrade\r\e[0K"
- - |
# apt_common
echo -e "\e[0Ksection_start:`date +%s`:apt_common[collapsed=true]\r\e[0KInstalling common packages"
- apt-get install make git ccache nasm
- |
# apt_common
echo -e "\e[0Ksection_end:`date +%s`:apt_common\r\e[0K"
- - |
# ccache_config
echo -e "\e[0Ksection_start:`date +%s`:ccache_config[collapsed=true]\r\e[0KSetting up ccache config"
- mkdir --parents --verbose ~/.ccache/
- touch ~/.ccache/ccache.conf
- |
# cache.conf
echo Adding ccache configution option
- |
# base_dir
echo base_dir = $PWD | tee --append ~/.ccache/ccache.conf
- |
# cache_dir
echo cache_dir = $PWD/ccache | tee --append ~/.ccache/ccache.conf
- |
# compiler_check
echo compiler_check = content | tee --append ~/.ccache/ccache.conf
- |
# stats_log
echo stats_log = $PWD/ccache_statslog | tee --append ~/.ccache/ccache.conf
- |
# max_size
echo max_size = 50M | tee --append ~/.ccache/ccache.conf
- |
# ccache_config
echo -e "\e[0Ksection_end:`date +%s`:ccache_config\r\e[0K"
- - |
# cache_reset
echo -e "\e[0Ksection_start:`date +%s`:ccache_reset[collapsed=true]\r\e[0KResetting ccache statistics"
- ccache --zero-stats
- ccache --show-stats
- |
# ccache_reset
echo -e "\e[0Ksection_end:`date +%s`:ccache_reset\r\e[0K"
artifacts:
paths:
- "bin/"
- "src/comptime.h"
name: "$CI_PROJECT_PATH_SLUG-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA-$CI_JOB_NAME_SLUG"
after_script:
- - |
# apt_clean
echo -e "\e[0Ksection_start:`date +%s`:apt_clean[collapsed=true]\r\e[0KCleaning of unneeded APT packages"
- apt-get autoclean
- |
# apt_clean
echo -e "\e[0Ksection_end:`date +%s`:apt_clean\r\e[0K"
- - |
# ccache_stats
echo -e "\e[0Ksection_start:`date +%s`:ccache_stats[collapsed=true]\r\e[0Kccache statistics:"
- ccache --show-stats --verbose
- ccache --show-log-stats --verbose
- |
# ccahe_stats
echo -e "\e[0Ksection_end:`date +%s`:ccache_stats\r\e[0K"
stages:
- build
Debian testing GCC:
stage: build
image: debian:testing-slim
allow_failure: true
artifacts:
name: "$CI_PROJECT_PATH_SLUG-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA-testing-gcc"
variables:
CC: gcc
LDFLAGS: -Wl,-fuse-ld=gold
script:
- - |
# apt_toolchain
echo -e "\e[0Ksection_start:`date +%s`:apt_toolchain[collapsed=true]\r\e[0KInstalling toolchain packages"
- apt-get install gcc
- |
# apt_toolchain
echo -e "\e[0Ksection_end:`date +%s`:apt_toolchain\r\e[0K"
- - |
# apt_development
echo -e "\e[0Ksection_start:`date +%s`:apt_development[collapsed=true]\r\e[0KInstalling development packages"
- apt-get install libsdl2-mixer-dev libpng-dev libcurl4-openssl-dev libgme-dev libopenmpt-dev
- |
# apt_development
echo -e "\e[0Ksection_end:`date +%s`:apt_development\r\e[0K"
- - |
# make
echo -e "\e[0Ksection_start:`date +%s`:make[collapsed=false]\r\e[0KCompiling SRB2"
- make --directory=src --keep-going CCACHE=1 ERRORMODE=1 NONX86=1 || make --directory=src --keep-going CCACHE=1 ERRORMODE=1 NONX86=1
- |
# make
echo -e "\e[0Ksection_end:`date +%s`:make\r\e[0K"
Windows x86:
stage: build
artifacts:
paths:
- "bin/"
- "src/comptime.h"
expose_as: "Win32"
name: "$CI_PROJECT_PATH_SLUG-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA-Win32"
variables:
PREFIX: i686-w64-mingw32
script:
- - |
# apt_toolchain
echo -e "\e[0Ksection_start:`date +%s`:apt_toolchain[collapsed=true]\r\e[0KInstalling toolchain packages"
- apt-get install gcc-mingw-w64-i686-win32
- |
# apt_toolchain
echo -e "\e[0Ksection_end:`date +%s`:apt_toolchain\r\e[0K"
- - |
# make
echo -e "\e[0Ksection_start:`date +%s`:make[collapsed=false]\r\e[0KCompiling SRB2"
- make --directory=src --keep-going CCACHE=1 ERRORMODE=1 MINGW=1 SDL=1 || make --directory=src --keep-going CCACHE=1 ERRORMODE=1 MINGW=1 SDL=1
- |
# make
echo -e "\e[0Ksection_end:`date +%s`:make\r\e[0K"
Debian stable:amd64:
stage: build
artifacts:
paths:
- "bin/"
- "src/comptime.h"
expose_as: "Debian amd64"
name: "$CI_PROJECT_PATH_SLUG-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA-x86-64"
variables:
CC: x86_64-linux-gnu-gcc
LDFLAGS: -Wl,-fuse-ld=gold
OBJCOPY: x86_64-linux-gnu-objcopy
OBJDUMP: x86_64-linux-gnu-objdump
PKG_CONFIG_PATH: /usr/lib/x86_64-linux-gnu/pkgconfig
script:
- - |
# apt_toolchain
echo -e "\e[0Ksection_start:`date +%s`:apt_toolchain[collapsed=true]\r\e[0KInstalling toolchain packages"
- apt-get install gcc-x86-64-linux-gnu || apt-get install gcc
- |
# apt_toolchain
echo -e "\e[0Ksection_end:`date +%s`:apt_toolchain\r\e[0K"
- - |
# apt_development
echo -e "\e[0Ksection_start:`date +%s`:apt_development[collapsed=true]\r\e[0KInstalling development packages"
- apt-get install libsdl2-mixer-dev:amd64 libpng-dev:amd64 libcurl4-openssl-dev:amd64 libgme-dev:amd64 libopenmpt-dev:amd64
- |
# apt_development
echo -e "\e[0Ksection_end:`date +%s`:apt_development\r\e[0K"
- - |
# make
echo -e "\e[0Ksection_start:`date +%s`:make[collapsed=false]\r\e[0KCompiling SRB2"
- make --directory=src --keep-going CCACHE=1 ERRORMODE=1 LINUX64=1 || make --directory=src --keep-going CCACHE=1 ERRORMODE=1 LINUX64=1
- |
# make
echo -e "\e[0Ksection_end:`date +%s`:make\r\e[0K"
Debian stable:i386:
stage: build
artifacts:
paths:
- "bin/"
- "src/comptime.h"
expose_as: "Debian i386"
name: "$CI_PROJECT_PATH_SLUG-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA-i686"
variables:
CC: i686-linux-gnu-gcc
OBJCOPY: i686-linux-gnu-objcopy
OBJDUMP: i686-linux-gnu-objdump
PKG_CONFIG_PATH: /usr/lib/i386-linux-gnu/pkgconfig
script:
- - |
# apt_toolchain
echo -e "\e[0Ksection_start:`date +%s`:apt_toolchain[collapsed=true]\r\e[0KInstalling toolchain packages"
- apt-get install gcc-i686-linux-gnu || apt-get install gcc
- |
# apt_toolchain
echo -e "\e[0Ksection_end:`date +%s`:apt_toolchain\r\e[0K"
- - |
# apt_development
echo -e "\e[0Ksection_start:`date +%s`:apt_development[collapsed=true]\r\e[0KInstalling development packages"
- apt-get install libsdl2-mixer-dev:i386 libpng-dev:i386 libcurl4-openssl-dev:i386 libgme-dev:i386 libopenmpt-dev:i386
- |
# apt_development
echo -e "\e[0Ksection_end:`date +%s`:apt_development\r\e[0K"
- - |
# make
echo -e "\e[0Ksection_start:`date +%s`:make[collapsed=false]\r\e[0KCompiling SRB2"
- make --directory=src --keep-going CCACHE=1 ERRORMODE=1 LINUX=1 || make --directory=src --keep-going CCACHE=1 ERRORMODE=1 LINUX=1
- |
# make
echo -e "\e[0Ksection_end:`date +%s`:make\r\e[0K"
Debian stable:arm64:
stage: build
artifacts:
paths:
- "bin/"
- "src/comptime.h"
expose_as: "Debian arm64"
name: "$CI_PROJECT_PATH_SLUG-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA-aarch64"
variables:
CC: aarch64-linux-gnu-gcc
LDFLAGS: -Wl,-fuse-ld=gold
OBJCOPY: aarch64-linux-gnu-objcopy
OBJDUMP: aarch64-linux-gnu-objdump
PKG_CONFIG_PATH: /usr/lib/aarch64-linux-gnu/pkgconfig
script:
- - |
# apt_toolchain
echo -e "\e[0Ksection_start:`date +%s`:apt_toolchain[collapsed=true]\r\e[0KInstalling toolchain packages"
- apt-get install gcc-aarch64-linux-gnu || apt-get install gcc
- |
# apt_toolchain
echo -e "\e[0Ksection_end:`date +%s`:apt_toolchain\r\e[0K"
- - |
# apt_development
echo -e "\e[0Ksection_start:`date +%s`:apt_development[collapsed=true]\r\e[0KInstalling development packages"
- apt-get install libsdl2-mixer-dev:arm64 libpng-dev:arm64 libcurl4-openssl-dev:arm64 libgme-dev:arm64 libopenmpt-dev:arm64
- |
# apt_development
echo -e "\e[0Ksection_end:`date +%s`:apt_development\r\e[0K"
- - |
# make
echo -e "\e[0Ksection_start:`date +%s`:make[collapsed=false]\r\e[0KCompiling SRB2"
- make --directory=src --keep-going CCACHE=1 ERRORMODE=1 LINUX64=1 ERRORMODE=1 NONX86=1 || make --directory=src --keep-going CCACHE=1 ERRORMODE=1 LINUX64=1 NONX86=1
- |
# make
echo -e "\e[0Ksection_end:`date +%s`:make\r\e[0K"
Windows x64:
stage: build
artifacts:
paths:
- "bin/"
- "src/comptime.h"
expose_as: "Win64"
name: "$CI_PROJECT_PATH_SLUG-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA-Win64"
variables:
PREFIX: x86_64-w64-mingw32
script:
- - |
# apt_toolchain
echo -e "\e[0Ksection_start:`date +%s`:apt_toolchain[collapsed=true]\r\e[0KInstalling toolchain packages"
- apt-get install gcc-mingw-w64-x86-64-win32
- |
# apt_toolchain
echo -e "\e[0Ksection_end:`date +%s`:apt_toolchain\r\e[0K"
- - |
# make
echo -e "\e[0Ksection_start:`date +%s`:make[collapsed=false]\r\e[0KCompiling SRB2"
- make --directory=src --keep-going CCACHE=1 ERRORMODE=1 MINGW64=1 SDL=1 || make --directory=src --keep-going CCACHE=1 ERRORMODE=1 MINGW64=1 SDL=1
- |
# make
echo -e "\e[0Ksection_end:`date +%s`:make\r\e[0K"
Debian stable Clang:
stage: build
allow_failure: true
artifacts:
name: "$CI_PROJECT_PATH_SLUG-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA-clang"
variables:
CC: clang
WFLAGS: -Wno-cast-align
CFLAGS: -Wno-cast-align
LDFLAGS: -Wl,-fuse-ld=gold
script:
- - |
# apt_toolchain
echo -e "\e[0Ksection_start:`date +%s`:apt_toolchain[collapsed=true]\r\e[0KInstalling toolchain packages"
- apt-get install clang
- |
# apt_toolchain
echo -e "\e[0Ksection_end:`date +%s`:apt_toolchain\r\e[0K"
- - |
# apt_development
echo -e "\e[0Ksection_start:`date +%s`:apt_development[collapsed=true]\r\e[0KInstalling development packages"
- apt-get install libsdl2-mixer-dev libpng-dev libcurl4-openssl-dev libgme-dev libopenmpt-dev
- |
# apt_development
echo -e "\e[0Ksection_end:`date +%s`:apt_development\r\e[0K"
- - |
# make
echo -e "\e[0Ksection_start:`date +%s`:make[collapsed=false]\r\e[0KCompiling SRB2"
- make --directory=src --keep-going CCACHE=1 ERRORMODE=1 NONX86=1 || make --directory=src --keep-going CCACHE=1 ERRORMODE=1 NONX86=1
- |
# make
echo -e "\e[0Ksection_end:`date +%s`:make\r\e[0K"
Debian testing Clang:
extends: Debian stable Clang
image: debian:testing-slim
artifacts:
name: "$CI_PROJECT_PATH_SLUG-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA-testing-clang"
variables:
CC: clang
WFLAGS: -Wno-cast-align -Wno-deprecated-non-prototype
CFLAGS: -Wno-cast-align -Wno-deprecated-non-prototype
LDFLAGS: -Wl,-fuse-ld=gold

View file

@ -3,12 +3,12 @@ ifdef ComSpec
COMSPEC=$(ComSpec) COMSPEC=$(ComSpec)
endif endif
ifdef COMSPEC ifdef COMSPEC
OBJCOPY=objcopy.exe OBJCOPY?=objcopy.exe
OBJDUMP=objdump.exe OBJDUMP?=objdump.exe
GZIP?=gzip.exe GZIP?=gzip.exe
else else
OBJCOPY=objcopy OBJCOPY?=objcopy
OBJDUMP=objdump OBJDUMP?=objdump
GZIP?=gzip GZIP?=gzip
endif endif
DBGNAME=$(BIN).debug DBGNAME=$(BIN).debug

View file

@ -8,11 +8,7 @@ LOCAL_SRC_FILES := am_map.c \
command.c \ command.c \
comptime.c \ comptime.c \
console.c \ console.c \
d_clisrv.c \
d_main.c \ d_main.c \
d_net.c \
d_netcmd.c \
d_netfil.c \
dehacked.c \ dehacked.c \
f_finale.c \ f_finale.c \
f_wipe.c \ f_wipe.c \
@ -20,7 +16,6 @@ LOCAL_SRC_FILES := am_map.c \
g_game.c \ g_game.c \
g_input.c \ g_input.c \
hu_stuff.c \ hu_stuff.c \
i_tcp.c \
info.c \ info.c \
lzf.c \ lzf.c \
m_argv.c \ m_argv.c \
@ -32,7 +27,6 @@ LOCAL_SRC_FILES := am_map.c \
m_queue.c \ m_queue.c \
m_random.c \ m_random.c \
md5.c \ md5.c \
mserv.c \
p_ceilng.c \ p_ceilng.c \
p_enemy.c \ p_enemy.c \
p_fab.c \ p_fab.c \
@ -61,6 +55,7 @@ LOCAL_SRC_FILES := am_map.c \
r_things.c \ r_things.c \
s_sound.c \ s_sound.c \
screen.c \ screen.c \
snake.c \
sounds.c \ sounds.c \
st_stuff.c \ st_stuff.c \
string.c \ string.c \

View file

@ -6,10 +6,6 @@ add_executable(SRB2SDL2 MACOSX_BUNDLE WIN32
config.h.in config.h.in
string.c string.c
d_main.c d_main.c
d_clisrv.c
d_net.c
d_netfil.c
d_netcmd.c
dehacked.c dehacked.c
deh_soc.c deh_soc.c
deh_lua.c deh_lua.c
@ -83,12 +79,10 @@ add_executable(SRB2SDL2 MACOSX_BUNDLE WIN32
sounds.c sounds.c
w_wad.c w_wad.c
filesrch.c filesrch.c
mserv.c
http-mserv.c
i_tcp.c
lzf.c lzf.c
b_bot.c b_bot.c
u_list.c u_list.c
snake.c
lua_script.c lua_script.c
lua_baselib.c lua_baselib.c
lua_mathlib.c lua_mathlib.c
@ -149,6 +143,7 @@ set(SRB2_CONFIG_DEV_BUILD OFF CACHE BOOL
"Compile a development build of SRB2.") "Compile a development build of SRB2.")
add_subdirectory(blua) add_subdirectory(blua)
add_subdirectory(netcode)
# OS macros # OS macros
if (UNIX) if (UNIX)

View file

@ -62,7 +62,6 @@
# #
# Netplay incompatible # Netplay incompatible
# -------------------- # --------------------
# NONET=1 - Disable online capability.
# NOMD5=1 - Disable MD5 checksum (validation tool). # NOMD5=1 - Disable MD5 checksum (validation tool).
# NOPOSTPROCESSING=1 - ? # NOPOSTPROCESSING=1 - ?
# MOBJCONSISTANCY=1 - ?? # MOBJCONSISTANCY=1 - ??
@ -141,9 +140,9 @@ endif
OBJDUMP_OPTS?=--wide --source --line-numbers OBJDUMP_OPTS?=--wide --source --line-numbers
OBJCOPY:=$(call Prefix,objcopy) OBJCOPY?=$(call Prefix,objcopy)
OBJDUMP:=$(call Prefix,objdump) OBJDUMP?=$(call Prefix,objdump)
WINDRES:=$(call Prefix,windres) WINDRES?=$(call Prefix,windres)
GZIP?=gzip GZIP?=gzip
GZIP_OPTS?=-9 -f -n GZIP_OPTS?=-9 -f -n
@ -187,6 +186,7 @@ objdir:=$(makedir)/objs
sources+=\ sources+=\
$(call List,Sourcefile)\ $(call List,Sourcefile)\
$(call List,blua/Sourcefile)\ $(call List,blua/Sourcefile)\
$(call List,netcode/Sourcefile)\
depends:=$(basename $(filter %.c %.s,$(sources))) depends:=$(basename $(filter %.c %.s,$(sources)))
objects:=$(basename $(filter %.c %.s %.nas,$(sources))) objects:=$(basename $(filter %.c %.s %.nas,$(sources)))

View file

@ -56,15 +56,18 @@ endif
# This must have high to low order. # This must have high to low order.
gcc_versions:=\ gcc_versions:=\
102 101\ 132 131 130\
93 92 91\ 123 122 121 120\
84 83 82 81\ 114 113 112 111 110\
75 74 73 72 71\ 105 104 103 102 101 100\
64 63 62 61\ 95 94 93 92 91 90\
55 54 53 52 51\ 85 84 83 82 81 80\
75 74 73 72 71 70\
64 63 62 61 60\
55 54 53 52 51 50\
49 48 47 46 45 44 43 42 41 40 49 48 47 46 45 44 43 42 41 40
latest_gcc_version:=10.2 latest_gcc_version:=13.2
# Automatically set version flag, but not if one was # Automatically set version flag, but not if one was
# manually set. And don't bother if this is a clean only # manually set. And don't bother if this is a clean only
@ -74,13 +77,18 @@ ifeq (,$(call Wildvar,GCC% destructive))
# can't use $(CC) --version here since that uses argv[0] to display the name # can't use $(CC) --version here since that uses argv[0] to display the name
# also gcc outputs the information to stderr, so I had to do 2>&1 # also gcc outputs the information to stderr, so I had to do 2>&1
# this program really doesn't like identifying itself # this program really doesn't like identifying itself
version:=$(shell $(CC) -v 2>&1) shellversion:=$(shell $(CC) -v 2>&1)
# Try to remove "-win32"
version:=$(subst -win32,.0,$(shellversion))
# check if this is in fact GCC # check if this is in fact GCC
ifneq (,$(findstring gcc version,$(version))) ifneq (,$(findstring gcc version,$(version)))
# in stark contrast to the name, gcc will give me a nicely formatted version number for free # in stark contrast to the name, gcc will give me a nicely formatted version number for free
version:=$(shell $(CC) -dumpfullversion) shellversion:=$(shell $(CC) -dumpfullversion)
# Try to remove "-win32"
version:=$(subst -win32,.0,$(shellversion))
# Turn version into words of major, minor # Turn version into words of major, minor
v:=$(subst ., ,$(version)) v:=$(subst ., ,$(version))

View file

@ -1,68 +1,66 @@
# #
# Makefile for feature flags. # Makefile for feature flags.
# #
passthru_opts+=\ passthru_opts+=\
NONET NO_IPV6 NOHW NOMD5 NOPOSTPROCESSING\ NO_IPV6 NOHW NOMD5 NOPOSTPROCESSING\
MOBJCONSISTANCY PACKETDROP ZDEBUG\ MOBJCONSISTANCY PACKETDROP ZDEBUG\
HAVE_MINIUPNPC\ HAVE_MINIUPNPC\
# build with debugging information # build with debugging information
ifdef DEBUGMODE ifdef DEBUGMODE
PACKETDROP=1 PACKETDROP=1
opts+=-DPARANOIA -DRANGECHECK opts+=-DPARANOIA -DRANGECHECK
endif endif
ifndef NOHW ifndef NOHW
opts+=-DHWRENDER opts+=-DHWRENDER
sources+=$(call List,hardware/Sourcefile) sources+=$(call List,hardware/Sourcefile)
endif endif
ifndef NOMD5 ifndef NOMD5
sources+=md5.c sources+=md5.c
endif endif
ifndef NOZLIB ifndef NOZLIB
ifndef NOPNG ifndef NOPNG
ifdef PNG_PKGCONFIG ifdef PNG_PKGCONFIG
$(eval $(call Use_pkg_config,PNG_PKGCONFIG)) $(eval $(call Use_pkg_config,PNG_PKGCONFIG))
else else
PNG_CONFIG?=$(call Prefix,libpng-config) PNG_CONFIG?=$(call Prefix,libpng-config)
$(eval $(call Configure,PNG,$(PNG_CONFIG) \ $(eval $(call Configure,PNG,$(PNG_CONFIG) \
$(if $(PNG_STATIC),--static),,--ldflags)) $(if $(PNG_STATIC),--static),,--ldflags))
endif endif
ifdef LINUX ifdef LINUX
opts+=-D_LARGEFILE64_SOURCE opts+=-D_LARGEFILE64_SOURCE
endif endif
opts+=-DHAVE_PNG opts+=-DHAVE_PNG
sources+=apng.c sources+=apng.c
endif endif
endif endif
ifndef NONET ifndef NOCURL
ifndef NOCURL CURLCONFIG?=curl-config
CURLCONFIG?=curl-config $(eval $(call Configure,CURL,$(CURLCONFIG)))
$(eval $(call Configure,CURL,$(CURLCONFIG))) opts+=-DHAVE_CURL
opts+=-DHAVE_CURL endif
endif
endif ifdef HAVE_MINIUPNPC
libs+=-lminiupnpc
ifdef HAVE_MINIUPNPC endif
libs+=-lminiupnpc
endif # (Valgrind is a memory debugger.)
ifdef VALGRIND
# (Valgrind is a memory debugger.) VALGRIND_PKGCONFIG?=valgrind
ifdef VALGRIND $(eval $(call Use_pkg_config,VALGRIND))
VALGRIND_PKGCONFIG?=valgrind ZDEBUG=1
$(eval $(call Use_pkg_config,VALGRIND)) opts+=-DHAVE_VALGRIND
ZDEBUG=1 endif
opts+=-DHAVE_VALGRIND
endif default_packages:=\
GME/libgme/LIBGME\
default_packages:=\ OPENMPT/libopenmpt/LIBOPENMPT\
GME/libgme/LIBGME\ ZLIB/zlib\
OPENMPT/libopenmpt/LIBOPENMPT\
ZLIB/zlib\ $(foreach p,$(default_packages),\
$(eval $(call Check_pkg_config,$(p))))
$(foreach p,$(default_packages),\
$(eval $(call Check_pkg_config,$(p))))

View file

@ -33,12 +33,10 @@ libs+=-lws2_32
endif endif
endif endif
ifndef NONET
ifndef MINGW64 # miniupnc is broken with MINGW64 ifndef MINGW64 # miniupnc is broken with MINGW64
opts+=-I../libs -DSTATIC_MINIUPNPC opts+=-I../libs -DSTATIC_MINIUPNPC
libs+=-L../libs/miniupnpc/mingw$(32) -lws2_32 -liphlpapi libs+=-L../libs/miniupnpc/mingw$(32) -lws2_32 -liphlpapi
endif endif
endif
ifndef MINGW64 ifndef MINGW64
32=32 32=32

View file

@ -1,9 +1,5 @@
string.c string.c
d_main.c d_main.c
d_clisrv.c
d_net.c
d_netfil.c
d_netcmd.c
dehacked.c dehacked.c
deh_soc.c deh_soc.c
deh_lua.c deh_lua.c
@ -77,12 +73,10 @@ s_sound.c
sounds.c sounds.c
w_wad.c w_wad.c
filesrch.c filesrch.c
mserv.c
http-mserv.c
i_tcp.c
lzf.c lzf.c
b_bot.c b_bot.c
u_list.c u_list.c
snake.c
lua_script.c lua_script.c
lua_baselib.c lua_baselib.c
lua_mathlib.c lua_mathlib.c

View file

@ -1,4 +1,4 @@
#include "../i_net.h" #include "../netcode/i_net.h"
boolean I_InitNetwork(void) boolean I_InitNetwork(void)
{ {

View file

@ -19,7 +19,8 @@
#include "lualib.h" #include "lualib.h"
#include "../i_system.h" #include "../i_system.h"
#include "../g_game.h" #include "../g_game.h"
#include "../d_netfil.h" #include "../netcode/d_netfil.h"
#include "../netcode/net_command.h"
#include "../lua_libs.h" #include "../lua_libs.h"
#include "../byteptr.h" #include "../byteptr.h"
#include "../lua_script.h" #include "../lua_script.h"

View file

@ -28,11 +28,12 @@
#include "byteptr.h" #include "byteptr.h"
#include "p_saveg.h" #include "p_saveg.h"
#include "g_game.h" // for player_names #include "g_game.h" // for player_names
#include "d_netcmd.h" #include "netcode/d_netcmd.h"
#include "netcode/net_command.h"
#include "hu_stuff.h" #include "hu_stuff.h"
#include "p_setup.h" #include "p_setup.h"
#include "lua_script.h" #include "lua_script.h"
#include "d_netfil.h" // findfile #include "netcode/d_netfil.h" // findfile
#include "r_data.h" // Color_cons_t #include "r_data.h" // Color_cons_t
#include "d_main.h" // D_IsPathAllowed #include "d_main.h" // D_IsPathAllowed

File diff suppressed because it is too large Load diff

View file

@ -34,7 +34,7 @@
#include "doomdef.h" #include "doomdef.h"
#include "am_map.h" #include "am_map.h"
#include "console.h" #include "console.h"
#include "d_net.h" #include "netcode/d_net.h"
#include "f_finale.h" #include "f_finale.h"
#include "g_game.h" #include "g_game.h"
#include "hu_stuff.h" #include "hu_stuff.h"
@ -56,11 +56,11 @@
#include "w_wad.h" #include "w_wad.h"
#include "z_zone.h" #include "z_zone.h"
#include "d_main.h" #include "d_main.h"
#include "d_netfil.h" #include "netcode/d_netfil.h"
#include "m_cheat.h" #include "m_cheat.h"
#include "y_inter.h" #include "y_inter.h"
#include "p_local.h" // chasecam #include "p_local.h" // chasecam
#include "mserv.h" // ms_RoomId #include "netcode/mserv.h" // ms_RoomId
#include "m_misc.h" // screenshot functionality #include "m_misc.h" // screenshot functionality
#include "deh_tables.h" // Dehacked list test #include "deh_tables.h" // Dehacked list test
#include "m_cond.h" // condition initialization #include "m_cond.h" // condition initialization

View file

@ -34,7 +34,7 @@
#include "r_sky.h" #include "r_sky.h"
#include "fastcmp.h" #include "fastcmp.h"
#include "lua_script.h" // Reluctantly included for LUA_EvalMath #include "lua_script.h" // Reluctantly included for LUA_EvalMath
#include "d_clisrv.h" #include "netcode/d_clisrv.h"
#ifdef HWRENDER #ifdef HWRENDER
#include "hardware/hw_light.h" #include "hardware/hw_light.h"

View file

@ -35,7 +35,7 @@
#include "r_sky.h" #include "r_sky.h"
#include "fastcmp.h" #include "fastcmp.h"
#include "lua_script.h" // Reluctantly included for LUA_EvalMath #include "lua_script.h" // Reluctantly included for LUA_EvalMath
#include "d_clisrv.h" #include "netcode/d_clisrv.h"
#ifdef HWRENDER #ifdef HWRENDER
#include "hardware/hw_light.h" #include "hardware/hw_light.h"

View file

@ -4883,7 +4883,7 @@ const char *const MENUTYPES_LIST[] = {
"MP_SERVER", "MP_SERVER",
"MP_CONNECT", "MP_CONNECT",
"MP_ROOM", "MP_ROOM",
"MP_PLAYERSETUP", // MP_PlayerSetupDef shared with SPLITSCREEN if #defined NONET "MP_PLAYERSETUP",
"MP_SERVER_OPTIONS", "MP_SERVER_OPTIONS",
// Options // Options

View file

@ -56,7 +56,6 @@
#endif #endif
#ifdef _WINDOWS #ifdef _WINDOWS
#define NONET
#if !defined (HWRENDER) && !defined (NOHW) #if !defined (HWRENDER) && !defined (NOHW)
#define HWRENDER #define HWRENDER
#endif #endif
@ -724,7 +723,7 @@ extern int
/// Maintain compatibility with older 2.2 demos /// Maintain compatibility with older 2.2 demos
#define OLD22DEMOCOMPAT #define OLD22DEMOCOMPAT
#if defined (HAVE_CURL) && ! defined (NONET) #ifdef HAVE_CURL
#define MASTERSERVER #define MASTERSERVER
#else #else
#undef UPDATE_ALERT #undef UPDATE_ALERT

View file

@ -634,7 +634,7 @@ extern boolean singletics;
// Netgame stuff // Netgame stuff
// ============= // =============
#include "d_clisrv.h" #include "netcode/d_clisrv.h"
extern consvar_t cv_timetic; // display high resolution timer extern consvar_t cv_timetic; // display high resolution timer
extern consvar_t cv_powerupdisplay; // display powerups extern consvar_t cv_powerupdisplay; // display powerups

View file

@ -1,4 +1,4 @@
#include "../i_net.h" #include "../netcode/i_net.h"
boolean I_InitNetwork(void) boolean I_InitNetwork(void)
{ {

View file

@ -14,13 +14,18 @@ size_t I_GetFreeMem(size_t *total)
return 0; return 0;
} }
void I_Sleep(UINT32 ms){} void I_Sleep(UINT32 ms)
{
(void)ms;
}
precise_t I_GetPreciseTime(void) { precise_t I_GetPreciseTime(void)
{
return 0; return 0;
} }
UINT64 I_GetPrecisePrecision(void) { UINT64 I_GetPrecisePrecision(void)
{
return 1000000; return 1000000;
} }
@ -182,10 +187,12 @@ const char *I_ClipboardPaste(void)
size_t I_GetRandomBytes(char *destination, size_t amount) size_t I_GetRandomBytes(char *destination, size_t amount)
{ {
(void)destination;
(void)amount;
return 0; return 0;
} }
void I_RegisterSysCommands(void) {} void I_RegisterSysCommands(void){}
void I_GetCursorPosition(INT32 *x, INT32 *y) void I_GetCursorPosition(INT32 *x, INT32 *y)
{ {

View file

@ -14,7 +14,7 @@
#include "doomdef.h" #include "doomdef.h"
#include "doomstat.h" #include "doomstat.h"
#include "d_main.h" #include "d_main.h"
#include "d_netcmd.h" #include "netcode/d_netcmd.h"
#include "f_finale.h" #include "f_finale.h"
#include "g_game.h" #include "g_game.h"
#include "hu_stuff.h" #include "hu_stuff.h"

View file

@ -26,7 +26,7 @@
#include <string.h> #include <string.h>
#include "filesrch.h" #include "filesrch.h"
#include "d_netfil.h" #include "netcode/d_netfil.h"
#include "m_misc.h" #include "m_misc.h"
#include "z_zone.h" #include "z_zone.h"
#include "m_menu.h" // Addons_option_Onchange #include "m_menu.h" // Addons_option_Onchange

View file

@ -5,7 +5,7 @@
#define __FILESRCH_H__ #define __FILESRCH_H__
#include "doomdef.h" #include "doomdef.h"
#include "d_netfil.h" #include "netcode/d_netfil.h"
#include "m_menu.h" // MAXSTRINGLENGTH #include "m_menu.h" // MAXSTRINGLENGTH
#include "w_wad.h" #include "w_wad.h"

View file

@ -15,7 +15,7 @@
#include "console.h" #include "console.h"
#include "d_main.h" #include "d_main.h"
#include "d_player.h" #include "d_player.h"
#include "d_clisrv.h" #include "netcode/d_clisrv.h"
#include "p_setup.h" #include "p_setup.h"
#include "i_time.h" #include "i_time.h"
#include "i_system.h" #include "i_system.h"
@ -39,7 +39,7 @@
#include "v_video.h" #include "v_video.h"
#include "lua_hook.h" #include "lua_hook.h"
#include "md5.h" // demo checksums #include "md5.h" // demo checksums
#include "d_netfil.h" // G_CheckDemoExtraFiles #include "netcode/d_netfil.h" // G_CheckDemoExtraFiles
boolean timingdemo; // if true, exit with report on completion boolean timingdemo; // if true, exit with report on completion
boolean nodrawers; // for comparative timing purposes boolean nodrawers; // for comparative timing purposes
@ -1891,16 +1891,9 @@ UINT8 G_CmpDemoTime(char *oldname, char *newname)
p++; // VERSION p++; // VERSION
p++; // SUBVERSION p++; // SUBVERSION
oldversion = READUINT16(p); oldversion = READUINT16(p);
switch(oldversion) // demoversion if (oldversion < 0x000c || oldversion > DEMOVERSION)
{ {
case DEMOVERSION: // latest always supported // too old (or new), cannot support
case 0x000f: // The previous demoversions also supported
case 0x000e:
case 0x000d: // all that changed between then and now was longer color name
case 0x000c:
break;
// too old, cannot support.
default:
CONS_Alert(CONS_NOTICE, M_GetText("File '%s' invalid format. It will be overwritten.\n"), oldname); CONS_Alert(CONS_NOTICE, M_GetText("File '%s' invalid format. It will be overwritten.\n"), oldname);
Z_Free(buffer); Z_Free(buffer);
return UINT8_MAX; return UINT8_MAX;
@ -1973,14 +1966,11 @@ void G_DoPlayDemo(char *defdemoname)
UINT8 i; UINT8 i;
lumpnum_t l; lumpnum_t l;
char skin[17],color[MAXCOLORNAME+1],*n,*pdemoname; char skin[17],color[MAXCOLORNAME+1],*n,*pdemoname;
UINT8 version,subversion,charability,charability2,thrustfactor,accelstart,acceleration,cnamelen; UINT8 version,subversion,charability,charability2,thrustfactor,accelstart,acceleration;
pflags_t pflags; pflags_t pflags;
UINT32 randseed, followitem; UINT32 randseed, followitem;
fixed_t camerascale,shieldscale,actionspd,mindash,maxdash,normalspeed,runspeed,jumpfactor,height,spinheight; fixed_t camerascale,shieldscale,actionspd,mindash,maxdash,normalspeed,runspeed,jumpfactor,height,spinheight;
char msg[1024]; char msg[1024];
#ifdef OLD22DEMOCOMPAT
boolean use_old_demo_vars = false;
#endif
skin[16] = '\0'; skin[16] = '\0';
color[MAXCOLORNAME] = '\0'; color[MAXCOLORNAME] = '\0';
@ -2039,23 +2029,13 @@ void G_DoPlayDemo(char *defdemoname)
subversion = READUINT8(demo_p); subversion = READUINT8(demo_p);
demoversion = READUINT16(demo_p); demoversion = READUINT16(demo_p);
demo_forwardmove_rng = (demoversion < 0x0010); demo_forwardmove_rng = (demoversion < 0x0010);
switch(demoversion)
{
case 0x000f:
case 0x000d:
case 0x000e:
case DEMOVERSION: // latest always supported
cnamelen = MAXCOLORNAME;
break;
#ifdef OLD22DEMOCOMPAT #ifdef OLD22DEMOCOMPAT
// all that changed between then and now was longer color name if (demoversion < 0x000c || demoversion > DEMOVERSION)
case 0x000c: #else
cnamelen = 16; if (demoversion < 0x000d || demoversion > DEMOVERSION)
use_old_demo_vars = true;
break;
#endif #endif
// too old, cannot support. {
default: // too old (or new), cannot support
snprintf(msg, 1024, M_GetText("%s is an incompatible replay format and cannot be played.\n"), pdemoname); snprintf(msg, 1024, M_GetText("%s is an incompatible replay format and cannot be played.\n"), pdemoname);
CONS_Alert(CONS_ERROR, "%s", msg); CONS_Alert(CONS_ERROR, "%s", msg);
M_StartMessage(msg, NULL, MM_NOTHING); M_StartMessage(msg, NULL, MM_NOTHING);
@ -2182,8 +2162,8 @@ void G_DoPlayDemo(char *defdemoname)
demo_p += 16; demo_p += 16;
// Color // Color
M_Memcpy(color,demo_p,cnamelen); M_Memcpy(color, demo_p, (demoversion < 0x000d) ? 16 : MAXCOLORNAME);
demo_p += cnamelen; demo_p += (demoversion < 0x000d) ? 16 : MAXCOLORNAME;
charability = READUINT8(demo_p); charability = READUINT8(demo_p);
charability2 = READUINT8(demo_p); charability2 = READUINT8(demo_p);
@ -2219,7 +2199,7 @@ void G_DoPlayDemo(char *defdemoname)
// net var data // net var data
#ifdef OLD22DEMOCOMPAT #ifdef OLD22DEMOCOMPAT
if (use_old_demo_vars) if (demoversion < 0x000d)
CV_LoadOldDemoVars(&demo_p); CV_LoadOldDemoVars(&demo_p);
else else
#endif #endif
@ -2352,19 +2332,13 @@ UINT8 G_CheckDemoForError(char *defdemoname)
demo_p++; // version demo_p++; // version
demo_p++; // subversion demo_p++; // subversion
our_demo_version = READUINT16(demo_p); our_demo_version = READUINT16(demo_p);
switch(our_demo_version)
{
case 0x000d:
case 0x000e:
case 0x000f:
case DEMOVERSION: // latest always supported
break;
#ifdef OLD22DEMOCOMPAT #ifdef OLD22DEMOCOMPAT
case 0x000c: if (our_demo_version < 0x000c || our_demo_version > DEMOVERSION)
break; #else
if (our_demo_version < 0x000d || our_demo_version > DEMOVERSION)
#endif #endif
// too old, cannot support. {
default: // too old (or new), cannot support
return DFILE_ERROR_NOTDEMO; return DFILE_ERROR_NOTDEMO;
} }
demo_p += 16; // demo checksum demo_p += 16; // demo checksum
@ -2386,7 +2360,6 @@ void G_AddGhost(char *defdemoname)
INT32 i; INT32 i;
lumpnum_t l; lumpnum_t l;
char name[17],skin[17],color[MAXCOLORNAME+1],*n,*pdemoname,md5[16]; char name[17],skin[17],color[MAXCOLORNAME+1],*n,*pdemoname,md5[16];
UINT8 cnamelen;
demoghost *gh; demoghost *gh;
UINT8 flags, subversion; UINT8 flags, subversion;
UINT8 *buffer,*p; UINT8 *buffer,*p;
@ -2438,20 +2411,9 @@ void G_AddGhost(char *defdemoname)
p++; // VERSION p++; // VERSION
subversion = READUINT8(p); // SUBVERSION subversion = READUINT8(p); // SUBVERSION
ghostversion = READUINT16(p); ghostversion = READUINT16(p);
switch(ghostversion) if (ghostversion < 0x000c || ghostversion > DEMOVERSION)
{ {
case 0x000f: // too old (or new), cannot support
case 0x000d:
case 0x000e:
case DEMOVERSION: // latest always supported
cnamelen = MAXCOLORNAME;
break;
// all that changed between then and now was longer color name
case 0x000c:
cnamelen = 16;
break;
// too old, cannot support.
default:
CONS_Alert(CONS_NOTICE, M_GetText("Ghost %s: Demo version incompatible.\n"), pdemoname); CONS_Alert(CONS_NOTICE, M_GetText("Ghost %s: Demo version incompatible.\n"), pdemoname);
Z_Free(pdemoname); Z_Free(pdemoname);
Z_Free(buffer); Z_Free(buffer);
@ -2514,8 +2476,8 @@ void G_AddGhost(char *defdemoname)
p += 16; p += 16;
// Color // Color
M_Memcpy(color, p,cnamelen); M_Memcpy(color, p, (ghostversion < 0x000d) ? 16 : MAXCOLORNAME);
p += cnamelen; p += (ghostversion < 0x000d) ? 16 : MAXCOLORNAME;
// Ghosts do not have a player structure to put this in. // Ghosts do not have a player structure to put this in.
p++; // charability p++; // charability
@ -2698,16 +2660,9 @@ void G_DoPlayMetal(void)
metal_p++; // VERSION metal_p++; // VERSION
metal_p++; // SUBVERSION metal_p++; // SUBVERSION
metalversion = READUINT16(metal_p); metalversion = READUINT16(metal_p);
switch(metalversion) if (metalversion < 0x000c || metalversion > DEMOVERSION)
{ {
case DEMOVERSION: // latest always supported // too old (or new), cannot support
case 0x000f:
case 0x000e: // There are checks wheter the momentum is from older demo versions or not
case 0x000d: // all that changed between then and now was longer color name
case 0x000c:
break;
// too old, cannot support.
default:
CONS_Alert(CONS_WARNING, M_GetText("Failed to load bot recording for this map, format version incompatible.\n")); CONS_Alert(CONS_WARNING, M_GetText("Failed to load bot recording for this map, format version incompatible.\n"));
Z_Free(metalbuffer); Z_Free(metalbuffer);
return; return;

View file

@ -15,7 +15,8 @@
#include "console.h" #include "console.h"
#include "d_main.h" #include "d_main.h"
#include "d_player.h" #include "d_player.h"
#include "d_clisrv.h" #include "netcode/d_clisrv.h"
#include "netcode/net_command.h"
#include "f_finale.h" #include "f_finale.h"
#include "p_setup.h" #include "p_setup.h"
#include "p_saveg.h" #include "p_saveg.h"

View file

@ -16,7 +16,7 @@
#include "g_input.h" #include "g_input.h"
#include "keys.h" #include "keys.h"
#include "hu_stuff.h" // need HUFONT start & end #include "hu_stuff.h" // need HUFONT start & end
#include "d_net.h" #include "netcode/d_net.h"
#include "console.h" #include "console.h"
#define MAXMOUSESENSITIVITY 100 // sensitivity steps #define MAXMOUSESENSITIVITY 100 // sensitivity steps

View file

@ -42,10 +42,10 @@ int unsortedVertexArrayAllocSize = 65536;
// Call HWR_RenderBatches to render all the collected geometry. // Call HWR_RenderBatches to render all the collected geometry.
void HWR_StartBatching(void) void HWR_StartBatching(void)
{ {
if (currently_batching) if (currently_batching)
I_Error("Repeat call to HWR_StartBatching without HWR_RenderBatches"); I_Error("Repeat call to HWR_StartBatching without HWR_RenderBatches");
// init arrays if that has not been done yet // init arrays if that has not been done yet
if (!finalVertexArray) if (!finalVertexArray)
{ {
finalVertexArray = malloc(finalVertexArrayAllocSize * sizeof(FOutVector)); finalVertexArray = malloc(finalVertexArrayAllocSize * sizeof(FOutVector));
@ -55,7 +55,7 @@ void HWR_StartBatching(void)
unsortedVertexArray = malloc(unsortedVertexArrayAllocSize * sizeof(FOutVector)); unsortedVertexArray = malloc(unsortedVertexArrayAllocSize * sizeof(FOutVector));
} }
currently_batching = true; currently_batching = true;
} }
// This replaces the direct calls to pfnSetTexture in cases where batching is available. // This replaces the direct calls to pfnSetTexture in cases where batching is available.

View file

@ -29,7 +29,7 @@
#include "../r_patch.h" #include "../r_patch.h"
#include "../r_picformats.h" #include "../r_picformats.h"
#include "../r_bsp.h" #include "../r_bsp.h"
#include "../d_clisrv.h" #include "../netcode/d_clisrv.h"
#include "../w_wad.h" #include "../w_wad.h"
#include "../z_zone.h" #include "../z_zone.h"
#include "../r_splats.h" #include "../r_splats.h"
@ -4141,14 +4141,11 @@ static void HWR_DrawSprite(gl_vissprite_t *spr)
float xscale, yscale; float xscale, yscale;
float xoffset, yoffset; float xoffset, yoffset;
float leftoffset, topoffset; float leftoffset, topoffset;
float scale = spr->scale;
float zoffset = (P_MobjFlip(spr->mobj) * 0.05f); float zoffset = (P_MobjFlip(spr->mobj) * 0.05f);
pslope_t *splatslope = NULL; pslope_t *splatslope = NULL;
INT32 i; INT32 i;
renderflags_t renderflags = spr->renderflags; renderflags_t renderflags = spr->renderflags;
if (renderflags & RF_SHADOWEFFECTS)
scale *= spr->shadowscale;
if (spr->rotateflags & SRF_3D || renderflags & RF_NOSPLATBILLBOARD) if (spr->rotateflags & SRF_3D || renderflags & RF_NOSPLATBILLBOARD)
angle = spr->mobj->angle; angle = spr->mobj->angle;

View file

@ -486,7 +486,7 @@ void HWR_InitModels(void)
size_t i; size_t i;
INT32 s; INT32 s;
FILE *f; FILE *f;
char name[24], filename[32]; char name[26], filename[32];
float scale, offset; float scale, offset;
size_t prefixlen; size_t prefixlen;
@ -585,7 +585,7 @@ modelfound:
void HWR_AddPlayerModel(int skin) // For skins that were added after startup void HWR_AddPlayerModel(int skin) // For skins that were added after startup
{ {
FILE *f; FILE *f;
char name[24], filename[32]; char name[26], filename[32];
float scale, offset; float scale, offset;
size_t prefixlen; size_t prefixlen;
@ -644,7 +644,7 @@ void HWR_AddSpriteModel(size_t spritenum) // For sprites that were added after s
// name[24] is used to check for names in the models.dat file that match with sprites or player skins // name[24] is used to check for names in the models.dat file that match with sprites or player skins
// sprite names are always 4 characters long, and names is for player skins can be up to 19 characters long // sprite names are always 4 characters long, and names is for player skins can be up to 19 characters long
// PLAYERMODELPREFIX is 6 characters long // PLAYERMODELPREFIX is 6 characters long
char name[24], filename[32]; char name[26], filename[32];
float scale, offset; float scale, offset;
if (nomd2s) if (nomd2s)

View file

@ -672,6 +672,9 @@ void GeneratePolygonNormals(model_t *model, int ztag)
for (k = 0; k < mesh->numTriangles; k++) for (k = 0; k < mesh->numTriangles; k++)
{ {
/// TODO: normalize vectors
(void)vertices;
(void)polyNormals;
// Vector::Normal(vertices, polyNormals); // Vector::Normal(vertices, polyNormals);
vertices += 3 * 3; vertices += 3 * 3;
polyNormals++; polyNormals++;

View file

@ -19,7 +19,9 @@
#include "m_cond.h" // emblems #include "m_cond.h" // emblems
#include "m_misc.h" // word jumping #include "m_misc.h" // word jumping
#include "d_clisrv.h" #include "netcode/d_clisrv.h"
#include "netcode/net_command.h"
#include "netcode/gamestate.h"
#include "g_game.h" #include "g_game.h"
#include "g_input.h" #include "g_input.h"
@ -175,14 +177,12 @@ static huddrawlist_h luahuddrawlist_scores;
static tic_t resynch_ticker = 0; static tic_t resynch_ticker = 0;
#ifndef NONET
// just after // just after
static void Command_Say_f(void); static void Command_Say_f(void);
static void Command_Sayto_f(void); static void Command_Sayto_f(void);
static void Command_Sayteam_f(void); static void Command_Sayteam_f(void);
static void Command_CSay_f(void); static void Command_CSay_f(void);
static void Got_Saycmd(UINT8 **p, INT32 playernum); static void Got_Saycmd(UINT8 **p, INT32 playernum);
#endif
void HU_LoadGraphics(void) void HU_LoadGraphics(void)
{ {
@ -327,13 +327,11 @@ void HU_LoadGraphics(void)
// //
void HU_Init(void) void HU_Init(void)
{ {
#ifndef NONET
COM_AddCommand("say", Command_Say_f, COM_LUA); COM_AddCommand("say", Command_Say_f, COM_LUA);
COM_AddCommand("sayto", Command_Sayto_f, COM_LUA); COM_AddCommand("sayto", Command_Sayto_f, COM_LUA);
COM_AddCommand("sayteam", Command_Sayteam_f, COM_LUA); COM_AddCommand("sayteam", Command_Sayteam_f, COM_LUA);
COM_AddCommand("csay", Command_CSay_f, COM_LUA); COM_AddCommand("csay", Command_CSay_f, COM_LUA);
RegisterNetXCmd(XD_SAY, Got_Saycmd); RegisterNetXCmd(XD_SAY, Got_Saycmd);
#endif
// set shift translation table // set shift translation table
shiftxform = english_shiftxform; shiftxform = english_shiftxform;
@ -363,8 +361,6 @@ void HU_Start(void)
// EXECUTION // EXECUTION
//====================================================================== //======================================================================
#ifndef NONET
// EVERY CHANGE IN THIS SCRIPT IS LOL XD! BY VINCYTM // EVERY CHANGE IN THIS SCRIPT IS LOL XD! BY VINCYTM
static UINT32 chat_nummsg_log = 0; static UINT32 chat_nummsg_log = 0;
@ -412,11 +408,9 @@ static void HU_removeChatText_Log(void)
} }
chat_nummsg_log--; // lost 1 msg. chat_nummsg_log--; // lost 1 msg.
} }
#endif
void HU_AddChatText(const char *text, boolean playsound) void HU_AddChatText(const char *text, boolean playsound)
{ {
#ifndef NONET
if (playsound && cv_consolechat.value != 2) // Don't play the sound if we're using hidden chat. if (playsound && cv_consolechat.value != 2) // Don't play the sound if we're using hidden chat.
S_StartSound(NULL, sfx_radio); S_StartSound(NULL, sfx_radio);
// reguardless of our preferences, put all of this in the chat buffer in case we decide to change from oldchat mid-game. // reguardless of our preferences, put all of this in the chat buffer in case we decide to change from oldchat mid-game.
@ -438,14 +432,8 @@ void HU_AddChatText(const char *text, boolean playsound)
CONS_Printf("%s\n", text); CONS_Printf("%s\n", text);
else // if we aren't, still save the message to log.txt else // if we aren't, still save the message to log.txt
CON_LogMessage(va("%s\n", text)); CON_LogMessage(va("%s\n", text));
#else
(void)playsound;
CONS_Printf("%s\n", text);
#endif
} }
#ifndef NONET
/** Runs a say command, sending an ::XD_SAY message. /** Runs a say command, sending an ::XD_SAY message.
* A say command consists of a signed 8-bit integer for the target, an * A say command consists of a signed 8-bit integer for the target, an
* unsigned 8-bit flag variable, and then the message itself. * unsigned 8-bit flag variable, and then the message itself.
@ -865,8 +853,6 @@ static void Got_Saycmd(UINT8 **p, INT32 playernum)
#endif #endif
} }
#endif
// //
// //
void HU_Ticker(void) void HU_Ticker(void)
@ -882,7 +868,6 @@ void HU_Ticker(void)
else else
hu_showscores = false; hu_showscores = false;
#ifndef NONET
if (chat_on) if (chat_on)
{ {
// count down the scroll timer. // count down the scroll timer.
@ -910,7 +895,6 @@ void HU_Ticker(void)
HU_removeChatText_Mini(); HU_removeChatText_Mini();
} }
} }
#endif
if (cechotimer > 0) --cechotimer; if (cechotimer > 0) --cechotimer;
@ -918,8 +902,6 @@ void HU_Ticker(void)
resynch_ticker++; resynch_ticker++;
} }
#ifndef NONET
static boolean teamtalk = false; static boolean teamtalk = false;
static boolean justscrolleddown; static boolean justscrolleddown;
static boolean justscrolledup; static boolean justscrolledup;
@ -1027,8 +1009,6 @@ static void HU_sendChatMessage(void)
} }
} }
#endif
void HU_clearChatChars(void) void HU_clearChatChars(void)
{ {
memset(w_chat, '\0', sizeof(w_chat)); memset(w_chat, '\0', sizeof(w_chat));
@ -1043,9 +1023,7 @@ void HU_clearChatChars(void)
// //
boolean HU_Responder(event_t *ev) boolean HU_Responder(event_t *ev)
{ {
#ifndef NONET
INT32 c=0; INT32 c=0;
#endif
if (ev->type != ev_keydown) if (ev->type != ev_keydown)
return false; return false;
@ -1072,7 +1050,6 @@ boolean HU_Responder(event_t *ev)
return false; return false;
}*/ //We don't actually care about that unless we get splitscreen netgames. :V }*/ //We don't actually care about that unless we get splitscreen netgames. :V
#ifndef NONET
c = (INT32)ev->key; c = (INT32)ev->key;
if (!chat_on) if (!chat_on)
@ -1222,7 +1199,6 @@ boolean HU_Responder(event_t *ev)
return true; return true;
} }
#endif
return false; return false;
} }
@ -1232,8 +1208,6 @@ boolean HU_Responder(event_t *ev)
// HEADS UP DRAWING // HEADS UP DRAWING
//====================================================================== //======================================================================
#ifndef NONET
// Precompile a wordwrapped string to any given width. // Precompile a wordwrapped string to any given width.
// This is a muuuch better method than V_WORDWRAP. // This is a muuuch better method than V_WORDWRAP.
// again stolen and modified a bit from video.c, don't mind me, will need to rearrange this one day. // again stolen and modified a bit from video.c, don't mind me, will need to rearrange this one day.
@ -1813,7 +1787,6 @@ static void HU_DrawChat_Old(void)
if (hu_tick < 4) if (hu_tick < 4)
V_DrawCharacter(HU_INPUTX + c, y, '_' | cv_constextsize.value |V_NOSCALESTART|t, true); V_DrawCharacter(HU_INPUTX + c, y, '_' | cv_constextsize.value |V_NOSCALESTART|t, true);
} }
#endif
// Draw crosshairs at the exact center of the view. // Draw crosshairs at the exact center of the view.
// In splitscreen, crosshairs are stretched vertically to compensate for V_PERPLAYER squishing them. // In splitscreen, crosshairs are stretched vertically to compensate for V_PERPLAYER squishing them.
@ -1953,7 +1926,6 @@ static void HU_DrawDemoInfo(void)
// //
void HU_Drawer(void) void HU_Drawer(void)
{ {
#ifndef NONET
// draw chat string plus cursor // draw chat string plus cursor
if (chat_on) if (chat_on)
{ {
@ -1970,7 +1942,6 @@ void HU_Drawer(void)
if (!OLDCHAT && cv_consolechat.value < 2 && netgame) // Don't display minimized chat if you set the mode to Window (Hidden) if (!OLDCHAT && cv_consolechat.value < 2 && netgame) // Don't display minimized chat if you set the mode to Window (Hidden)
HU_drawMiniChat(); // draw messages in a cool fashion. HU_drawMiniChat(); // draw messages in a cool fashion.
} }
#endif
if (cechotimer) if (cechotimer)
HU_DrawCEcho(); HU_DrawCEcho();

View file

@ -17,7 +17,7 @@
#include "command.h" #include "command.h"
#include "doomtype.h" #include "doomtype.h"
#include "d_netcmd.h" #include "netcode/d_netcmd.h"
#include "m_fixed.h" #include "m_fixed.h"
#include "i_system.h" #include "i_system.h"

View file

@ -26,11 +26,11 @@
#include "y_inter.h" #include "y_inter.h"
#include "hu_stuff.h" // HU_AddChatText #include "hu_stuff.h" // HU_AddChatText
#include "console.h" #include "console.h"
#include "d_netcmd.h" // IsPlayerAdmin #include "netcode/d_netcmd.h" // IsPlayerAdmin
#include "m_menu.h" // Player Setup menu color stuff #include "m_menu.h" // Player Setup menu color stuff
#include "m_misc.h" // M_MapNumber #include "m_misc.h" // M_MapNumber
#include "b_bot.h" // B_UpdateBotleader #include "b_bot.h" // B_UpdateBotleader
#include "d_clisrv.h" // CL_RemovePlayer #include "netcode/d_clisrv.h" // CL_RemovePlayer
#include "i_system.h" // I_GetPreciseTime, I_GetPrecisePrecision #include "i_system.h" // I_GetPreciseTime, I_GetPrecisePrecision
#include "lua_script.h" #include "lua_script.h"
@ -3544,7 +3544,7 @@ static int lib_gAddGametype(lua_State *L)
// Partly lifted from Got_AddPlayer // Partly lifted from Got_AddPlayer
static int lib_gAddPlayer(lua_State *L) static int lib_gAddPlayer(lua_State *L)
{ {
INT16 i, newplayernum, botcount = 1; INT16 i, newplayernum;
player_t *newplayer; player_t *newplayer;
SINT8 skinnum = 0, bot; SINT8 skinnum = 0, bot;
@ -3552,10 +3552,8 @@ static int lib_gAddPlayer(lua_State *L)
{ {
if (!playeringame[i]) if (!playeringame[i])
break; break;
if (players[i].bot)
botcount++; // How many of us are there already?
} }
if (i >= MAXPLAYERS) if (i >= MAXPLAYERS)
{ {
lua_pushnil(L); lua_pushnil(L);

View file

@ -16,6 +16,7 @@
#include "g_game.h" #include "g_game.h"
#include "byteptr.h" #include "byteptr.h"
#include "z_zone.h" #include "z_zone.h"
#include "netcode/net_command.h"
#include "lua_script.h" #include "lua_script.h"
#include "lua_libs.h" #include "lua_libs.h"

View file

@ -24,7 +24,7 @@
#include "lua_hud.h" // hud_running errors #include "lua_hud.h" // hud_running errors
#include "m_perfstats.h" #include "m_perfstats.h"
#include "d_netcmd.h" // for cv_perfstats #include "netcode/d_netcmd.h" // for cv_perfstats
#include "i_system.h" // I_GetPreciseTime #include "i_system.h" // I_GetPreciseTime
/* ========================================================================= /* =========================================================================

View file

@ -28,7 +28,7 @@
#include "p_slopes.h" // for P_SlopeById and slopelist #include "p_slopes.h" // for P_SlopeById and slopelist
#include "p_polyobj.h" // polyobj_t, PolyObjects #include "p_polyobj.h" // polyobj_t, PolyObjects
#ifdef LUA_ALLOW_BYTECODE #ifdef LUA_ALLOW_BYTECODE
#include "d_netfil.h" // for LUA_DumpFile #include "netcode/d_netfil.h" // for LUA_DumpFile
#endif #endif
#include "lua_script.h" #include "lua_script.h"

View file

@ -19,7 +19,7 @@
#include "r_local.h" #include "r_local.h"
#include "p_local.h" #include "p_local.h"
#include "p_setup.h" #include "p_setup.h"
#include "d_net.h" #include "netcode/d_net.h"
#include "m_cheat.h" #include "m_cheat.h"
#include "m_menu.h" #include "m_menu.h"

View file

@ -20,7 +20,7 @@
#include "doomdef.h" #include "doomdef.h"
#include "d_main.h" #include "d_main.h"
#include "d_netcmd.h" #include "netcode/d_netcmd.h"
#include "console.h" #include "console.h"
#include "r_fps.h" #include "r_fps.h"
#include "r_local.h" #include "r_local.h"
@ -53,8 +53,10 @@
#include "hardware/hw_main.h" #include "hardware/hw_main.h"
#endif #endif
#include "d_net.h" #include "netcode/d_net.h"
#include "mserv.h" #include "netcode/mserv.h"
#include "netcode/server_connection.h"
#include "netcode/client_connection.h"
#include "m_misc.h" #include "m_misc.h"
#include "m_anigif.h" #include "m_anigif.h"
#include "byteptr.h" #include "byteptr.h"
@ -149,9 +151,7 @@ levellist_mode_t levellistmode = LLM_CREATESERVER;
UINT8 maplistoption = 0; UINT8 maplistoption = 0;
static char joystickInfo[MAX_JOYSTICKS+1][29]; static char joystickInfo[MAX_JOYSTICKS+1][29];
#ifndef NONET
static UINT32 serverlistpage; static UINT32 serverlistpage;
#endif
static UINT8 numsaves = 0; static UINT8 numsaves = 0;
static saveinfo_t* savegameinfo = NULL; // Extra info about the save games. static saveinfo_t* savegameinfo = NULL; // Extra info about the save games.
@ -190,10 +190,8 @@ static void M_GoBack(INT32 choice);
static void M_StopMessage(INT32 choice); static void M_StopMessage(INT32 choice);
static boolean stopstopmessage = false; static boolean stopstopmessage = false;
#ifndef NONET
static void M_HandleServerPage(INT32 choice); static void M_HandleServerPage(INT32 choice);
static void M_RoomMenu(INT32 choice); static void M_RoomMenu(INT32 choice);
#endif
// Prototyping is fun, innit? // Prototyping is fun, innit?
// ========================================================================== // ==========================================================================
@ -296,7 +294,6 @@ static void M_SetupMultiPlayer2(INT32 choice);
static void M_StartSplitServerMenu(INT32 choice); static void M_StartSplitServerMenu(INT32 choice);
static void M_StartServer(INT32 choice); static void M_StartServer(INT32 choice);
static void M_ServerOptions(INT32 choice); static void M_ServerOptions(INT32 choice);
#ifndef NONET
static void M_StartServerMenu(INT32 choice); static void M_StartServerMenu(INT32 choice);
static void M_ConnectMenu(INT32 choice); static void M_ConnectMenu(INT32 choice);
static void M_ConnectMenuModChecks(INT32 choice); static void M_ConnectMenuModChecks(INT32 choice);
@ -304,7 +301,6 @@ static void M_Refresh(INT32 choice);
static void M_Connect(INT32 choice); static void M_Connect(INT32 choice);
static void M_ChooseRoom(INT32 choice); static void M_ChooseRoom(INT32 choice);
menu_t MP_MainDef; menu_t MP_MainDef;
#endif
// Options // Options
// Split into multiple parts due to size // Split into multiple parts due to size
@ -382,11 +378,9 @@ static void M_DrawVideoMode(void);
static void M_DrawColorMenu(void); static void M_DrawColorMenu(void);
static void M_DrawScreenshotMenu(void); static void M_DrawScreenshotMenu(void);
static void M_DrawMonitorToggles(void); static void M_DrawMonitorToggles(void);
#ifndef NONET
static void M_DrawConnectMenu(void); static void M_DrawConnectMenu(void);
static void M_DrawMPMainMenu(void); static void M_DrawMPMainMenu(void);
static void M_DrawRoomMenu(void); static void M_DrawRoomMenu(void);
#endif
static void M_DrawJoystick(void); static void M_DrawJoystick(void);
static void M_DrawSetupMultiPlayerMenu(void); static void M_DrawSetupMultiPlayerMenu(void);
static void M_DrawColorRamp(INT32 x, INT32 y, INT32 w, INT32 h, skincolor_t color); static void M_DrawColorRamp(INT32 x, INT32 y, INT32 w, INT32 h, skincolor_t color);
@ -401,10 +395,8 @@ static void M_HandleImageDef(INT32 choice);
static void M_HandleLoadSave(INT32 choice); static void M_HandleLoadSave(INT32 choice);
static void M_HandleLevelStats(INT32 choice); static void M_HandleLevelStats(INT32 choice);
static void M_HandlePlaystyleMenu(INT32 choice); static void M_HandlePlaystyleMenu(INT32 choice);
#ifndef NONET
static boolean M_CancelConnect(void); static boolean M_CancelConnect(void);
static void M_HandleConnectIP(INT32 choice); static void M_HandleConnectIP(INT32 choice);
#endif
static void M_HandleSetupMultiPlayer(INT32 choice); static void M_HandleSetupMultiPlayer(INT32 choice);
static void M_HandleVideoMode(INT32 choice); static void M_HandleVideoMode(INT32 choice);
@ -503,11 +495,7 @@ consvar_t cv_dummyloadless = CVAR_INIT ("dummyloadless", "In-game", CV_HIDEN, lo
static menuitem_t MainMenu[] = static menuitem_t MainMenu[] =
{ {
{IT_STRING|IT_CALL, NULL, "1 Player", M_SinglePlayerMenu, 76}, {IT_STRING|IT_CALL, NULL, "1 Player", M_SinglePlayerMenu, 76},
#ifndef NONET
{IT_STRING|IT_SUBMENU, NULL, "Multiplayer", &MP_MainDef, 84}, {IT_STRING|IT_SUBMENU, NULL, "Multiplayer", &MP_MainDef, 84},
#else
{IT_STRING|IT_CALL, NULL, "Multiplayer", M_StartSplitServerMenu, 84},
#endif
{IT_STRING|IT_CALL, NULL, "Extras", M_SecretsMenu, 92}, {IT_STRING|IT_CALL, NULL, "Extras", M_SecretsMenu, 92},
{IT_CALL |IT_STRING, NULL, "Addons", M_Addons, 100}, {IT_CALL |IT_STRING, NULL, "Addons", M_Addons, 100},
{IT_STRING|IT_CALL, NULL, "Options", M_Options, 108}, {IT_STRING|IT_CALL, NULL, "Options", M_Options, 108},
@ -930,16 +918,10 @@ static menuitem_t SP_PlayerMenu[] =
static menuitem_t MP_SplitServerMenu[] = static menuitem_t MP_SplitServerMenu[] =
{ {
{IT_STRING|IT_CALL, NULL, "Select Gametype/Level...", M_MapChange, 100}, {IT_STRING|IT_CALL, NULL, "Select Gametype/Level...", M_MapChange, 100},
#ifdef NONET // In order to keep player setup accessible.
{IT_STRING|IT_CALL, NULL, "Player 1 setup...", M_SetupMultiPlayer, 110},
{IT_STRING|IT_CALL, NULL, "Player 2 setup...", M_SetupMultiPlayer2, 120},
#endif
{IT_STRING|IT_CALL, NULL, "More Options...", M_ServerOptions, 130}, {IT_STRING|IT_CALL, NULL, "More Options...", M_ServerOptions, 130},
{IT_WHITESTRING|IT_CALL, NULL, "Start", M_StartServer, 140}, {IT_WHITESTRING|IT_CALL, NULL, "Start", M_StartServer, 140},
}; };
#ifndef NONET
static menuitem_t MP_MainMenu[] = static menuitem_t MP_MainMenu[] =
{ {
{IT_HEADER, NULL, "Join a game", NULL, 0}, {IT_HEADER, NULL, "Join a game", NULL, 0},
@ -1026,8 +1008,6 @@ menuitem_t MP_RoomMenu[] =
{IT_DISABLED, NULL, "", M_ChooseRoom, 162}, {IT_DISABLED, NULL, "", M_ChooseRoom, 162},
}; };
#endif
static menuitem_t MP_PlayerSetupMenu[] = static menuitem_t MP_PlayerSetupMenu[] =
{ {
{IT_KEYHANDLER, NULL, "", M_HandleSetupMultiPlayer, 0}, // name {IT_KEYHANDLER, NULL, "", M_HandleSetupMultiPlayer, 0}, // name
@ -1586,14 +1566,12 @@ enum
static menuitem_t OP_ServerOptionsMenu[] = static menuitem_t OP_ServerOptionsMenu[] =
{ {
{IT_HEADER, NULL, "General", NULL, 0}, {IT_HEADER, NULL, "General", NULL, 0},
#ifndef NONET
{IT_STRING | IT_CVAR | IT_CV_STRING, {IT_STRING | IT_CVAR | IT_CV_STRING,
NULL, "Server name", &cv_servername, 7}, NULL, "Server name", &cv_servername, 7},
{IT_STRING | IT_CVAR, NULL, "Max Players", &cv_maxplayers, 21}, {IT_STRING | IT_CVAR, NULL, "Max Players", &cv_maxplayers, 21},
{IT_STRING | IT_CVAR, NULL, "Allow Add-on Downloading", &cv_downloading, 26}, {IT_STRING | IT_CVAR, NULL, "Allow Add-on Downloading", &cv_downloading, 26},
{IT_STRING | IT_CVAR, NULL, "Allow players to join", &cv_allownewplayer, 31}, {IT_STRING | IT_CVAR, NULL, "Allow players to join", &cv_allownewplayer, 31},
{IT_STRING | IT_CVAR, NULL, "Minutes for reconnecting", &cv_rejointimeout, 36}, {IT_STRING | IT_CVAR, NULL, "Minutes for reconnecting", &cv_rejointimeout, 36},
#endif
{IT_STRING | IT_CVAR, NULL, "Map progression", &cv_advancemap, 41}, {IT_STRING | IT_CVAR, NULL, "Map progression", &cv_advancemap, 41},
{IT_STRING | IT_CVAR, NULL, "Intermission Timer", &cv_inttime, 46}, {IT_STRING | IT_CVAR, NULL, "Intermission Timer", &cv_inttime, 46},
@ -1632,7 +1610,6 @@ static menuitem_t OP_ServerOptionsMenu[] =
{IT_STRING | IT_CVAR, NULL, "Autobalance sizes", &cv_autobalance, 216}, {IT_STRING | IT_CVAR, NULL, "Autobalance sizes", &cv_autobalance, 216},
{IT_STRING | IT_CVAR, NULL, "Scramble on Map Change", &cv_scrambleonchange, 221}, {IT_STRING | IT_CVAR, NULL, "Scramble on Map Change", &cv_scrambleonchange, 221},
#ifndef NONET
{IT_HEADER, NULL, "Advanced", NULL, 230}, {IT_HEADER, NULL, "Advanced", NULL, 230},
{IT_STRING | IT_CVAR | IT_CV_STRING, NULL, "Master server", &cv_masterserver, 236}, {IT_STRING | IT_CVAR | IT_CV_STRING, NULL, "Master server", &cv_masterserver, 236},
@ -1640,7 +1617,6 @@ static menuitem_t OP_ServerOptionsMenu[] =
{IT_STRING | IT_CVAR, NULL, "Attempts to resynchronise", &cv_resynchattempts, 256}, {IT_STRING | IT_CVAR, NULL, "Attempts to resynchronise", &cv_resynchattempts, 256},
{IT_STRING | IT_CVAR, NULL, "Show IP Address of Joiners", &cv_showjoinaddress, 261}, {IT_STRING | IT_CVAR, NULL, "Show IP Address of Joiners", &cv_showjoinaddress, 261},
#endif
}; };
static menuitem_t OP_MonitorToggleMenu[] = static menuitem_t OP_MonitorToggleMenu[] =
@ -1954,11 +1930,7 @@ menu_t MP_SplitServerDef =
MTREE2(MN_MP_MAIN, MN_MP_SPLITSCREEN), MTREE2(MN_MP_MAIN, MN_MP_SPLITSCREEN),
"M_MULTI", "M_MULTI",
sizeof (MP_SplitServerMenu)/sizeof (menuitem_t), sizeof (MP_SplitServerMenu)/sizeof (menuitem_t),
#ifndef NONET
&MP_MainDef, &MP_MainDef,
#else
&MainDef,
#endif
MP_SplitServerMenu, MP_SplitServerMenu,
M_DrawServerMenu, M_DrawServerMenu,
27, 30 - 50, 27, 30 - 50,
@ -1966,8 +1938,6 @@ menu_t MP_SplitServerDef =
NULL NULL
}; };
#ifndef NONET
menu_t MP_MainDef = menu_t MP_MainDef =
{ {
MN_MP_MAIN, MN_MP_MAIN,
@ -2019,15 +1989,10 @@ menu_t MP_RoomDef =
0, 0,
NULL NULL
}; };
#endif
menu_t MP_PlayerSetupDef = menu_t MP_PlayerSetupDef =
{ {
#ifdef NONET
MTREE2(MN_MP_MAIN, MN_MP_PLAYERSETUP),
#else
MTREE3(MN_MP_MAIN, MN_MP_SPLITSCREEN, MN_MP_PLAYERSETUP), MTREE3(MN_MP_MAIN, MN_MP_SPLITSCREEN, MN_MP_PLAYERSETUP),
#endif
"M_SPLAYR", "M_SPLAYR",
sizeof (MP_PlayerSetupMenu)/sizeof (menuitem_t), sizeof (MP_PlayerSetupMenu)/sizeof (menuitem_t),
&MainDef, // doesn't matter &MainDef, // doesn't matter
@ -2787,6 +2752,7 @@ void M_SetMenuCurBackground(const char *defaultname)
{ {
char name[9]; char name[9];
strncpy(name, defaultname, 8); strncpy(name, defaultname, 8);
name[8] = '\0';
M_IterateMenuTree(MIT_SetCurBackground, &name); M_IterateMenuTree(MIT_SetCurBackground, &name);
} }
@ -3956,9 +3922,7 @@ void M_Init(void)
OP_JoystickSetMenu[i].itemaction = M_AssignJoystick; OP_JoystickSetMenu[i].itemaction = M_AssignJoystick;
} }
#ifndef NONET
CV_RegisterVar(&cv_serversort); CV_RegisterVar(&cv_serversort);
#endif
} }
void M_InitCharacterTables(void) void M_InitCharacterTables(void)
@ -11108,7 +11072,6 @@ static void M_EndGame(INT32 choice)
#define S_LINEY(n) currentMenu->y + SERVERHEADERHEIGHT + (n * SERVERLINEHEIGHT) #define S_LINEY(n) currentMenu->y + SERVERHEADERHEIGHT + (n * SERVERLINEHEIGHT)
#ifndef NONET
static UINT32 localservercount; static UINT32 localservercount;
static void M_HandleServerPage(INT32 choice) static void M_HandleServerPage(INT32 choice)
@ -11380,11 +11343,9 @@ static int ServerListEntryComparator_modified(const void *entry1, const void *en
// Default to strcmp. // Default to strcmp.
return strcmp(sa->info.servername, sb->info.servername); return strcmp(sa->info.servername, sb->info.servername);
} }
#endif
void M_SortServerList(void) void M_SortServerList(void)
{ {
#ifndef NONET
switch(cv_serversort.value) switch(cv_serversort.value)
{ {
case 0: // Ping. case 0: // Ping.
@ -11406,10 +11367,8 @@ void M_SortServerList(void)
qsort(serverlist, serverlistcount, sizeof(serverelem_t), ServerListEntryComparator_gametypename); qsort(serverlist, serverlistcount, sizeof(serverelem_t), ServerListEntryComparator_gametypename);
break; break;
} }
#endif
} }
#ifndef NONET
#ifdef UPDATE_ALERT #ifdef UPDATE_ALERT
static boolean M_CheckMODVersion(int id) static boolean M_CheckMODVersion(int id)
{ {
@ -11608,7 +11567,6 @@ static void M_ChooseRoom(INT32 choice)
if (currentMenu == &MP_ConnectDef) if (currentMenu == &MP_ConnectDef)
M_Refresh(0); M_Refresh(0);
} }
#endif //NONET
//=========================================================================== //===========================================================================
// Start Server Menu // Start Server Menu
@ -11656,7 +11614,6 @@ static void M_DrawServerMenu(void)
{ {
M_DrawGenericMenu(); M_DrawGenericMenu();
#ifndef NONET
// Room name // Room name
if (currentMenu == &MP_ServerDef) if (currentMenu == &MP_ServerDef)
{ {
@ -11668,15 +11625,10 @@ static void M_DrawServerMenu(void)
V_DrawRightAlignedString(BASEVIDWIDTH - currentMenu->x, currentMenu->y + MP_ServerMenu[mp_server_room].alphaKey, V_DrawRightAlignedString(BASEVIDWIDTH - currentMenu->x, currentMenu->y + MP_ServerMenu[mp_server_room].alphaKey,
V_YELLOWMAP, room_list[menuRoomIndex].name); V_YELLOWMAP, room_list[menuRoomIndex].name);
} }
#endif
if (cv_nextmap.value) if (cv_nextmap.value)
{ {
#ifndef NONET
#define imgheight MP_ServerMenu[mp_server_levelgt].alphaKey #define imgheight MP_ServerMenu[mp_server_levelgt].alphaKey
#else
#define imgheight 100
#endif
patch_t *PictureOfLevel; patch_t *PictureOfLevel;
lumpnum_t lumpnum; lumpnum_t lumpnum;
char headerstr[40]; char headerstr[40];
@ -11728,7 +11680,6 @@ static void M_ServerOptions(INT32 choice)
{ {
(void)choice; (void)choice;
#ifndef NONET
if ((splitscreen && !netgame) || currentMenu == &MP_SplitServerDef) if ((splitscreen && !netgame) || currentMenu == &MP_SplitServerDef)
{ {
OP_ServerOptionsMenu[ 1].status = IT_GRAYEDOUT; // Server name OP_ServerOptionsMenu[ 1].status = IT_GRAYEDOUT; // Server name
@ -11749,7 +11700,6 @@ static void M_ServerOptions(INT32 choice)
OP_ServerOptionsMenu[37].status = IT_STRING | IT_CVAR; OP_ServerOptionsMenu[37].status = IT_STRING | IT_CVAR;
OP_ServerOptionsMenu[38].status = IT_STRING | IT_CVAR; OP_ServerOptionsMenu[38].status = IT_STRING | IT_CVAR;
} }
#endif
/* Disable fading because of different menu head. */ /* Disable fading because of different menu head. */
if (currentMenu == &OP_MainDef)/* from Options menu */ if (currentMenu == &OP_MainDef)/* from Options menu */
@ -11761,7 +11711,6 @@ static void M_ServerOptions(INT32 choice)
M_SetupNextMenu(&OP_ServerOptionsDef); M_SetupNextMenu(&OP_ServerOptionsDef);
} }
#ifndef NONET
static void M_StartServerMenu(INT32 choice) static void M_StartServerMenu(INT32 choice)
{ {
(void)choice; (void)choice;
@ -12028,7 +11977,6 @@ static void M_HandleConnectIP(INT32 choice)
M_ClearMenus(true); M_ClearMenus(true);
} }
} }
#endif //!NONET
// ======================== // ========================
// MULTIPLAYER PLAYER SETUP // MULTIPLAYER PLAYER SETUP
@ -12705,7 +12653,7 @@ static void M_SetupMultiPlayer2(INT32 choice)
multi_frame = 0; multi_frame = 0;
multi_tics = 4*FRACUNIT; multi_tics = 4*FRACUNIT;
strcpy (setupm_name, cv_playername2.string); strcpy (setupm_name, cv_playername2.string);
// set for splitscreen secondary player // set for splitscreen secondary player

View file

@ -20,7 +20,7 @@
#include "command.h" #include "command.h"
#include "f_finale.h" // for ttmode_enum #include "f_finale.h" // for ttmode_enum
#include "i_threads.h" #include "i_threads.h"
#include "mserv.h" #include "netcode/mserv.h"
#include "r_things.h" // for SKINNAMESIZE #include "r_things.h" // for SKINNAMESIZE
// Compatibility with old-style named NiGHTS replay files. // Compatibility with old-style named NiGHTS replay files.
@ -74,7 +74,7 @@ typedef enum
MN_MP_SERVER, MN_MP_SERVER,
MN_MP_CONNECT, MN_MP_CONNECT,
MN_MP_ROOM, MN_MP_ROOM,
MN_MP_PLAYERSETUP, // MP_PlayerSetupDef shared with SPLITSCREEN if #defined NONET MN_MP_PLAYERSETUP,
MN_MP_SERVER_OPTIONS, MN_MP_SERVER_OPTIONS,
// Options // Options

View file

@ -12,7 +12,7 @@
#include "m_perfstats.h" #include "m_perfstats.h"
#include "v_video.h" #include "v_video.h"
#include "i_video.h" #include "i_video.h"
#include "d_netcmd.h" #include "netcode/d_netcmd.h"
#include "r_main.h" #include "r_main.h"
#include "i_system.h" #include "i_system.h"
#include "z_zone.h" #include "z_zone.h"

View file

@ -0,0 +1,15 @@
target_sources(SRB2SDL2 PRIVATE
d_clisrv.c
server_connection.c
client_connection.c
tic_command.c
net_command.c
gamestate.c
commands.c
d_net.c
d_netcmd.c
d_netfil.c
http-mserv.c
i_tcp.c
mserv.c
)

13
src/netcode/Sourcefile Normal file
View file

@ -0,0 +1,13 @@
d_clisrv.c
server_connection.c
client_connection.c
tic_command.c
net_command.c
gamestate.c
commands.c
d_net.c
d_netcmd.c
d_netfil.c
http-mserv.c
i_tcp.c
mserv.c

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,61 @@
// SONIC ROBO BLAST 2
//-----------------------------------------------------------------------------
// Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2023 by Sonic Team Junior.
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
// See the 'LICENSE' file for more details.
//-----------------------------------------------------------------------------
/// \file client_connection.h
/// \brief Client connection handling
#ifndef __D_CLIENT_CONNECTION__
#define __D_CLIENT_CONNECTION__
#include "../doomtype.h"
#include "d_clisrv.h"
#define MAXSERVERLIST (MAXNETNODES-1)
typedef struct
{
SINT8 node;
serverinfo_pak info;
} serverelem_t;
typedef enum
{
CL_SEARCHING,
CL_CHECKFILES,
CL_DOWNLOADFILES,
CL_ASKJOIN,
CL_LOADFILES,
CL_WAITJOINRESPONSE,
CL_DOWNLOADSAVEGAME,
CL_CONNECTED,
CL_ABORTED,
CL_ASKFULLFILELIST,
CL_CONFIRMCONNECT
} cl_mode_t;
extern serverelem_t serverlist[MAXSERVERLIST];
extern UINT32 serverlistcount;
extern cl_mode_t cl_mode;
extern boolean serverisfull; //lets us be aware if the server was full after we check files, but before downloading, so we can ask if the user still wants to download or not
extern tic_t firstconnectattempttime;
extern UINT8 mynode; // my address pointofview server
void CL_QueryServerList(msg_server_t *list);
void CL_UpdateServerList(boolean internetsearch, INT32 room);
void CL_ConnectToServer(void);
boolean CL_SendJoin(void);
void PT_ServerInfo(SINT8 node);
void PT_MoreFilesNeeded(SINT8 node);
void PT_ServerRefuse(SINT8 node);
void PT_ServerCFG(SINT8 node);
#endif

484
src/netcode/commands.c Normal file
View file

@ -0,0 +1,484 @@
// SONIC ROBO BLAST 2
//-----------------------------------------------------------------------------
// Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2023 by Sonic Team Junior.
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
// See the 'LICENSE' file for more details.
//-----------------------------------------------------------------------------
/// \file commands.c
/// \brief Various netgame commands, such as kick and ban
#include "commands.h"
#include "d_clisrv.h"
#include "client_connection.h"
#include "net_command.h"
#include "d_netcmd.h"
#include "d_net.h"
#include "i_net.h"
#include "protocol.h"
#include "../byteptr.h"
#include "../d_main.h"
#include "../g_game.h"
#include "../w_wad.h"
#include "../z_zone.h"
#include "../doomstat.h"
#include "../doomdef.h"
#include "../r_local.h"
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <string.h>
typedef struct banreason_s
{
char *reason;
struct banreason_s *prev; //-1
struct banreason_s *next; //+1
} banreason_t;
static banreason_t *reasontail = NULL; //last entry, use prev
static banreason_t *reasonhead = NULL; //1st entry, use next
void Ban_Add(const char *reason)
{
banreason_t *reasonlist = malloc(sizeof(*reasonlist));
if (!reasonlist)
return;
if (!reason)
reason = "NA";
reasonlist->next = NULL;
reasonlist->reason = Z_StrDup(reason);
if ((reasonlist->prev = reasontail) == NULL)
reasonhead = reasonlist;
else
reasontail->next = reasonlist;
reasontail = reasonlist;
}
static void Ban_Clear(void)
{
banreason_t *temp;
I_ClearBans();
reasontail = NULL;
while (reasonhead)
{
temp = reasonhead->next;
Z_Free(reasonhead->reason);
free(reasonhead);
reasonhead = temp;
}
}
void Ban_Load_File(boolean warning)
{
FILE *f;
const char *address, *mask;
char buffer[MAX_WADPATH];
if (!I_ClearBans)
return;
f = fopen(va("%s"PATHSEP"%s", srb2home, "ban.txt"), "r");
if (!f)
{
if (warning)
CONS_Alert(CONS_WARNING, M_GetText("Could not open ban.txt for ban list\n"));
return;
}
Ban_Clear();
for (; fgets(buffer, (int)sizeof(buffer), f);)
{
address = strtok(buffer, " \t\r\n");
mask = strtok(NULL, " \t\r\n");
I_SetBanAddress(address, mask);
Ban_Add(strtok(NULL, "\r\n"));
}
fclose(f);
}
void D_SaveBan(void)
{
FILE *f;
banreason_t *reasonlist = reasonhead;
const char *address, *mask;
const char *path = va("%s"PATHSEP"%s", srb2home, "ban.txt");
if (!reasonhead)
{
remove(path);
return;
}
f = fopen(path, "w");
if (!f)
{
CONS_Alert(CONS_WARNING, M_GetText("Could not save ban list into ban.txt\n"));
return;
}
for (size_t i = 0;(address = I_GetBanAddress(i)) != NULL;i++)
{
if (!I_GetBanMask || (mask = I_GetBanMask(i)) == NULL)
fprintf(f, "%s 0", address);
else
fprintf(f, "%s %s", address, mask);
if (reasonlist && reasonlist->reason)
fprintf(f, " %s\n", reasonlist->reason);
else
fprintf(f, " %s\n", "NA");
if (reasonlist) reasonlist = reasonlist->next;
}
fclose(f);
}
void Command_ShowBan(void) //Print out ban list
{
size_t i;
const char *address, *mask;
banreason_t *reasonlist = reasonhead;
if (I_GetBanAddress)
CONS_Printf(M_GetText("Ban List:\n"));
else
return;
for (i = 0;(address = I_GetBanAddress(i)) != NULL;i++)
{
if (!I_GetBanMask || (mask = I_GetBanMask(i)) == NULL)
CONS_Printf("%s: %s ", sizeu1(i+1), address);
else
CONS_Printf("%s: %s/%s ", sizeu1(i+1), address, mask);
if (reasonlist && reasonlist->reason)
CONS_Printf("(%s)\n", reasonlist->reason);
else
CONS_Printf("\n");
if (reasonlist) reasonlist = reasonlist->next;
}
if (i == 0 && !address)
CONS_Printf(M_GetText("(empty)\n"));
}
void Command_ClearBans(void)
{
if (!I_ClearBans)
return;
Ban_Clear();
D_SaveBan();
}
void Command_Ban(void)
{
if (COM_Argc() < 2)
{
CONS_Printf(M_GetText("Ban <playername/playernum> <reason>: ban and kick a player\n"));
return;
}
if (!netgame) // Don't kick Tails in splitscreen!
{
CONS_Printf(M_GetText("This only works in a netgame.\n"));
return;
}
if (server || IsPlayerAdmin(consoleplayer))
{
UINT8 buf[3 + MAX_REASONLENGTH];
UINT8 *p = buf;
const SINT8 pn = nametonum(COM_Argv(1));
const INT32 node = playernode[(INT32)pn];
if (pn == -1 || pn == 0)
return;
WRITEUINT8(p, pn);
if (server && I_Ban && !I_Ban(node)) // only the server is allowed to do this right now
{
CONS_Alert(CONS_WARNING, M_GetText("Too many bans! Geez, that's a lot of people you're excluding...\n"));
WRITEUINT8(p, KICK_MSG_GO_AWAY);
SendNetXCmd(XD_KICK, &buf, 2);
}
else
{
if (server) // only the server is allowed to do this right now
{
Ban_Add(COM_Argv(2));
D_SaveBan(); // save the ban list
}
if (COM_Argc() == 2)
{
WRITEUINT8(p, KICK_MSG_BANNED);
SendNetXCmd(XD_KICK, &buf, 2);
}
else
{
size_t j = COM_Argc();
char message[MAX_REASONLENGTH];
//Steal from the motd code so you don't have to put the reason in quotes.
strlcpy(message, COM_Argv(2), sizeof message);
for (size_t i = 3; i < j; i++)
{
strlcat(message, " ", sizeof message);
strlcat(message, COM_Argv(i), sizeof message);
}
WRITEUINT8(p, KICK_MSG_CUSTOM_BAN);
WRITESTRINGN(p, message, MAX_REASONLENGTH);
SendNetXCmd(XD_KICK, &buf, p - buf);
}
}
}
else
CONS_Printf(M_GetText("Only the server or a remote admin can use this.\n"));
}
void Command_BanIP(void)
{
if (COM_Argc() < 2)
{
CONS_Printf(M_GetText("banip <ip> <reason>: ban an ip address\n"));
return;
}
if (server) // Only the server can use this, otherwise does nothing.
{
const char *address = (COM_Argv(1));
const char *reason;
if (COM_Argc() == 2)
reason = NULL;
else
reason = COM_Argv(2);
if (I_SetBanAddress && I_SetBanAddress(address, NULL))
{
if (reason)
CONS_Printf("Banned IP address %s for: %s\n", address, reason);
else
CONS_Printf("Banned IP address %s\n", address);
Ban_Add(reason);
D_SaveBan();
}
else
{
return;
}
}
}
void Command_ReloadBan(void) //recheck ban.txt
{
Ban_Load_File(true);
}
void Command_Kick(void)
{
if (COM_Argc() < 2)
{
CONS_Printf(M_GetText("kick <playername/playernum> <reason>: kick a player\n"));
return;
}
if (!netgame) // Don't kick Tails in splitscreen!
{
CONS_Printf(M_GetText("This only works in a netgame.\n"));
return;
}
if (server || IsPlayerAdmin(consoleplayer))
{
UINT8 buf[3 + MAX_REASONLENGTH];
UINT8 *p = buf;
const SINT8 pn = nametonum(COM_Argv(1));
if (pn == -1 || pn == 0)
return;
// Special case if we are trying to kick a player who is downloading the game state:
// trigger a timeout instead of kicking them, because a kick would only
// take effect after they have finished downloading
if (server && playernode[pn] != UINT8_MAX && netnodes[playernode[pn]].sendingsavegame)
{
Net_ConnectionTimeout(playernode[pn]);
return;
}
WRITESINT8(p, pn);
if (COM_Argc() == 2)
{
WRITEUINT8(p, KICK_MSG_GO_AWAY);
SendNetXCmd(XD_KICK, &buf, 2);
}
else
{
size_t j = COM_Argc();
char message[MAX_REASONLENGTH];
//Steal from the motd code so you don't have to put the reason in quotes.
strlcpy(message, COM_Argv(2), sizeof message);
for (size_t i = 3; i < j; i++)
{
strlcat(message, " ", sizeof message);
strlcat(message, COM_Argv(i), sizeof message);
}
WRITEUINT8(p, KICK_MSG_CUSTOM_KICK);
WRITESTRINGN(p, message, MAX_REASONLENGTH);
SendNetXCmd(XD_KICK, &buf, p - buf);
}
}
else
CONS_Printf(M_GetText("Only the server or a remote admin can use this.\n"));
}
void Command_connect(void)
{
if (COM_Argc() < 2 || *COM_Argv(1) == 0)
{
CONS_Printf(M_GetText(
"Connect <serveraddress> (port): connect to a server\n"
"Connect ANY: connect to the first lan server found\n"
//"Connect SELF: connect to your own server.\n"
));
return;
}
if (Playing() || titledemo)
{
CONS_Printf(M_GetText("You cannot connect while in a game. End this game first.\n"));
return;
}
server = false;
/*
if (!stricmp(COM_Argv(1), "self"))
{
servernode = 0;
server = true;
/// \bug should be but...
//SV_SpawnServer();
}
else
*/
{
// used in menu to connect to a server in the list
if (netgame && !stricmp(COM_Argv(1), "node"))
{
servernode = (SINT8)atoi(COM_Argv(2));
}
else if (netgame)
{
CONS_Printf(M_GetText("You cannot connect while in a game. End this game first.\n"));
return;
}
else if (I_NetOpenSocket)
{
I_NetOpenSocket();
netgame = true;
multiplayer = true;
if (!stricmp(COM_Argv(1), "any"))
servernode = BROADCASTADDR;
else if (I_NetMakeNodewPort)
{
if (COM_Argc() >= 3) // address AND port
servernode = I_NetMakeNodewPort(COM_Argv(1), COM_Argv(2));
else // address only, or address:port
servernode = I_NetMakeNode(COM_Argv(1));
}
else
{
CONS_Alert(CONS_ERROR, M_GetText("There is no server identification with this network driver\n"));
D_CloseConnection();
return;
}
}
else
CONS_Alert(CONS_ERROR, M_GetText("There is no network driver\n"));
}
splitscreen = false;
SplitScreen_OnChange();
botingame = false;
botskin = 0;
CL_ConnectToServer();
}
void Command_GetPlayerNum(void)
{
for (INT32 i = 0; i < MAXPLAYERS; i++)
if (playeringame[i])
{
if (serverplayer == i)
CONS_Printf(M_GetText("num:%2d node:%2d %s\n"), i, playernode[i], player_names[i]);
else
CONS_Printf(M_GetText("\x82num:%2d node:%2d %s\n"), i, playernode[i], player_names[i]);
}
}
/** Lists all players and their player numbers.
*
* \sa Command_GetPlayerNum
*/
void Command_Nodes(void)
{
size_t maxlen = 0;
const char *address;
for (INT32 i = 0; i < MAXPLAYERS; i++)
{
const size_t plen = strlen(player_names[i]);
if (playeringame[i] && plen > maxlen)
maxlen = plen;
}
for (INT32 i = 0; i < MAXPLAYERS; i++)
{
if (playeringame[i])
{
CONS_Printf("%.2u: %*s", i, (int)maxlen, player_names[i]);
if (playernode[i] != UINT8_MAX)
{
CONS_Printf(" - node %.2d", playernode[i]);
if (I_GetNodeAddress && (address = I_GetNodeAddress(playernode[i])) != NULL)
CONS_Printf(" - %s", address);
}
if (IsPlayerAdmin(i))
CONS_Printf(M_GetText(" (verified admin)"));
if (players[i].spectator)
CONS_Printf(M_GetText(" (spectator)"));
CONS_Printf("\n");
}
}
}

33
src/netcode/commands.h Normal file
View file

@ -0,0 +1,33 @@
// SONIC ROBO BLAST 2
//-----------------------------------------------------------------------------
// Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2023 by Sonic Team Junior.
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
// See the 'LICENSE' file for more details.
//-----------------------------------------------------------------------------
/// \file commands.h
/// \brief Various netgame commands, such as kick and ban
#ifndef __COMMANDS__
#define __COMMANDS__
#include "../doomdef.h"
#define MAX_REASONLENGTH 30
void Ban_Add(const char *reason);
void D_SaveBan(void);
void Ban_Load_File(boolean warning);
void Command_ShowBan(void);
void Command_ClearBans(void);
void Command_Ban(void);
void Command_BanIP(void);
void Command_ReloadBan(void);
void Command_Kick(void);
void Command_connect(void);
void Command_GetPlayerNum(void);
void Command_Nodes(void);
#endif

1736
src/netcode/d_clisrv.c Normal file

File diff suppressed because it is too large Load diff

135
src/netcode/d_clisrv.h Normal file
View file

@ -0,0 +1,135 @@
// SONIC ROBO BLAST 2
//-----------------------------------------------------------------------------
// Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2023 by Sonic Team Junior.
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
// See the 'LICENSE' file for more details.
//-----------------------------------------------------------------------------
/// \file d_clisrv.h
/// \brief high level networking stuff
#ifndef __D_CLISRV__
#define __D_CLISRV__
#include "protocol.h"
#include "../d_ticcmd.h"
#include "d_net.h"
#include "d_netcmd.h"
#include "d_net.h"
#include "../tables.h"
#include "../d_player.h"
#include "mserv.h"
#define CLIENTBACKUPTICS 32
#ifdef PACKETDROP
void Command_Drop(void);
void Command_Droprate(void);
#endif
#ifdef _DEBUG
void Command_Numnodes(void);
#endif
extern INT32 mapchangepending;
// Points inside doomcom
extern doomdata_t *netbuffer;
#define BASEPACKETSIZE offsetof(doomdata_t, u)
#define BASESERVERTICSSIZE offsetof(doomdata_t, u.serverpak.cmds[0])
typedef enum
{
KR_KICK = 1, //Kicked by server
KR_PINGLIMIT = 2, //Broke Ping Limit
KR_SYNCH = 3, //Synch Failure
KR_TIMEOUT = 4, //Connection Timeout
KR_BAN = 5, //Banned by server
KR_LEAVE = 6, //Quit the game
} kickreason_t;
/* the max number of name changes in some time period */
#define MAXNAMECHANGES (5)
#define NAMECHANGERATE (60*TICRATE)
extern boolean server;
extern boolean serverrunning;
#define client (!server)
extern boolean dedicated; // For dedicated server
extern UINT16 software_MAXPACKETLENGTH;
extern boolean acceptnewnode;
extern SINT8 servernode;
extern tic_t maketic;
extern tic_t neededtic;
extern INT16 consistancy[BACKUPTICS];
void Command_Ping_f(void);
extern tic_t connectiontimeout;
extern UINT16 pingmeasurecount;
extern UINT32 realpingtable[MAXPLAYERS];
extern UINT32 playerpingtable[MAXPLAYERS];
extern tic_t servermaxping;
extern consvar_t cv_netticbuffer, cv_resynchattempts, cv_blamecfail, cv_playbackspeed, cv_dedicatedidletime;
// Used in d_net, the only dependence
void D_ClientServerInit(void);
// Create any new ticcmds and broadcast to other players.
void NetUpdate(void);
// Maintain connections to nodes without timing them all out.
void NetKeepAlive(void);
void GetPackets(void);
void ResetNode(INT32 node);
INT16 Consistancy(void);
void SV_StartSinglePlayerServer(void);
void SV_SpawnServer(void);
void SV_StopServer(void);
void SV_ResetServer(void);
void CL_AddSplitscreenPlayer(void);
void CL_RemoveSplitscreenPlayer(void);
void CL_Reset(void);
void CL_ClearPlayer(INT32 playernum);
void CL_RemovePlayer(INT32 playernum, kickreason_t reason);
void CL_HandleTimeout(void);
// Is there a game running
boolean Playing(void);
// Broadcasts special packets to other players
// to notify of game exit
void D_QuitNetGame(void);
//? How many ticks to run?
boolean TryRunTics(tic_t realtic);
// extra data for lmps
// these functions scare me. they contain magic.
/*boolean AddLmpExtradata(UINT8 **demo_p, INT32 playernum);
void ReadLmpExtraData(UINT8 **demo_pointer, INT32 playernum);*/
// translate a playername in a player number return -1 if not found and
// print a error message in the console
SINT8 nametonum(const char *name);
extern char motd[254], server_context[8];
extern UINT8 playernode[MAXPLAYERS];
INT32 D_NumPlayers(void);
INT32 D_NumBots(void);
tic_t GetLag(INT32 node);
void D_MD5PasswordPass(const UINT8 *buffer, size_t len, const char *salt, void *dest);
extern UINT8 adminpassmd5[16];
extern boolean adminpasswordset;
extern boolean hu_stopped;
#endif

View file

@ -16,19 +16,21 @@
/// This protocol uses a mix of "goback n" and "selective repeat" implementation /// This protocol uses a mix of "goback n" and "selective repeat" implementation
/// The NOTHING packet is sent when connection is idle to acknowledge packets /// The NOTHING packet is sent when connection is idle to acknowledge packets
#include "doomdef.h" #include "../doomdef.h"
#include "g_game.h" #include "../g_game.h"
#include "i_time.h" #include "../i_time.h"
#include "i_net.h" #include "i_net.h"
#include "i_system.h" #include "../i_system.h"
#include "m_argv.h" #include "../m_argv.h"
#include "d_net.h" #include "d_net.h"
#include "w_wad.h" #include "../w_wad.h"
#include "d_netfil.h" #include "d_netfil.h"
#include "d_clisrv.h" #include "d_clisrv.h"
#include "z_zone.h" #include "tic_command.h"
#include "net_command.h"
#include "../z_zone.h"
#include "i_tcp.h" #include "i_tcp.h"
#include "d_main.h" // srb2home #include "../d_main.h" // srb2home
// //
// NETWORKING // NETWORKING
@ -138,7 +140,6 @@ boolean Net_GetNetStat(void)
#define URGENTFREESLOTNUM 10 #define URGENTFREESLOTNUM 10
#define ACKTOSENDTIMEOUT (TICRATE/11) #define ACKTOSENDTIMEOUT (TICRATE/11)
#ifndef NONET
typedef struct typedef struct
{ {
UINT8 acknum; UINT8 acknum;
@ -152,7 +153,6 @@ typedef struct
doomdata_t data; doomdata_t data;
} pak; } pak;
} ackpak_t; } ackpak_t;
#endif
typedef enum typedef enum
{ {
@ -160,10 +160,8 @@ typedef enum
NF_TIMEOUT = 2, // Flag is set when the node got a timeout NF_TIMEOUT = 2, // Flag is set when the node got a timeout
} node_flags_t; } node_flags_t;
#ifndef NONET
// Table of packets that were not acknowleged can be resent (the sender window) // Table of packets that were not acknowleged can be resent (the sender window)
static ackpak_t ackpak[MAXACKPACKETS]; static ackpak_t ackpak[MAXACKPACKETS];
#endif
typedef struct typedef struct
{ {
@ -191,7 +189,6 @@ typedef struct
static node_t nodes[MAXNETNODES]; static node_t nodes[MAXNETNODES];
#define NODETIMEOUT 14 #define NODETIMEOUT 14
#ifndef NONET
// return <0 if a < b (mod 256) // return <0 if a < b (mod 256)
// 0 if a = n (mod 256) // 0 if a = n (mod 256)
// >0 if a > b (mod 256) // >0 if a > b (mod 256)
@ -214,7 +211,7 @@ FUNCMATH static INT32 cmpack(UINT8 a, UINT8 b)
static boolean GetFreeAcknum(UINT8 *freeack, boolean lowtimer) static boolean GetFreeAcknum(UINT8 *freeack, boolean lowtimer)
{ {
node_t *node = &nodes[doomcom->remotenode]; node_t *node = &nodes[doomcom->remotenode];
INT32 i, numfreeslot = 0; INT32 numfreeslot = 0;
if (cmpack((UINT8)((node->remotefirstack + MAXACKTOSEND) % 256), node->nextacknum) < 0) if (cmpack((UINT8)((node->remotefirstack + MAXACKTOSEND) % 256), node->nextacknum) < 0)
{ {
@ -222,7 +219,7 @@ static boolean GetFreeAcknum(UINT8 *freeack, boolean lowtimer)
return false; return false;
} }
for (i = 0; i < MAXACKPACKETS; i++) for (INT32 i = 0; i < MAXACKPACKETS; i++)
if (!ackpak[i].acknum) if (!ackpak[i].acknum)
{ {
// For low priority packets, make sure to let freeslots so urgent packets can be sent // For low priority packets, make sure to let freeslots so urgent packets can be sent
@ -279,10 +276,10 @@ static boolean GetFreeAcknum(UINT8 *freeack, boolean lowtimer)
*/ */
INT32 Net_GetFreeAcks(boolean urgent) INT32 Net_GetFreeAcks(boolean urgent)
{ {
INT32 i, numfreeslot = 0; INT32 numfreeslot = 0;
INT32 n = 0; // Number of free acks found INT32 n = 0; // Number of free acks found
for (i = 0; i < MAXACKPACKETS; i++) for (INT32 i = 0; i < MAXACKPACKETS; i++)
if (!ackpak[i].acknum) if (!ackpak[i].acknum)
{ {
// For low priority packets, make sure to let freeslots so urgent packets can be sent // For low priority packets, make sure to let freeslots so urgent packets can be sent
@ -318,7 +315,6 @@ static void RemoveAck(INT32 i)
// We have got a packet, proceed the ack request and ack return // We have got a packet, proceed the ack request and ack return
static boolean Processackpak(void) static boolean Processackpak(void)
{ {
INT32 i;
boolean goodpacket = true; boolean goodpacket = true;
node_t *node = &nodes[doomcom->remotenode]; node_t *node = &nodes[doomcom->remotenode];
@ -327,7 +323,7 @@ static boolean Processackpak(void)
{ {
node->remotefirstack = netbuffer->ackreturn; node->remotefirstack = netbuffer->ackreturn;
// Search the ackbuffer and free it // Search the ackbuffer and free it
for (i = 0; i < MAXACKPACKETS; i++) for (INT32 i = 0; i < MAXACKPACKETS; i++)
if (ackpak[i].acknum && ackpak[i].destinationnode == node - nodes if (ackpak[i].acknum && ackpak[i].destinationnode == node - nodes
&& cmpack(ackpak[i].acknum, netbuffer->ackreturn) <= 0) && cmpack(ackpak[i].acknum, netbuffer->ackreturn) <= 0)
{ {
@ -349,7 +345,7 @@ static boolean Processackpak(void)
else else
{ {
// Check if it is not already in the queue // Check if it is not already in the queue
for (i = node->acktosend_tail; i != node->acktosend_head; i = (i+1) % MAXACKTOSEND) for (INT32 i = node->acktosend_tail; i != node->acktosend_head; i = (i+1) % MAXACKTOSEND)
if (node->acktosend[i] == ack) if (node->acktosend[i] == ack)
{ {
DEBFILE(va("Discard(2) ack %d (duplicated)\n", ack)); DEBFILE(va("Discard(2) ack %d (duplicated)\n", ack));
@ -377,7 +373,7 @@ static boolean Processackpak(void)
while (change) while (change)
{ {
change = false; change = false;
for (i = node->acktosend_tail; i != node->acktosend_head; for (INT32 i = node->acktosend_tail; i != node->acktosend_head;
i = (i+1) % MAXACKTOSEND) i = (i+1) % MAXACKTOSEND)
{ {
if (cmpack(node->acktosend[i], nextfirstack) <= 0) if (cmpack(node->acktosend[i], nextfirstack) <= 0)
@ -426,28 +422,20 @@ static boolean Processackpak(void)
} }
return goodpacket; return goodpacket;
} }
#endif
// send special packet with only ack on it // send special packet with only ack on it
void Net_SendAcks(INT32 node) void Net_SendAcks(INT32 node)
{ {
#ifdef NONET
(void)node;
#else
netbuffer->packettype = PT_NOTHING; netbuffer->packettype = PT_NOTHING;
M_Memcpy(netbuffer->u.textcmd, nodes[node].acktosend, MAXACKTOSEND); M_Memcpy(netbuffer->u.textcmd, nodes[node].acktosend, MAXACKTOSEND);
HSendPacket(node, false, 0, MAXACKTOSEND); HSendPacket(node, false, 0, MAXACKTOSEND);
#endif
} }
#ifndef NONET
static void GotAcks(void) static void GotAcks(void)
{ {
INT32 i, j; for (INT32 j = 0; j < MAXACKTOSEND; j++)
for (j = 0; j < MAXACKTOSEND; j++)
if (netbuffer->u.textcmd[j]) if (netbuffer->u.textcmd[j])
for (i = 0; i < MAXACKPACKETS; i++) for (INT32 i = 0; i < MAXACKPACKETS; i++)
if (ackpak[i].acknum && ackpak[i].destinationnode == doomcom->remotenode) if (ackpak[i].acknum && ackpak[i].destinationnode == doomcom->remotenode)
{ {
if (ackpak[i].acknum == netbuffer->u.textcmd[j]) if (ackpak[i].acknum == netbuffer->u.textcmd[j])
@ -463,7 +451,6 @@ static void GotAcks(void)
} }
} }
} }
#endif
void Net_ConnectionTimeout(INT32 node) void Net_ConnectionTimeout(INT32 node)
{ {
@ -472,14 +459,10 @@ void Net_ConnectionTimeout(INT32 node)
return; return;
nodes[node].flags |= NF_TIMEOUT; nodes[node].flags |= NF_TIMEOUT;
// Send a very special packet to self (hack the reboundstore queue) if (server)
// Main code will handle it SendKicksForNode(node, KICK_MSG_TIMEOUT | KICK_MSG_KEEP_BODY);
reboundstore[rebound_head].packettype = PT_NODETIMEOUT; else
reboundstore[rebound_head].ack = 0; CL_HandleTimeout();
reboundstore[rebound_head].ackreturn = 0;
reboundstore[rebound_head].u.textcmd[0] = (UINT8)node;
reboundsize[rebound_head] = (INT16)(BASEPACKETSIZE + 1);
rebound_head = (rebound_head+1) % MAXREBOUND;
// Do not redo it quickly (if we do not close connection it is // Do not redo it quickly (if we do not close connection it is
// for a good reason!) // for a good reason!)
@ -489,10 +472,8 @@ void Net_ConnectionTimeout(INT32 node)
// Resend the data if needed // Resend the data if needed
void Net_AckTicker(void) void Net_AckTicker(void)
{ {
#ifndef NONET
INT32 i;
for (i = 0; i < MAXACKPACKETS; i++) for (INT32 i = 0; i < MAXACKPACKETS; i++)
{ {
const INT32 nodei = ackpak[i].destinationnode; const INT32 nodei = ackpak[i].destinationnode;
node_t *node = &nodes[nodei]; node_t *node = &nodes[nodei];
@ -519,7 +500,7 @@ void Net_AckTicker(void)
} }
} }
for (i = 1; i < MAXNETNODES; i++) for (INT32 i = 1; i < MAXNETNODES; i++)
{ {
// This is something like node open flag // This is something like node open flag
if (nodes[i].firstacktosend) if (nodes[i].firstacktosend)
@ -536,16 +517,12 @@ void Net_AckTicker(void)
} }
} }
} }
#endif
} }
// Remove last packet received ack before resending the ackreturn // Remove last packet received ack before resending the ackreturn
// (the higher layer doesn't have room, or something else ....) // (the higher layer doesn't have room, or something else ....)
void Net_UnAcknowledgePacket(INT32 node) void Net_UnAcknowledgePacket(INT32 node)
{ {
#ifdef NONET
(void)node;
#else
INT32 hm1 = (nodes[node].acktosend_head-1+MAXACKTOSEND) % MAXACKTOSEND; INT32 hm1 = (nodes[node].acktosend_head-1+MAXACKTOSEND) % MAXACKTOSEND;
DEBFILE(va("UnAcknowledge node %d\n", node)); DEBFILE(va("UnAcknowledge node %d\n", node));
if (!node) if (!node)
@ -577,10 +554,8 @@ void Net_UnAcknowledgePacket(INT32 node)
if (!nodes[node].firstacktosend) if (!nodes[node].firstacktosend)
nodes[node].firstacktosend = 1; nodes[node].firstacktosend = 1;
} }
#endif
} }
#ifndef NONET
/** Checks if all acks have been received /** Checks if all acks have been received
* *
* \return True if all acks have been received * \return True if all acks have been received
@ -588,15 +563,12 @@ void Net_UnAcknowledgePacket(INT32 node)
*/ */
static boolean Net_AllAcksReceived(void) static boolean Net_AllAcksReceived(void)
{ {
INT32 i; for (INT32 i = 0; i < MAXACKPACKETS; i++)
for (i = 0; i < MAXACKPACKETS; i++)
if (ackpak[i].acknum) if (ackpak[i].acknum)
return false; return false;
return true; return true;
} }
#endif
/** Waits for all ackreturns /** Waits for all ackreturns
* *
@ -605,9 +577,6 @@ static boolean Net_AllAcksReceived(void)
*/ */
void Net_WaitAllAckReceived(UINT32 timeout) void Net_WaitAllAckReceived(UINT32 timeout)
{ {
#ifdef NONET
(void)timeout;
#else
tic_t tictac = I_GetTime(); tic_t tictac = I_GetTime();
timeout = tictac + timeout*NEWTICRATE; timeout = tictac + timeout*NEWTICRATE;
@ -623,7 +592,6 @@ void Net_WaitAllAckReceived(UINT32 timeout)
HGetPacket(); HGetPacket();
Net_AckTicker(); Net_AckTicker();
} }
#endif
} }
static void InitNode(node_t *node) static void InitNode(node_t *node)
@ -637,14 +605,10 @@ static void InitNode(node_t *node)
static void InitAck(void) static void InitAck(void)
{ {
INT32 i; for (INT32 i = 0; i < MAXACKPACKETS; i++)
#ifndef NONET
for (i = 0; i < MAXACKPACKETS; i++)
ackpak[i].acknum = 0; ackpak[i].acknum = 0;
#endif
for (i = 0; i < MAXNETNODES; i++) for (INT32 i = 0; i < MAXNETNODES; i++)
InitNode(&nodes[i]); InitNode(&nodes[i]);
} }
@ -655,17 +619,12 @@ static void InitAck(void)
*/ */
void Net_AbortPacketType(UINT8 packettype) void Net_AbortPacketType(UINT8 packettype)
{ {
#ifdef NONET for (INT32 i = 0; i < MAXACKPACKETS; i++)
(void)packettype;
#else
INT32 i;
for (i = 0; i < MAXACKPACKETS; i++)
if (ackpak[i].acknum && (ackpak[i].pak.data.packettype == packettype if (ackpak[i].acknum && (ackpak[i].pak.data.packettype == packettype
|| packettype == UINT8_MAX)) || packettype == UINT8_MAX))
{ {
ackpak[i].acknum = 0; ackpak[i].acknum = 0;
} }
#endif
} }
// ----------------------------------------------------------------- // -----------------------------------------------------------------
@ -675,10 +634,6 @@ void Net_AbortPacketType(UINT8 packettype)
// remove a node, clear all ack from this node and reset askret // remove a node, clear all ack from this node and reset askret
void Net_CloseConnection(INT32 node) void Net_CloseConnection(INT32 node)
{ {
#ifdef NONET
(void)node;
#else
INT32 i;
boolean forceclose = (node & FORCECLOSE) != 0; boolean forceclose = (node & FORCECLOSE) != 0;
if (node == -1) if (node == -1)
@ -708,7 +663,7 @@ void Net_CloseConnection(INT32 node)
} }
// check if we are waiting for an ack from this node // check if we are waiting for an ack from this node
for (i = 0; i < MAXACKPACKETS; i++) for (INT32 i = 0; i < MAXACKPACKETS; i++)
if (ackpak[i].acknum && ackpak[i].destinationnode == node) if (ackpak[i].acknum && ackpak[i].destinationnode == node)
{ {
if (!forceclose) if (!forceclose)
@ -722,10 +677,8 @@ void Net_CloseConnection(INT32 node)
if (server) if (server)
SV_AbortLuaFileTransfer(node); SV_AbortLuaFileTransfer(node);
I_NetFreeNodenum(node); I_NetFreeNodenum(node);
#endif
} }
#ifndef NONET
// //
// Checksum // Checksum
// //
@ -734,23 +687,20 @@ static UINT32 NetbufferChecksum(void)
UINT32 c = 0x1234567; UINT32 c = 0x1234567;
const INT32 l = doomcom->datalength - 4; const INT32 l = doomcom->datalength - 4;
const UINT8 *buf = (UINT8 *)netbuffer + 4; const UINT8 *buf = (UINT8 *)netbuffer + 4;
INT32 i;
for (i = 0; i < l; i++, buf++) for (INT32 i = 0; i < l; i++, buf++)
c += (*buf) * (i+1); c += (*buf) * (i+1);
return LONG(c); return LONG(c);
} }
#endif
#ifdef DEBUGFILE #ifdef DEBUGFILE
static void fprintfstring(char *s, size_t len) static void fprintfstring(char *s, size_t len)
{ {
INT32 mode = 0; INT32 mode = 0;
size_t i;
for (i = 0; i < len; i++) for (size_t i = 0; i < len; i++)
if (s[i] < 32) if (s[i] < 32)
{ {
if (!mode) if (!mode)
@ -810,6 +760,8 @@ static const char *packettypename[NUMPACKETTYPE] =
"ASKLUAFILE", "ASKLUAFILE",
"HASLUAFILE", "HASLUAFILE",
"PT_BASICKEEPALIVE",
"FILEFRAGMENT", "FILEFRAGMENT",
"FILEACK", "FILEACK",
"FILERECEIVED", "FILERECEIVED",
@ -817,7 +769,6 @@ static const char *packettypename[NUMPACKETTYPE] =
"TEXTCMD", "TEXTCMD",
"TEXTCMD2", "TEXTCMD2",
"CLIENTJOIN", "CLIENTJOIN",
"NODETIMEOUT",
"LOGIN", "LOGIN",
"TELLFILESNEEDED", "TELLFILESNEEDED",
"MOREFILESNEEDED", "MOREFILESNEEDED",
@ -921,7 +872,6 @@ void Command_Drop(void)
{ {
INT32 packetquantity; INT32 packetquantity;
const char *packetname; const char *packetname;
size_t i;
if (COM_Argc() < 2) if (COM_Argc() < 2)
{ {
@ -951,11 +901,11 @@ void Command_Drop(void)
packetname = COM_Argv(1); packetname = COM_Argv(1);
if (!(stricmp(packetname, "all") && stricmp(packetname, "any"))) if (!(stricmp(packetname, "all") && stricmp(packetname, "any")))
for (i = 0; i < NUMPACKETTYPE; i++) for (size_t i = 0; i < NUMPACKETTYPE; i++)
packetdropquantity[i] = packetquantity; packetdropquantity[i] = packetquantity;
else else
{ {
for (i = 0; i < NUMPACKETTYPE; i++) for (size_t i = 0; i < NUMPACKETTYPE; i++)
if (!stricmp(packetname, packettypename[i])) if (!stricmp(packetname, packettypename[i]))
{ {
packetdropquantity[i] = packetquantity; packetdropquantity[i] = packetquantity;
@ -986,14 +936,12 @@ void Command_Droprate(void)
packetdroprate = droprate; packetdroprate = droprate;
} }
#ifndef NONET
static boolean ShouldDropPacket(void) static boolean ShouldDropPacket(void)
{ {
return (packetdropquantity[netbuffer->packettype]) return (packetdropquantity[netbuffer->packettype])
|| (packetdroprate != 0 && rand() < (RAND_MAX * (packetdroprate / 100.f))) || packetdroprate == 100; || (packetdroprate != 0 && rand() < (RAND_MAX * (packetdroprate / 100.f))) || packetdroprate == 100;
} }
#endif #endif
#endif
// //
// HSendPacket // HSendPacket
@ -1028,11 +976,6 @@ boolean HSendPacket(INT32 node, boolean reliable, UINT8 acknum, size_t packetlen
if (!netgame) if (!netgame)
I_Error("Tried to transmit to another node"); I_Error("Tried to transmit to another node");
#ifdef NONET
(void)node;
(void)reliable;
(void)acknum;
#else
// do this before GetFreeAcknum because this function backups // do this before GetFreeAcknum because this function backups
// the current packet // the current packet
doomcom->remotenode = (INT16)node; doomcom->remotenode = (INT16)node;
@ -1093,8 +1036,6 @@ boolean HSendPacket(INT32 node, boolean reliable, UINT8 acknum, size_t packetlen
} }
#endif #endif
#endif // ndef NONET
return true; return true;
} }
@ -1112,10 +1053,7 @@ boolean HGetPacket(void)
{ {
M_Memcpy(netbuffer, &reboundstore[rebound_tail], reboundsize[rebound_tail]); M_Memcpy(netbuffer, &reboundstore[rebound_tail], reboundsize[rebound_tail]);
doomcom->datalength = reboundsize[rebound_tail]; doomcom->datalength = reboundsize[rebound_tail];
if (netbuffer->packettype == PT_NODETIMEOUT) doomcom->remotenode = 0;
doomcom->remotenode = netbuffer->u.textcmd[0];
else
doomcom->remotenode = 0;
rebound_tail = (rebound_tail+1) % MAXREBOUND; rebound_tail = (rebound_tail+1) % MAXREBOUND;
#ifdef DEBUGFILE #ifdef DEBUGFILE
@ -1128,8 +1066,6 @@ boolean HGetPacket(void)
if (!netgame) if (!netgame)
return false; return false;
#ifndef NONET
while(true) while(true)
{ {
//nodejustjoined = I_NetGet(); //nodejustjoined = I_NetGet();
@ -1189,7 +1125,6 @@ boolean HGetPacket(void)
} }
break; break;
} }
#endif // ndef NONET
return true; return true;
} }
@ -1399,13 +1334,12 @@ void Command_Ping_f(void)
int name_width = 0; int name_width = 0;
int ms_width = 0; int ms_width = 0;
int n;
INT32 i;
pingc = 0; pingc = 0;
for (i = 1; i < MAXPLAYERS; ++i) for (INT32 i = 1; i < MAXPLAYERS; ++i)
if (playeringame[i]) if (playeringame[i])
{ {
int n;
n = strlen(player_names[i]); n = strlen(player_names[i]);
if (n > name_width) if (n > name_width)
name_width = n; name_width = n;
@ -1425,7 +1359,7 @@ void Command_Ping_f(void)
qsort(pingv, pingc, sizeof (struct pingcell), &pingcellcmp); qsort(pingv, pingc, sizeof (struct pingcell), &pingcellcmp);
for (i = 0; i < pingc; ++i) for (INT32 i = 0; i < pingc; ++i)
{ {
CONS_Printf("%02d : %-*s %*d ms\n", CONS_Printf("%02d : %-*s %*d ms\n",
pingv[i].num, pingv[i].num,
@ -1441,15 +1375,13 @@ void Command_Ping_f(void)
void D_CloseConnection(void) void D_CloseConnection(void)
{ {
INT32 i;
if (netgame) if (netgame)
{ {
// wait the ackreturn with timout of 5 Sec // wait the ackreturn with timout of 5 Sec
Net_WaitAllAckReceived(5); Net_WaitAllAckReceived(5);
// close all connection // close all connection
for (i = 0; i < MAXNETNODES; i++) for (INT32 i = 0; i < MAXNETNODES; i++)
Net_CloseConnection(i|FORCECLOSE); Net_CloseConnection(i|FORCECLOSE);
InitAck(); InitAck();

View file

@ -18,6 +18,8 @@
#ifndef __D_NET__ #ifndef __D_NET__
#define __D_NET__ #define __D_NET__
#include "../doomtype.h"
// Max computers in a game // Max computers in a game
// 127 is probably as high as this can go, because // 127 is probably as high as this can go, because
// SINT8 is used for nodes sometimes >:( // SINT8 is used for nodes sometimes >:(
@ -37,10 +39,24 @@ boolean Net_GetNetStat(void);
extern INT32 getbytes; extern INT32 getbytes;
extern INT64 sendbytes; // Realtime updated extern INT64 sendbytes; // Realtime updated
extern SINT8 nodetoplayer[MAXNETNODES]; typedef struct netnode_s
extern SINT8 nodetoplayer2[MAXNETNODES]; // Say the numplayer for this node if any (splitscreen) {
extern UINT8 playerpernode[MAXNETNODES]; // Used specially for splitscreen boolean ingame; // set false as nodes leave game
extern boolean nodeingame[MAXNETNODES]; // Set false as nodes leave game tic_t freezetimeout; // Until when can this node freeze the server before getting a timeout?
SINT8 player;
SINT8 player2; // say the numplayer for this node if any (splitscreen)
UINT8 numplayers; // used specialy for scplitscreen
tic_t tic; // what tic the client have received
tic_t supposedtic; // nettics prevision for smaller packet
boolean sendingsavegame; // Are we sending the savegame?
boolean resendingsavegame; // Are we resending the savegame?
tic_t savegameresendcooldown; // How long before we can resend again?
} netnode_t;
extern netnode_t netnodes[MAXNETNODES];
extern boolean serverrunning; extern boolean serverrunning;
@ -52,9 +68,6 @@ boolean HSendPacket(INT32 node, boolean reliable, UINT8 acknum,
size_t packetlength); size_t packetlength);
boolean HGetPacket(void); boolean HGetPacket(void);
void D_SetDoomcom(void); void D_SetDoomcom(void);
#ifndef NONET
void D_SaveBan(void);
#endif
boolean D_CheckNetGame(void); boolean D_CheckNetGame(void);
void D_CloseConnection(void); void D_CloseConnection(void);
void Net_UnAcknowledgePacket(INT32 node); void Net_UnAcknowledgePacket(INT32 node);

View file

@ -12,44 +12,46 @@
/// commands are executed through the command buffer /// commands are executed through the command buffer
/// like console commands, other miscellaneous commands (at the end) /// like console commands, other miscellaneous commands (at the end)
#include "doomdef.h" #include "../doomdef.h"
#include "console.h" #include "../console.h"
#include "command.h" #include "../command.h"
#include "i_time.h" #include "../i_time.h"
#include "i_system.h" #include "../i_system.h"
#include "g_game.h" #include "../g_game.h"
#include "hu_stuff.h" #include "../hu_stuff.h"
#include "g_input.h" #include "../g_input.h"
#include "m_menu.h" #include "../m_menu.h"
#include "r_local.h" #include "../r_local.h"
#include "r_skins.h" #include "../r_skins.h"
#include "p_local.h" #include "../p_local.h"
#include "p_setup.h" #include "../p_setup.h"
#include "s_sound.h" #include "../s_sound.h"
#include "i_sound.h" #include "../i_sound.h"
#include "m_misc.h" #include "../m_misc.h"
#include "am_map.h" #include "../am_map.h"
#include "byteptr.h" #include "../byteptr.h"
#include "d_netfil.h" #include "d_netfil.h"
#include "p_spec.h" #include "../p_spec.h"
#include "m_cheat.h" #include "../m_cheat.h"
#include "d_clisrv.h" #include "d_clisrv.h"
#include "server_connection.h"
#include "net_command.h"
#include "d_net.h" #include "d_net.h"
#include "v_video.h" #include "../v_video.h"
#include "d_main.h" #include "../d_main.h"
#include "m_random.h" #include "../m_random.h"
#include "f_finale.h" #include "../f_finale.h"
#include "filesrch.h" #include "../filesrch.h"
#include "mserv.h" #include "mserv.h"
#include "z_zone.h" #include "../z_zone.h"
#include "lua_script.h" #include "../lua_script.h"
#include "lua_hook.h" #include "../lua_hook.h"
#include "m_cond.h" #include "../m_cond.h"
#include "m_anigif.h" #include "../m_anigif.h"
#include "md5.h" #include "../md5.h"
#include "m_perfstats.h" #include "../m_perfstats.h"
#include "u_list.h" #include "../u_list.h"
#ifdef NETGAME_DEVMODE #ifdef NETGAME_DEVMODE
#define CV_RESTRICT CV_NETVAR #define CV_RESTRICT CV_NETVAR
@ -595,13 +597,10 @@ void D_RegisterServerCommands(void)
CV_RegisterVar(&cv_maxsend); CV_RegisterVar(&cv_maxsend);
CV_RegisterVar(&cv_noticedownload); CV_RegisterVar(&cv_noticedownload);
CV_RegisterVar(&cv_downloadspeed); CV_RegisterVar(&cv_downloadspeed);
#ifndef NONET
CV_RegisterVar(&cv_allownewplayer); CV_RegisterVar(&cv_allownewplayer);
CV_RegisterVar(&cv_joinnextround);
CV_RegisterVar(&cv_showjoinaddress); CV_RegisterVar(&cv_showjoinaddress);
CV_RegisterVar(&cv_blamecfail); CV_RegisterVar(&cv_blamecfail);
CV_RegisterVar(&cv_dedicatedidletime); CV_RegisterVar(&cv_dedicatedidletime);
#endif
COM_AddCommand("ping", Command_Ping_f, COM_LUA); COM_AddCommand("ping", Command_Ping_f, COM_LUA);
CV_RegisterVar(&cv_nettimeout); CV_RegisterVar(&cv_nettimeout);
@ -1742,8 +1741,7 @@ void D_MapChange(INT32 mapnum, INT32 newgametype, boolean pultmode, boolean rese
// reset players if there is a new one // reset players if there is a new one
if (!IsPlayerAdmin(consoleplayer)) if (!IsPlayerAdmin(consoleplayer))
{ {
if (SV_SpawnServer()) SV_SpawnServer();
buf[0] &= ~(1<<1);
if (!Playing()) // you failed to start a server somehow, so cancel the map change if (!Playing()) // you failed to start a server somehow, so cancel the map change
return; return;
} }

View file

@ -15,7 +15,7 @@
#ifndef __D_NETCMD__ #ifndef __D_NETCMD__
#define __D_NETCMD__ #define __D_NETCMD__
#include "command.h" #include "../command.h"
// console vars // console vars
extern consvar_t cv_playername; extern consvar_t cv_playername;

View file

@ -31,24 +31,25 @@
#include <sys/utime.h> #include <sys/utime.h>
#endif #endif
#include "doomdef.h" #include "../doomdef.h"
#include "doomstat.h" #include "../doomstat.h"
#include "d_main.h" #include "../d_main.h"
#include "g_game.h" #include "../g_game.h"
#include "i_time.h" #include "../i_time.h"
#include "i_net.h" #include "i_net.h"
#include "i_system.h" #include "../i_system.h"
#include "m_argv.h" #include "../m_argv.h"
#include "d_net.h" #include "d_net.h"
#include "w_wad.h" #include "../w_wad.h"
#include "d_netfil.h" #include "d_netfil.h"
#include "z_zone.h" #include "net_command.h"
#include "byteptr.h" #include "../z_zone.h"
#include "p_setup.h" #include "../byteptr.h"
#include "m_misc.h" #include "../p_setup.h"
#include "m_menu.h" #include "../m_misc.h"
#include "md5.h" #include "../m_menu.h"
#include "filesrch.h" #include "../md5.h"
#include "../filesrch.h"
#include <errno.h> #include <errno.h>
@ -103,26 +104,31 @@ typedef struct
} pauseddownload_t; } pauseddownload_t;
static pauseddownload_t *pauseddownload = NULL; static pauseddownload_t *pauseddownload = NULL;
#ifndef NONET
// for cl loading screen // for cl loading screen
INT32 lastfilenum = -1; INT32 lastfilenum = -1;
INT32 downloadcompletednum = 0; INT32 downloadcompletednum = 0;
UINT32 downloadcompletedsize = 0; UINT32 downloadcompletedsize = 0;
INT32 totalfilesrequestednum = 0; INT32 totalfilesrequestednum = 0;
UINT32 totalfilesrequestedsize = 0; UINT32 totalfilesrequestedsize = 0;
#endif
luafiletransfer_t *luafiletransfers = NULL; luafiletransfer_t *luafiletransfers = NULL;
boolean waitingforluafiletransfer = false; boolean waitingforluafiletransfer = false;
boolean waitingforluafilecommand = false; boolean waitingforluafilecommand = false;
char luafiledir[256 + 16] = "luafiles"; char luafiledir[256 + 16] = "luafiles";
// max file size to send to a player (in kilobytes)
static CV_PossibleValue_t maxsend_cons_t[] = {{0, "MIN"}, {204800, "MAX"}, {0, NULL}};
consvar_t cv_maxsend = CVAR_INIT ("maxsend", "4096", CV_SAVE|CV_NETVAR, maxsend_cons_t, NULL);
consvar_t cv_noticedownload = CVAR_INIT ("noticedownload", "Off", CV_SAVE|CV_NETVAR, CV_OnOff, NULL);
// Speed of file downloading (in packets per tic)
static CV_PossibleValue_t downloadspeed_cons_t[] = {{1, "MIN"}, {300, "MAX"}, {0, NULL}};
consvar_t cv_downloadspeed = CVAR_INIT ("downloadspeed", "16", CV_SAVE|CV_NETVAR, downloadspeed_cons_t, NULL);
static UINT16 GetWadNumFromFileNeededId(UINT8 id) static UINT16 GetWadNumFromFileNeededId(UINT8 id)
{ {
UINT16 wadnum; for (UINT16 wadnum = mainwads; wadnum < numwadfiles; wadnum++)
for (wadnum = mainwads; wadnum < numwadfiles; wadnum++)
{ {
if (!wadfiles[wadnum]->important) if (!wadfiles[wadnum]->important)
continue; continue;
@ -142,14 +148,13 @@ static UINT16 GetWadNumFromFileNeededId(UINT8 id)
*/ */
UINT8 *PutFileNeeded(UINT16 firstfile) UINT8 *PutFileNeeded(UINT16 firstfile)
{ {
size_t i;
UINT8 count = 0; UINT8 count = 0;
UINT8 *p_start = netbuffer->packettype == PT_MOREFILESNEEDED ? netbuffer->u.filesneededcfg.files : netbuffer->u.serverinfo.fileneeded; UINT8 *p_start = netbuffer->packettype == PT_MOREFILESNEEDED ? netbuffer->u.filesneededcfg.files : netbuffer->u.serverinfo.fileneeded;
UINT8 *p = p_start; UINT8 *p = p_start;
char wadfilename[MAX_WADPATH] = ""; char wadfilename[MAX_WADPATH] = "";
UINT8 filestatus, folder; UINT8 filestatus, folder;
for (i = mainwads; i < numwadfiles; i++) //mainwads, otherwise we start on the first mainwad for (size_t i = mainwads; i < numwadfiles; i++) //mainwads, otherwise we start on the first mainwad
{ {
// If it has only music/sound lumps, don't put it in the list // If it has only music/sound lumps, don't put it in the list
if (!wadfiles[i]->important) if (!wadfiles[i]->important)
@ -224,7 +229,6 @@ void FreeFileNeeded(void)
*/ */
void D_ParseFileneeded(INT32 fileneedednum_parm, UINT8 *fileneededstr, UINT16 firstfile) void D_ParseFileneeded(INT32 fileneedednum_parm, UINT8 *fileneededstr, UINT16 firstfile)
{ {
INT32 i;
UINT8 *p; UINT8 *p;
UINT8 filestatus; UINT8 filestatus;
@ -233,7 +237,7 @@ void D_ParseFileneeded(INT32 fileneedednum_parm, UINT8 *fileneededstr, UINT16 fi
AllocFileNeeded(fileneedednum); AllocFileNeeded(fileneedednum);
for (i = firstfile; i < fileneedednum; i++) for (INT32 i = firstfile; i < fileneedednum; i++)
{ {
fileneeded[i].type = FILENEEDED_WAD; fileneeded[i].type = FILENEEDED_WAD;
fileneeded[i].status = FS_NOTCHECKED; // We haven't even started looking for the file yet fileneeded[i].status = FS_NOTCHECKED; // We haven't even started looking for the file yet
@ -250,9 +254,7 @@ void D_ParseFileneeded(INT32 fileneedednum_parm, UINT8 *fileneededstr, UINT16 fi
void CL_PrepareDownloadSaveGame(const char *tmpsave) void CL_PrepareDownloadSaveGame(const char *tmpsave)
{ {
#ifndef NONET
lastfilenum = -1; lastfilenum = -1;
#endif
FreeFileNeeded(); FreeFileNeeded();
AllocFileNeeded(1); AllocFileNeeded(1);
@ -275,9 +277,9 @@ void CL_PrepareDownloadSaveGame(const char *tmpsave)
*/ */
boolean CL_CheckDownloadable(void) boolean CL_CheckDownloadable(void)
{ {
UINT8 i,dlstatus = 0; UINT8 dlstatus = 0;
for (i = 0; i < fileneedednum; i++) for (UINT8 i = 0; i < fileneedednum; i++)
if (fileneeded[i].status != FS_FOUND && fileneeded[i].status != FS_OPEN) if (fileneeded[i].status != FS_FOUND && fileneeded[i].status != FS_OPEN)
{ {
if (fileneeded[i].willsend == 1) if (fileneeded[i].willsend == 1)
@ -298,7 +300,7 @@ boolean CL_CheckDownloadable(void)
// not downloadable, put reason in console // not downloadable, put reason in console
CONS_Alert(CONS_NOTICE, M_GetText("You need additional files to connect to this server:\n")); CONS_Alert(CONS_NOTICE, M_GetText("You need additional files to connect to this server:\n"));
for (i = 0; i < fileneedednum; i++) for (UINT8 i = 0; i < fileneedednum; i++)
if (fileneeded[i].status != FS_FOUND && fileneeded[i].status != FS_OPEN) if (fileneeded[i].status != FS_FOUND && fileneeded[i].status != FS_OPEN)
{ {
CONS_Printf(" * \"%s\" (%dK)", fileneeded[i].filename, fileneeded[i].totalsize >> 10); CONS_Printf(" * \"%s\" (%dK)", fileneeded[i].filename, fileneeded[i].totalsize >> 10);
@ -368,14 +370,13 @@ void CL_AbortDownloadResume(void)
boolean CL_SendFileRequest(void) boolean CL_SendFileRequest(void)
{ {
char *p; char *p;
INT32 i;
INT64 totalfreespaceneeded = 0, availablefreespace; INT64 totalfreespaceneeded = 0, availablefreespace;
#ifdef PARANOIA #ifdef PARANOIA
if (M_CheckParm("-nodownload")) if (M_CheckParm("-nodownload"))
I_Error("Attempted to download files in -nodownload mode"); I_Error("Attempted to download files in -nodownload mode");
for (i = 0; i < fileneedednum; i++) for (INT32 i = 0; i < fileneedednum; i++)
if (fileneeded[i].status != FS_FOUND && fileneeded[i].status != FS_OPEN if (fileneeded[i].status != FS_FOUND && fileneeded[i].status != FS_OPEN
&& (fileneeded[i].willsend == 0 || fileneeded[i].willsend == 2)) && (fileneeded[i].willsend == 0 || fileneeded[i].willsend == 2))
{ {
@ -385,7 +386,7 @@ boolean CL_SendFileRequest(void)
netbuffer->packettype = PT_REQUESTFILE; netbuffer->packettype = PT_REQUESTFILE;
p = (char *)netbuffer->u.textcmd; p = (char *)netbuffer->u.textcmd;
for (i = 0; i < fileneedednum; i++) for (INT32 i = 0; i < fileneedednum; i++)
if ((fileneeded[i].status == FS_NOTFOUND || fileneeded[i].status == FS_MD5SUMBAD)) if ((fileneeded[i].status == FS_NOTFOUND || fileneeded[i].status == FS_MD5SUMBAD))
{ {
totalfreespaceneeded += fileneeded[i].totalsize; totalfreespaceneeded += fileneeded[i].totalsize;
@ -413,26 +414,31 @@ boolean CL_SendFileRequest(void)
} }
// get request filepak and put it on the send queue // get request filepak and put it on the send queue
// returns false if a requested file was not found or cannot be sent void PT_RequestFile(SINT8 node)
boolean PT_RequestFile(INT32 node)
{ {
UINT8 *p = netbuffer->u.textcmd; UINT8 *p = netbuffer->u.textcmd;
UINT8 id;
if (client || !cv_downloading.value)
{
Net_CloseConnection(node); // close connection if you are not the server or disabled downloading
return;
}
while (p < netbuffer->u.textcmd + MAXTEXTCMD-1) // Don't allow hacked client to overflow while (p < netbuffer->u.textcmd + MAXTEXTCMD-1) // Don't allow hacked client to overflow
{ {
id = READUINT8(p); UINT8 id = READUINT8(p);
if (id == 0xFF) if (id == 0xFF)
break; break;
if (!AddFileToSendQueue(node, id)) if (!AddFileToSendQueue(node, id))
{ {
SV_AbortSendFiles(node); SV_AbortSendFiles(node);
return false; // don't read the rest of the files Net_CloseConnection(node); // close connection if one of the requested files could not be sent
return; // don't read the rest of the files
} }
} }
return true; // no problems with any files return; // no problems with any files
} }
/** Checks if the files needed aren't already loaded or on the disk /** Checks if the files needed aren't already loaded or on the disk
@ -531,9 +537,7 @@ INT32 CL_CheckFiles(void)
// Load it now // Load it now
boolean CL_LoadServerFiles(void) boolean CL_LoadServerFiles(void)
{ {
INT32 i; for (INT32 i = 0; i < fileneedednum; i++)
for (i = 0; i < fileneedednum; i++)
{ {
if (fileneeded[i].status == FS_OPEN) if (fileneeded[i].status == FS_OPEN)
continue; // Already loaded continue; // Already loaded
@ -629,11 +633,10 @@ void AddLuaFileTransfer(const char *filename, const char *mode)
static void SV_PrepareSendLuaFileToNextNode(void) static void SV_PrepareSendLuaFileToNextNode(void)
{ {
INT32 i;
UINT8 success = 1; UINT8 success = 1;
// Find a client to send the file to // Find a client to send the file to
for (i = 1; i < MAXNETNODES; i++) for (INT32 i = 1; i < MAXNETNODES; i++)
if (luafiletransfers->nodestatus[i] == LFTNS_WAITING) // Node waiting if (luafiletransfers->nodestatus[i] == LFTNS_WAITING) // Node waiting
{ {
// Tell the client we're about to send them the file // Tell the client we're about to send them the file
@ -655,13 +658,12 @@ static void SV_PrepareSendLuaFileToNextNode(void)
void SV_PrepareSendLuaFile(void) void SV_PrepareSendLuaFile(void)
{ {
char *binfilename; char *binfilename;
INT32 i;
luafiletransfers->ongoing = true; luafiletransfers->ongoing = true;
// Set status to "waiting" for everyone // Set status to "waiting" for everyone
for (i = 0; i < MAXNETNODES; i++) for (INT32 i = 0; i < MAXNETNODES; i++)
luafiletransfers->nodestatus[i] = (nodeingame[i] ? LFTNS_WAITING : LFTNS_NONE); luafiletransfers->nodestatus[i] = (netnodes[i].ingame ? LFTNS_WAITING : LFTNS_NONE);
if (FIL_ReadFileOK(luafiletransfers->realfilename)) if (FIL_ReadFileOK(luafiletransfers->realfilename))
{ {
@ -1137,12 +1139,13 @@ void FileSendTicker(void)
} }
} }
void PT_FileAck(void) void PT_FileAck(SINT8 node)
{ {
fileack_pak *packet = &netbuffer->u.fileack; fileack_pak *packet = &netbuffer->u.fileack;
INT32 node = doomcom->remotenode;
filetran_t *trans = &transfer[node]; filetran_t *trans = &transfer[node];
INT32 i, j;
if (client)
return;
// Wrong file id? Ignore it, it's probably a late packet // Wrong file id? Ignore it, it's probably a late packet
if (!(trans->txlist && packet->fileid == trans->txlist->fileid)) if (!(trans->txlist && packet->fileid == trans->txlist->fileid))
@ -1161,11 +1164,11 @@ void PT_FileAck(void)
trans->dontsenduntil = 0; trans->dontsenduntil = 0;
} }
for (i = 0; i < packet->numsegments; i++) for (INT32 i = 0; i < packet->numsegments; i++)
{ {
fileacksegment_t *segment = &packet->segments[i]; fileacksegment_t *segment = &packet->segments[i];
for (j = 0; j < 32; j++) for (INT32 j = 0; j < 32; j++)
if (LONG(segment->acks) & (1 << j)) if (LONG(segment->acks) & (1 << j))
{ {
if (LONG(segment->start) * FILEFRAGMENTSIZE >= trans->txlist->size) if (LONG(segment->start) * FILEFRAGMENTSIZE >= trans->txlist->size)
@ -1190,24 +1193,23 @@ void PT_FileAck(void)
} }
} }
void PT_FileReceived(void) void PT_FileReceived(SINT8 node)
{ {
filetx_t *trans = transfer[doomcom->remotenode].txlist; filetx_t *trans = transfer[node].txlist;
if (trans && netbuffer->u.filereceived == trans->fileid) if (server && trans && netbuffer->u.filereceived == trans->fileid)
SV_EndFileSend(doomcom->remotenode); SV_EndFileSend(node);
} }
static void SendAckPacket(fileack_pak *packet, UINT8 fileid) static void SendAckPacket(fileack_pak *packet, UINT8 fileid)
{ {
size_t packetsize; size_t packetsize;
INT32 i;
packetsize = sizeof(*packet) + packet->numsegments * sizeof(*packet->segments); packetsize = sizeof(*packet) + packet->numsegments * sizeof(*packet->segments);
// Finalise the packet // Finalise the packet
packet->fileid = fileid; packet->fileid = fileid;
for (i = 0; i < packet->numsegments; i++) for (INT32 i = 0; i < packet->numsegments; i++)
{ {
packet->segments[i].start = LONG(packet->segments[i].start); packet->segments[i].start = LONG(packet->segments[i].start);
packet->segments[i].acks = LONG(packet->segments[i].acks); packet->segments[i].acks = LONG(packet->segments[i].acks);
@ -1247,9 +1249,7 @@ static void AddFragmentToAckPacket(fileack_pak *packet, UINT8 iteration, UINT32
void FileReceiveTicker(void) void FileReceiveTicker(void)
{ {
INT32 i; for (INT32 i = 0; i < fileneedednum; i++)
for (i = 0; i < fileneedednum; i++)
{ {
fileneeded_t *file = &fileneeded[i]; fileneeded_t *file = &fileneeded[i];
@ -1263,8 +1263,7 @@ void FileReceiveTicker(void)
if (file->ackresendposition != UINT32_MAX && file->status == FS_DOWNLOADING) if (file->ackresendposition != UINT32_MAX && file->status == FS_DOWNLOADING)
{ {
// Acknowledge ~70 MB/s, whichs means the client sends ~18 KB/s // Acknowledge ~70 MB/s, whichs means the client sends ~18 KB/s
INT32 j; for (INT32 j = 0; j < 2048; j++)
for (j = 0; j < 2048; j++)
{ {
if (file->receivedfragments[file->ackresendposition]) if (file->receivedfragments[file->ackresendposition])
AddFragmentToAckPacket(file->ackpacket, file->iteration, file->ackresendposition, i); AddFragmentToAckPacket(file->ackpacket, file->iteration, file->ackresendposition, i);
@ -1281,8 +1280,27 @@ void FileReceiveTicker(void)
} }
} }
void PT_FileFragment(void) void PT_FileFragment(SINT8 node, INT32 netconsole)
{ {
if (netnodes[node].ingame)
{
// Only accept PT_FILEFRAGMENT from the server.
if (node != servernode)
{
CONS_Alert(CONS_WARNING, M_GetText("%s received from non-host %d\n"), "PT_FILEFRAGMENT", node);
if (server)
SendKick(netconsole, KICK_MSG_CON_FAIL | KICK_MSG_KEEP_BODY);
return;
}
if (server)
return;
}
else if (server || node != servernode)
{
Net_CloseConnection(node);
return;
}
INT32 filenum = netbuffer->u.filetxpak.fileid; INT32 filenum = netbuffer->u.filetxpak.fileid;
fileneeded_t *file = &fileneeded[filenum]; fileneeded_t *file = &fileneeded[filenum];
UINT32 fragmentpos = LONG(netbuffer->u.filetxpak.position); UINT32 fragmentpos = LONG(netbuffer->u.filetxpak.position);
@ -1439,9 +1457,7 @@ void PT_FileFragment(void)
I_Error("Received a file not requested (file id: %d, file status: %s)\n", filenum, s); I_Error("Received a file not requested (file id: %d, file status: %s)\n", filenum, s);
} }
#ifndef NONET
lastfilenum = filenum; lastfilenum = filenum;
#endif
} }
/** \brief Checks if a node is downloading a file /** \brief Checks if a node is downloading a file
@ -1469,15 +1485,14 @@ void SV_AbortSendFiles(INT32 node)
void CloseNetFile(void) void CloseNetFile(void)
{ {
INT32 i;
// Is sending? // Is sending?
for (i = 0; i < MAXNETNODES; i++) for (INT32 i = 0; i < MAXNETNODES; i++)
SV_AbortSendFiles(i); SV_AbortSendFiles(i);
// Receiving a file? // Receiving a file?
if (fileneeded) if (fileneeded)
{ {
for (i = 0; i < fileneedednum; i++) for (INT32 i = 0; i < fileneedednum; i++)
if (fileneeded[i].status == FS_DOWNLOADING && fileneeded[i].file) if (fileneeded[i].status == FS_DOWNLOADING && fileneeded[i].file)
{ {
fclose(fileneeded[i].file); fclose(fileneeded[i].file);
@ -1510,9 +1525,7 @@ void CloseNetFile(void)
void Command_Downloads_f(void) void Command_Downloads_f(void)
{ {
INT32 node; for (INT32 node = 0; node < MAXNETNODES; node++)
for (node = 0; node < MAXNETNODES; node++)
if (transfer[node].txlist if (transfer[node].txlist
&& transfer[node].txlist->ram == SF_FILE) // Node is downloading a file? && transfer[node].txlist->ram == SF_FILE) // Node is downloading a file?
{ {
@ -1546,14 +1559,11 @@ void Command_Downloads_f(void)
void nameonly(char *s) void nameonly(char *s)
{ {
size_t j, len; for (size_t j = strlen(s); j != (size_t)-1; j--)
void *ns;
for (j = strlen(s); j != (size_t)-1; j--)
if ((s[j] == '\\') || (s[j] == ':') || (s[j] == '/')) if ((s[j] == '\\') || (s[j] == ':') || (s[j] == '/'))
{ {
ns = &(s[j+1]); void *ns = &(s[j+1]);
len = strlen(ns); size_t len = strlen(ns);
#if 0 #if 0
M_Memcpy(s, ns, len+1); M_Memcpy(s, ns, len+1);
#else #else
@ -1566,9 +1576,9 @@ void nameonly(char *s)
// Returns the length in characters of the last element of a path. // Returns the length in characters of the last element of a path.
size_t nameonlylength(const char *s) size_t nameonlylength(const char *s)
{ {
size_t j, len = strlen(s); size_t len = strlen(s);
for (j = len; j != (size_t)-1; j--) for (size_t j = len; j != (size_t)-1; j--)
if ((s[j] == '\\') || (s[j] == ':') || (s[j] == '/')) if ((s[j] == '\\') || (s[j] == ':') || (s[j] == '/'))
return len - j - 1; return len - j - 1;

View file

@ -15,7 +15,7 @@
#include "d_net.h" #include "d_net.h"
#include "d_clisrv.h" #include "d_clisrv.h"
#include "w_wad.h" #include "../w_wad.h"
typedef enum typedef enum
{ {
@ -70,13 +70,13 @@ extern INT32 fileneedednum;
extern fileneeded_t *fileneeded; extern fileneeded_t *fileneeded;
extern char downloaddir[512]; extern char downloaddir[512];
#ifndef NONET
extern INT32 lastfilenum; extern INT32 lastfilenum;
extern INT32 downloadcompletednum; extern INT32 downloadcompletednum;
extern UINT32 downloadcompletedsize; extern UINT32 downloadcompletedsize;
extern INT32 totalfilesrequestednum; extern INT32 totalfilesrequestednum;
extern UINT32 totalfilesrequestedsize; extern UINT32 totalfilesrequestedsize;
#endif
extern consvar_t cv_maxsend, cv_noticedownload, cv_downloadspeed;
void AllocFileNeeded(INT32 size); void AllocFileNeeded(INT32 size);
void FreeFileNeeded(void); void FreeFileNeeded(void);
@ -90,16 +90,16 @@ void AddRamToSendQueue(INT32 node, void *data, size_t size, freemethod_t freemet
UINT8 fileid); UINT8 fileid);
void FileSendTicker(void); void FileSendTicker(void);
void PT_FileAck(void); void PT_FileAck(SINT8 node);
void PT_FileReceived(void); void PT_FileReceived(SINT8 node);
boolean SendingFile(INT32 node); boolean SendingFile(INT32 node);
void FileReceiveTicker(void); void FileReceiveTicker(void);
void PT_FileFragment(void); void PT_FileFragment(SINT8 node, INT32 netconsole);
boolean CL_CheckDownloadable(void); boolean CL_CheckDownloadable(void);
boolean CL_SendFileRequest(void); boolean CL_SendFileRequest(void);
boolean PT_RequestFile(INT32 node); void PT_RequestFile(SINT8 node);
typedef enum typedef enum
{ {

336
src/netcode/gamestate.c Normal file
View file

@ -0,0 +1,336 @@
// SONIC ROBO BLAST 2
//-----------------------------------------------------------------------------
// Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2023 by Sonic Team Junior.
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
// See the 'LICENSE' file for more details.
//-----------------------------------------------------------------------------
/// \file gamestate.c
/// \brief Gamestate (re)sending
#include "d_clisrv.h"
#include "d_netfil.h"
#include "gamestate.h"
#include "i_net.h"
#include "protocol.h"
#include "server_connection.h"
#include "../am_map.h"
#include "../byteptr.h"
#include "../console.h"
#include "../d_main.h"
#include "../doomstat.h"
#include "../doomtype.h"
#include "../f_finale.h"
#include "../g_demo.h"
#include "../g_game.h"
#include "../i_time.h"
#include "../lua_script.h"
#include "../lzf.h"
#include "../m_misc.h"
#include "../p_local.h"
#include "../p_saveg.h"
#include "../r_main.h"
#include "../tables.h"
#include "../z_zone.h"
#if defined (__GNUC__) || defined (__unix__)
#include <unistd.h>
#endif
#define SAVEGAMESIZE (768*1024)
UINT8 hu_redownloadinggamestate = 0;
boolean cl_redownloadinggamestate = false;
boolean SV_ResendingSavegameToAnyone(void)
{
for (INT32 i = 0; i < MAXNETNODES; i++)
if (netnodes[i].resendingsavegame)
return true;
return false;
}
void SV_SendSaveGame(INT32 node, boolean resending)
{
size_t length, compressedlen;
UINT8 *savebuffer;
UINT8 *compressedsave;
UINT8 *buffertosend;
// first save it in a malloced buffer
savebuffer = (UINT8 *)malloc(SAVEGAMESIZE);
if (!savebuffer)
{
CONS_Alert(CONS_ERROR, M_GetText("No more free memory for savegame\n"));
return;
}
// Leave room for the uncompressed length.
save_p = savebuffer + sizeof(UINT32);
P_SaveNetGame(resending);
length = save_p - savebuffer;
if (length > SAVEGAMESIZE)
{
free(savebuffer);
save_p = NULL;
I_Error("Savegame buffer overrun");
}
// Allocate space for compressed save: one byte fewer than for the
// uncompressed data to ensure that the compression is worthwhile.
compressedsave = malloc(length - 1);
if (!compressedsave)
{
CONS_Alert(CONS_ERROR, M_GetText("No more free memory for savegame\n"));
return;
}
// Attempt to compress it.
if((compressedlen = lzf_compress(savebuffer + sizeof(UINT32), length - sizeof(UINT32), compressedsave + sizeof(UINT32), length - sizeof(UINT32) - 1)))
{
// Compressing succeeded; send compressed data
free(savebuffer);
// State that we're compressed.
buffertosend = compressedsave;
WRITEUINT32(compressedsave, length - sizeof(UINT32));
length = compressedlen + sizeof(UINT32);
}
else
{
// Compression failed to make it smaller; send original
free(compressedsave);
// State that we're not compressed
buffertosend = savebuffer;
WRITEUINT32(savebuffer, 0);
}
AddRamToSendQueue(node, buffertosend, length, SF_RAM, 0);
save_p = NULL;
// Remember when we started sending the savegame so we can handle timeouts
netnodes[node].sendingsavegame = true;
netnodes[node].freezetimeout = I_GetTime() + jointimeout + length / 1024; // 1 extra tic for each kilobyte
}
#ifdef DUMPCONSISTENCY
#define TMPSAVENAME "badmath.sav"
static consvar_t cv_dumpconsistency = CVAR_INIT ("dumpconsistency", "Off", CV_SAVE|CV_NETVAR, CV_OnOff, NULL);
void SV_SavedGame(void)
{
size_t length;
UINT8 *savebuffer;
char tmpsave[256];
if (!cv_dumpconsistency.value)
return;
sprintf(tmpsave, "%s" PATHSEP TMPSAVENAME, srb2home);
// first save it in a malloced buffer
save_p = savebuffer = (UINT8 *)malloc(SAVEGAMESIZE);
if (!save_p)
{
CONS_Alert(CONS_ERROR, M_GetText("No more free memory for savegame\n"));
return;
}
P_SaveNetGame(false);
length = save_p - savebuffer;
if (length > SAVEGAMESIZE)
{
free(savebuffer);
save_p = NULL;
I_Error("Savegame buffer overrun");
}
// then save it!
if (!FIL_WriteFile(tmpsave, savebuffer, length))
CONS_Printf(M_GetText("Didn't save %s for netgame"), tmpsave);
free(savebuffer);
save_p = NULL;
}
#undef TMPSAVENAME
#endif
#define TMPSAVENAME "$$$.sav"
void CL_LoadReceivedSavegame(boolean reloading)
{
UINT8 *savebuffer = NULL;
size_t length, decompressedlen;
char tmpsave[256];
FreeFileNeeded();
sprintf(tmpsave, "%s" PATHSEP TMPSAVENAME, srb2home);
length = FIL_ReadFile(tmpsave, &savebuffer);
CONS_Printf(M_GetText("Loading savegame length %s\n"), sizeu1(length));
if (!length)
{
I_Error("Can't read savegame sent");
return;
}
save_p = savebuffer;
// Decompress saved game if necessary.
decompressedlen = READUINT32(save_p);
if(decompressedlen > 0)
{
UINT8 *decompressedbuffer = Z_Malloc(decompressedlen, PU_STATIC, NULL);
lzf_decompress(save_p, length - sizeof(UINT32), decompressedbuffer, decompressedlen);
Z_Free(savebuffer);
save_p = savebuffer = decompressedbuffer;
}
paused = false;
demoplayback = false;
titlemapinaction = TITLEMAP_OFF;
titledemo = false;
automapactive = false;
// load a base level
if (P_LoadNetGame(reloading))
{
const UINT8 actnum = mapheaderinfo[gamemap-1]->actnum;
CONS_Printf(M_GetText("Map is now \"%s"), G_BuildMapName(gamemap));
if (strcmp(mapheaderinfo[gamemap-1]->lvlttl, ""))
{
CONS_Printf(": %s", mapheaderinfo[gamemap-1]->lvlttl);
if (!(mapheaderinfo[gamemap-1]->levelflags & LF_NOZONE))
CONS_Printf(M_GetText(" Zone"));
if (actnum > 0)
CONS_Printf(" %2d", actnum);
}
CONS_Printf("\"\n");
}
// done
Z_Free(savebuffer);
save_p = NULL;
if (unlink(tmpsave) == -1)
CONS_Alert(CONS_ERROR, M_GetText("Can't delete %s\n"), tmpsave);
consistancy[gametic%BACKUPTICS] = Consistancy();
CON_ToggleOff();
// Tell the server we have received and reloaded the gamestate
// so they know they can resume the game
netbuffer->packettype = PT_RECEIVEDGAMESTATE;
HSendPacket(servernode, true, 0, 0);
}
void CL_ReloadReceivedSavegame(void)
{
for (INT32 i = 0; i < MAXPLAYERS; i++)
{
LUA_InvalidatePlayer(&players[i]);
sprintf(player_names[i], "Player %d", i + 1);
}
CL_LoadReceivedSavegame(true);
neededtic = max(neededtic, gametic);
maketic = neededtic;
ticcmd_oldangleturn[0] = players[consoleplayer].oldrelangleturn;
P_ForceLocalAngle(&players[consoleplayer], (angle_t)(players[consoleplayer].angleturn << 16));
if (splitscreen)
{
ticcmd_oldangleturn[1] = players[secondarydisplayplayer].oldrelangleturn;
P_ForceLocalAngle(&players[secondarydisplayplayer], (angle_t)(players[secondarydisplayplayer].angleturn << 16));
}
camera.subsector = R_PointInSubsector(camera.x, camera.y);
camera2.subsector = R_PointInSubsector(camera2.x, camera2.y);
cl_redownloadinggamestate = false;
CONS_Printf(M_GetText("Game state reloaded\n"));
}
void Command_ResendGamestate(void)
{
SINT8 playernum;
if (COM_Argc() == 1)
{
CONS_Printf(M_GetText("resendgamestate <playername/playernum>: resend the game state to a player\n"));
return;
}
else if (client)
{
CONS_Printf(M_GetText("Only the server can use this.\n"));
return;
}
playernum = nametonum(COM_Argv(1));
if (playernum == -1 || playernum == 0)
return;
// Send a PT_WILLRESENDGAMESTATE packet to the client so they know what's going on
netbuffer->packettype = PT_WILLRESENDGAMESTATE;
if (!HSendPacket(playernode[playernum], true, 0, 0))
{
CONS_Alert(CONS_ERROR, M_GetText("A problem occurred, please try again.\n"));
return;
}
}
void PT_CanReceiveGamestate(SINT8 node)
{
if (client || netnodes[node].sendingsavegame)
return;
CONS_Printf(M_GetText("Resending game state to %s...\n"), player_names[netnodes[node].player]);
SV_SendSaveGame(node, true); // Resend a complete game state
netnodes[node].resendingsavegame = true;
}
void PT_ReceivedGamestate(SINT8 node)
{
netnodes[node].sendingsavegame = false;
netnodes[node].resendingsavegame = false;
netnodes[node].savegameresendcooldown = I_GetTime() + 5 * TICRATE;
}
void PT_WillResendGamestate(SINT8 node)
{
(void)node;
char tmpsave[256];
if (server || cl_redownloadinggamestate)
return;
// Send back a PT_CANRECEIVEGAMESTATE packet to the server
// so they know they can start sending the game state
netbuffer->packettype = PT_CANRECEIVEGAMESTATE;
if (!HSendPacket(servernode, true, 0, 0))
return;
CONS_Printf(M_GetText("Reloading game state...\n"));
sprintf(tmpsave, "%s" PATHSEP TMPSAVENAME, srb2home);
// Don't get a corrupt savegame error because tmpsave already exists
if (FIL_FileExists(tmpsave) && unlink(tmpsave) == -1)
I_Error("Can't delete %s\n", tmpsave);
CL_PrepareDownloadSaveGame(tmpsave);
cl_redownloadinggamestate = true;
}

31
src/netcode/gamestate.h Normal file
View file

@ -0,0 +1,31 @@
// SONIC ROBO BLAST 2
//-----------------------------------------------------------------------------
// Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2023 by Sonic Team Junior.
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
// See the 'LICENSE' file for more details.
//-----------------------------------------------------------------------------
/// \file gamestate.h
/// \brief Gamestate (re)sending
#ifndef __GAMESTATE__
#define __GAMESTATE__
#include "../doomtype.h"
extern UINT8 hu_redownloadinggamestate;
extern boolean cl_redownloadinggamestate;
boolean SV_ResendingSavegameToAnyone(void);
void SV_SendSaveGame(INT32 node, boolean resending);
void SV_SavedGame(void);
void CL_LoadReceivedSavegame(boolean reloading);
void CL_ReloadReceivedSavegame(void);
void Command_ResendGamestate(void);
void PT_CanReceiveGamestate(SINT8 node);
void PT_ReceivedGamestate(SINT8 node);
void PT_WillResendGamestate(SINT8 node);
#endif

View file

@ -18,14 +18,15 @@ Documentation available here.
#include <curl/curl.h> #include <curl/curl.h>
#endif #endif
#include "doomdef.h" #include "../doomdef.h"
#include "d_clisrv.h" #include "d_clisrv.h"
#include "command.h" #include "client_connection.h"
#include "m_argv.h" #include "../command.h"
#include "m_menu.h" #include "../m_argv.h"
#include "../m_menu.h"
#include "mserv.h" #include "mserv.h"
#include "i_tcp.h"/* for current_port */ #include "i_tcp.h"/* for current_port */
#include "i_threads.h" #include "../i_threads.h"
/* reasonable default I guess?? */ /* reasonable default I guess?? */
#define DEFAULT_BUFFER_SIZE (4096) #define DEFAULT_BUFFER_SIZE (4096)
@ -95,7 +96,7 @@ init_user_agent_once(void)
{ {
if (hms_useragent[0] != '\0') if (hms_useragent[0] != '\0')
return; return;
get_user_agent(hms_useragent, 512); get_user_agent(hms_useragent, 512);
} }

View file

@ -18,8 +18,8 @@
#pragma interface #pragma interface
#endif #endif
#include "doomdef.h" #include "../doomdef.h"
#include "command.h" #include "../command.h"
/// \brief program net id /// \brief program net id
#define DOOMCOM_ID (INT32)0x12345678l #define DOOMCOM_ID (INT32)0x12345678l

View file

@ -36,109 +36,100 @@
#include <ws2tcpip.h> #include <ws2tcpip.h>
#endif #endif
#include "doomdef.h" #include "../doomdef.h"
#if defined (NOMD5) && !defined (NONET) #ifdef USE_WINSOCK1
//#define NONET #include <winsock.h>
#else
#ifndef USE_WINSOCK
#include <arpa/inet.h>
#ifdef __APPLE_CC__
#ifndef _BSD_SOCKLEN_T_
#define _BSD_SOCKLEN_T_
#endif //_BSD_SOCKLEN_T_
#endif //__APPLE_CC__
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <sys/ioctl.h>
#endif //normal BSD API
#include <errno.h>
#include <time.h>
#if defined (__unix__) || defined (__APPLE__) || defined (UNIXCOMMON)
#include <sys/time.h>
#endif // UNIXCOMMON
#endif #endif
#ifdef NONET #ifdef USE_WINSOCK
#undef HAVE_MINIUPNPC // some undefined under win32
#else #undef errno
#ifdef USE_WINSOCK1 //#define errno WSAGetLastError() //Alam_GBC: this is the correct way, right?
#include <winsock.h> #define errno h_errno // some very strange things happen when not using h_error?!?
#else #ifdef EWOULDBLOCK
#ifndef USE_WINSOCK #undef EWOULDBLOCK
#include <arpa/inet.h>
#ifdef __APPLE_CC__
#ifndef _BSD_SOCKLEN_T_
#define _BSD_SOCKLEN_T_
#endif //_BSD_SOCKLEN_T_
#endif //__APPLE_CC__
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <sys/ioctl.h>
#endif //normal BSD API
#include <errno.h>
#include <time.h>
#if defined (__unix__) || defined (__APPLE__) || defined (UNIXCOMMON)
#include <sys/time.h>
#endif // UNIXCOMMON
#endif #endif
#define EWOULDBLOCK WSAEWOULDBLOCK
#ifdef USE_WINSOCK #ifdef EMSGSIZE
// some undefined under win32 #undef EMSGSIZE
#undef errno
//#define errno WSAGetLastError() //Alam_GBC: this is the correct way, right?
#define errno h_errno // some very strange things happen when not using h_error?!?
#ifdef EWOULDBLOCK
#undef EWOULDBLOCK
#endif
#define EWOULDBLOCK WSAEWOULDBLOCK
#ifdef EMSGSIZE
#undef EMSGSIZE
#endif
#define EMSGSIZE WSAEMSGSIZE
#ifdef ECONNREFUSED
#undef ECONNREFUSED
#endif
#define ECONNREFUSED WSAECONNREFUSED
#ifdef ETIMEDOUT
#undef ETIMEDOUT
#endif
#define ETIMEDOUT WSAETIMEDOUT
#ifndef IOC_VENDOR
#define IOC_VENDOR 0x18000000
#endif
#ifndef _WSAIOW
#define _WSAIOW(x,y) (IOC_IN|(x)|(y))
#endif
#ifndef SIO_UDP_CONNRESET
#define SIO_UDP_CONNRESET _WSAIOW(IOC_VENDOR,12)
#endif
#ifndef AI_ADDRCONFIG
#define AI_ADDRCONFIG 0x00000400
#endif
#ifndef STATUS_INVALID_PARAMETER
#define STATUS_INVALID_PARAMETER 0xC000000D
#endif
#endif // USE_WINSOCK
typedef union
{
struct sockaddr any;
struct sockaddr_in ip4;
#ifdef HAVE_IPV6
struct sockaddr_in6 ip6;
#endif #endif
} mysockaddr_t; #define EMSGSIZE WSAEMSGSIZE
#ifdef ECONNREFUSED
#undef ECONNREFUSED
#endif
#define ECONNREFUSED WSAECONNREFUSED
#ifdef ETIMEDOUT
#undef ETIMEDOUT
#endif
#define ETIMEDOUT WSAETIMEDOUT
#ifndef IOC_VENDOR
#define IOC_VENDOR 0x18000000
#endif
#ifndef _WSAIOW
#define _WSAIOW(x,y) (IOC_IN|(x)|(y))
#endif
#ifndef SIO_UDP_CONNRESET
#define SIO_UDP_CONNRESET _WSAIOW(IOC_VENDOR,12)
#endif
#ifndef AI_ADDRCONFIG
#define AI_ADDRCONFIG 0x00000400
#endif
#ifndef STATUS_INVALID_PARAMETER
#define STATUS_INVALID_PARAMETER 0xC000000D
#endif
#endif // USE_WINSOCK
#ifdef HAVE_MINIUPNPC typedef union
#ifdef STATIC_MINIUPNPC {
#define STATICLIB struct sockaddr any;
#endif struct sockaddr_in ip4;
#include "miniupnpc/miniwget.h" #ifdef HAVE_IPV6
#include "miniupnpc/miniupnpc.h" struct sockaddr_in6 ip6;
#include "miniupnpc/upnpcommands.h" #endif
#undef STATICLIB } mysockaddr_t;
static UINT8 UPNP_support = TRUE;
#endif // HAVE_MINIUPNC
#endif // !NONET #ifdef HAVE_MINIUPNPC
#ifdef STATIC_MINIUPNPC
#define STATICLIB
#endif
#include "miniupnpc/miniwget.h"
#include "miniupnpc/miniupnpc.h"
#include "miniupnpc/upnpcommands.h"
#undef STATICLIB
static UINT8 UPNP_support = TRUE;
#endif // HAVE_MINIUPNC
#define MAXBANS 100 #define MAXBANS 100
#include "i_system.h" #include "../i_system.h"
#include "i_net.h" #include "i_net.h"
#include "d_net.h" #include "d_net.h"
#include "d_netfil.h" #include "d_netfil.h"
#include "i_tcp.h" #include "i_tcp.h"
#include "m_argv.h" #include "../m_argv.h"
#include "doomstat.h" #include "../doomstat.h"
// win32 // win32
#ifdef USE_WINSOCK #ifdef USE_WINSOCK
@ -151,7 +142,7 @@
#define SELECTTEST #define SELECTTEST
#define DEFAULTPORT "5029" #define DEFAULTPORT "5029"
#if defined (USE_WINSOCK) && !defined (NONET) #ifdef USE_WINSOCK
typedef SOCKET SOCKET_TYPE; typedef SOCKET SOCKET_TYPE;
#define ERRSOCKET (SOCKET_ERROR) #define ERRSOCKET (SOCKET_ERROR)
#else #else
@ -163,22 +154,20 @@
#define ERRSOCKET (-1) #define ERRSOCKET (-1)
#endif #endif
#ifndef NONET // define socklen_t in DOS/Windows if it is not already defined
// define socklen_t in DOS/Windows if it is not already defined #ifdef USE_WINSOCK1
#ifdef USE_WINSOCK1 typedef int socklen_t;
typedef int socklen_t;
#endif
static SOCKET_TYPE mysockets[MAXNETNODES+1] = {ERRSOCKET};
static size_t mysocketses = 0;
static int myfamily[MAXNETNODES+1] = {0};
static SOCKET_TYPE nodesocket[MAXNETNODES+1] = {ERRSOCKET};
static mysockaddr_t clientaddress[MAXNETNODES+1];
static mysockaddr_t broadcastaddress[MAXNETNODES+1];
static size_t broadcastaddresses = 0;
static boolean nodeconnected[MAXNETNODES+1];
static mysockaddr_t banned[MAXBANS];
static UINT8 bannedmask[MAXBANS];
#endif #endif
static SOCKET_TYPE mysockets[MAXNETNODES+1] = {ERRSOCKET};
static size_t mysocketses = 0;
static int myfamily[MAXNETNODES+1] = {0};
static SOCKET_TYPE nodesocket[MAXNETNODES+1] = {ERRSOCKET};
static mysockaddr_t clientaddress[MAXNETNODES+1];
static mysockaddr_t broadcastaddress[MAXNETNODES+1];
static size_t broadcastaddresses = 0;
static boolean nodeconnected[MAXNETNODES+1];
static mysockaddr_t banned[MAXBANS];
static UINT8 bannedmask[MAXBANS];
static size_t numbans = 0; static size_t numbans = 0;
static boolean SOCK_bannednode[MAXNETNODES+1]; /// \note do we really need the +1? static boolean SOCK_bannednode[MAXNETNODES+1]; /// \note do we really need the +1?
@ -187,7 +176,6 @@ static boolean init_tcp_driver = false;
static const char *serverport_name = DEFAULTPORT; static const char *serverport_name = DEFAULTPORT;
static const char *clientport_name;/* any port */ static const char *clientport_name;/* any port */
#ifndef NONET
#ifdef USE_WINSOCK #ifdef USE_WINSOCK
// stupid microsoft makes things complicated // stupid microsoft makes things complicated
static char *get_WSAErrorStr(int e) static char *get_WSAErrorStr(int e)
@ -387,47 +375,33 @@ static const char *SOCK_AddrToStr(mysockaddr_t *sk)
#endif #endif
return s; return s;
} }
#endif
static const char *SOCK_GetNodeAddress(INT32 node) static const char *SOCK_GetNodeAddress(INT32 node)
{ {
if (node == 0) if (node == 0)
return "self"; return "self";
#ifdef NONET
return NULL;
#else
if (!nodeconnected[node]) if (!nodeconnected[node])
return NULL; return NULL;
return SOCK_AddrToStr(&clientaddress[node]); return SOCK_AddrToStr(&clientaddress[node]);
#endif
} }
static const char *SOCK_GetBanAddress(size_t ban) static const char *SOCK_GetBanAddress(size_t ban)
{ {
if (ban >= numbans) if (ban >= numbans)
return NULL; return NULL;
#ifdef NONET
return NULL;
#else
return SOCK_AddrToStr(&banned[ban]); return SOCK_AddrToStr(&banned[ban]);
#endif
} }
static const char *SOCK_GetBanMask(size_t ban) static const char *SOCK_GetBanMask(size_t ban)
{ {
#ifdef NONET
(void)ban;
#else
static char s[16]; //255.255.255.255 netmask? no, just CDIR for only static char s[16]; //255.255.255.255 netmask? no, just CDIR for only
if (ban >= numbans) if (ban >= numbans)
return NULL; return NULL;
if (sprintf(s,"%d",bannedmask[ban]) > 0) if (sprintf(s,"%d",bannedmask[ban]) > 0)
return s; return s;
#endif
return NULL; return NULL;
} }
#ifndef NONET
static boolean SOCK_cmpaddr(mysockaddr_t *a, mysockaddr_t *b, UINT8 mask) static boolean SOCK_cmpaddr(mysockaddr_t *a, mysockaddr_t *b, UINT8 mask)
{ {
UINT32 bitmask = INADDR_NONE; UINT32 bitmask = INADDR_NONE;
@ -455,24 +429,20 @@ static boolean SOCK_cmpaddr(mysockaddr_t *a, mysockaddr_t *b, UINT8 mask)
*/ */
static void cleanupnodes(void) static void cleanupnodes(void)
{ {
SINT8 j;
if (!Playing()) if (!Playing())
return; return;
// Why can't I start at zero? // Why can't I start at zero?
for (j = 1; j < MAXNETNODES; j++) for (SINT8 j = 1; j < MAXNETNODES; j++)
if (!(nodeingame[j] || SendingFile(j))) if (!(netnodes[j].ingame || SendingFile(j)))
nodeconnected[j] = false; nodeconnected[j] = false;
} }
static SINT8 getfreenode(void) static SINT8 getfreenode(void)
{ {
SINT8 j;
cleanupnodes(); cleanupnodes();
for (j = 0; j < MAXNETNODES; j++) for (SINT8 j = 0; j < MAXNETNODES; j++)
if (!nodeconnected[j]) if (!nodeconnected[j])
{ {
nodeconnected[j] = true; nodeconnected[j] = true;
@ -485,8 +455,8 @@ static SINT8 getfreenode(void)
* downloading a needed wad, but it's better than not letting anyone join... * downloading a needed wad, but it's better than not letting anyone join...
*/ */
/*I_Error("No more free nodes!!1!11!11!!1111\n"); /*I_Error("No more free nodes!!1!11!11!!1111\n");
for (j = 1; j < MAXNETNODES; j++) for (SINT8 j = 1; j < MAXNETNODES; j++)
if (!nodeingame[j]) if (!netnodes[j].ingame)
return j;*/ return j;*/
return -1; return -1;
@ -497,28 +467,27 @@ void Command_Numnodes(void)
{ {
INT32 connected = 0; INT32 connected = 0;
INT32 ingame = 0; INT32 ingame = 0;
INT32 i;
for (i = 1; i < MAXNETNODES; i++) for (INT32 i = 1; i < MAXNETNODES; i++)
{ {
if (!(nodeconnected[i] || nodeingame[i])) if (!(nodeconnected[i] || netnodes[i].ingame))
continue; continue;
if (nodeconnected[i]) if (nodeconnected[i])
connected++; connected++;
if (nodeingame[i]) if (netnodes[i].ingame)
ingame++; ingame++;
CONS_Printf("%2d - ", i); CONS_Printf("%2d - ", i);
if (nodetoplayer[i] != -1) if (netnodes[i].player != -1)
CONS_Printf("player %.2d", nodetoplayer[i]); CONS_Printf("player %.2d", netnodes[i].player);
else else
CONS_Printf(" "); CONS_Printf(" ");
if (nodeconnected[i]) if (nodeconnected[i])
CONS_Printf(" - connected"); CONS_Printf(" - connected");
else else
CONS_Printf(" - "); CONS_Printf(" - ");
if (nodeingame[i]) if (netnodes[i].ingame)
CONS_Printf(" - ingame"); CONS_Printf(" - ingame");
else else
CONS_Printf(" - "); CONS_Printf(" - ");
@ -531,19 +500,17 @@ void Command_Numnodes(void)
connected, ingame); connected, ingame);
} }
#endif #endif
#endif
#ifndef NONET
// Returns true if a packet was received from a new node, false in all other cases // Returns true if a packet was received from a new node, false in all other cases
static boolean SOCK_Get(void) static boolean SOCK_Get(void)
{ {
size_t i, n; size_t i;
int j; int j;
ssize_t c; ssize_t c;
mysockaddr_t fromaddress; mysockaddr_t fromaddress;
socklen_t fromlen; socklen_t fromlen;
for (n = 0; n < mysocketses; n++) for (size_t n = 0; n < mysocketses; n++)
{ {
fromlen = (socklen_t)sizeof(fromaddress); fromlen = (socklen_t)sizeof(fromaddress);
c = recvfrom(mysockets[n], (char *)&doomcom->data, MAXPACKETLENGTH, 0, c = recvfrom(mysockets[n], (char *)&doomcom->data, MAXPACKETLENGTH, 0,
@ -596,20 +563,17 @@ static boolean SOCK_Get(void)
doomcom->remotenode = -1; // no packet doomcom->remotenode = -1; // no packet
return false; return false;
} }
#endif
// check if we can send (do not go over the buffer) // check if we can send (do not go over the buffer)
#ifndef NONET
static fd_set masterset; static fd_set masterset;
#ifdef SELECTTEST #ifdef SELECTTEST
static boolean FD_CPY(fd_set *src, fd_set *dst, SOCKET_TYPE *fd, size_t len) static boolean FD_CPY(fd_set *src, fd_set *dst, SOCKET_TYPE *fd, size_t len)
{ {
size_t i;
boolean testset = false; boolean testset = false;
FD_ZERO(dst); FD_ZERO(dst);
for (i = 0; i < len;i++) for (size_t i = 0; i < len;i++)
{ {
if(fd[i] != (SOCKET_TYPE)ERRSOCKET && if(fd[i] != (SOCKET_TYPE)ERRSOCKET &&
FD_ISSET(fd[i], src) && !FD_ISSET(fd[i], dst)) // no checking for dups FD_ISSET(fd[i], src) && !FD_ISSET(fd[i], dst)) // no checking for dups
@ -649,9 +613,7 @@ static boolean SOCK_CanGet(void)
return false; return false;
} }
#endif #endif
#endif
#ifndef NONET
static inline ssize_t SOCK_SendToAddr(SOCKET_TYPE socket, mysockaddr_t *sockaddr) static inline ssize_t SOCK_SendToAddr(SOCKET_TYPE socket, mysockaddr_t *sockaddr)
{ {
socklen_t d4 = (socklen_t)sizeof(struct sockaddr_in); socklen_t d4 = (socklen_t)sizeof(struct sockaddr_in);
@ -675,16 +637,15 @@ static inline ssize_t SOCK_SendToAddr(SOCKET_TYPE socket, mysockaddr_t *sockaddr
static void SOCK_Send(void) static void SOCK_Send(void)
{ {
ssize_t c = ERRSOCKET; ssize_t c = ERRSOCKET;
size_t i, j;
if (!nodeconnected[doomcom->remotenode]) if (!nodeconnected[doomcom->remotenode])
return; return;
if (doomcom->remotenode == BROADCASTADDR) if (doomcom->remotenode == BROADCASTADDR)
{ {
for (i = 0; i < mysocketses; i++) for (size_t i = 0; i < mysocketses; i++)
{ {
for (j = 0; j < broadcastaddresses; j++) for (size_t j = 0; j < broadcastaddresses; j++)
{ {
if (myfamily[i] == broadcastaddress[j].any.sa_family) if (myfamily[i] == broadcastaddress[j].any.sa_family)
SOCK_SendToAddr(mysockets[i], &broadcastaddress[j]); SOCK_SendToAddr(mysockets[i], &broadcastaddress[j]);
@ -694,7 +655,7 @@ static void SOCK_Send(void)
} }
else if (nodesocket[doomcom->remotenode] == (SOCKET_TYPE)ERRSOCKET) else if (nodesocket[doomcom->remotenode] == (SOCKET_TYPE)ERRSOCKET)
{ {
for (i = 0; i < mysocketses; i++) for (size_t i = 0; i < mysocketses; i++)
{ {
if (myfamily[i] == clientaddress[doomcom->remotenode].any.sa_family) if (myfamily[i] == clientaddress[doomcom->remotenode].any.sa_family)
SOCK_SendToAddr(mysockets[i], &clientaddress[doomcom->remotenode]); SOCK_SendToAddr(mysockets[i], &clientaddress[doomcom->remotenode]);
@ -714,9 +675,7 @@ static void SOCK_Send(void)
SOCK_GetNodeAddress(doomcom->remotenode), e, strerror(e)); SOCK_GetNodeAddress(doomcom->remotenode), e, strerror(e));
} }
} }
#endif
#ifndef NONET
static void SOCK_FreeNodenum(INT32 numnode) static void SOCK_FreeNodenum(INT32 numnode)
{ {
// can't disconnect from self :) // can't disconnect from self :)
@ -731,12 +690,10 @@ static void SOCK_FreeNodenum(INT32 numnode)
// put invalid address // put invalid address
memset(&clientaddress[numnode], 0, sizeof (clientaddress[numnode])); memset(&clientaddress[numnode], 0, sizeof (clientaddress[numnode]));
} }
#endif
// //
// UDPsocket // UDPsocket
// //
#ifndef NONET
// allocate a socket // allocate a socket
static SOCKET_TYPE UDP_Bind(int family, struct sockaddr *addr, socklen_t addrlen) static SOCKET_TYPE UDP_Bind(int family, struct sockaddr *addr, socklen_t addrlen)
@ -1061,12 +1018,10 @@ static boolean UDP_Socket(void)
return true; return true;
} }
#endif
boolean I_InitTcpDriver(void) boolean I_InitTcpDriver(void)
{ {
boolean tcp_was_up = init_tcp_driver; boolean tcp_was_up = init_tcp_driver;
#ifndef NONET
if (!init_tcp_driver) if (!init_tcp_driver)
{ {
#ifdef USE_WINSOCK #ifdef USE_WINSOCK
@ -1121,7 +1076,7 @@ boolean I_InitTcpDriver(void)
#endif #endif
init_tcp_driver = true; init_tcp_driver = true;
} }
#endif
if (!tcp_was_up && init_tcp_driver) if (!tcp_was_up && init_tcp_driver)
{ {
I_AddExitFunc(I_ShutdownTcpDriver); I_AddExitFunc(I_ShutdownTcpDriver);
@ -1135,11 +1090,9 @@ boolean I_InitTcpDriver(void)
return init_tcp_driver; return init_tcp_driver;
} }
#ifndef NONET
static void SOCK_CloseSocket(void) static void SOCK_CloseSocket(void)
{ {
size_t i; for (size_t i=0; i < MAXNETNODES+1; i++)
for (i=0; i < MAXNETNODES+1; i++)
{ {
if (mysockets[i] != (SOCKET_TYPE)ERRSOCKET if (mysockets[i] != (SOCKET_TYPE)ERRSOCKET
&& FD_ISSET(mysockets[i], &masterset)) && FD_ISSET(mysockets[i], &masterset))
@ -1150,11 +1103,9 @@ static void SOCK_CloseSocket(void)
mysockets[i] = ERRSOCKET; mysockets[i] = ERRSOCKET;
} }
} }
#endif
void I_ShutdownTcpDriver(void) void I_ShutdownTcpDriver(void)
{ {
#ifndef NONET
SOCK_CloseSocket(); SOCK_CloseSocket();
CONS_Printf("I_ShutdownTcpDriver: "); CONS_Printf("I_ShutdownTcpDriver: ");
@ -1164,10 +1115,8 @@ void I_ShutdownTcpDriver(void)
#endif #endif
CONS_Printf("shut down\n"); CONS_Printf("shut down\n");
init_tcp_driver = false; init_tcp_driver = false;
#endif
} }
#ifndef NONET
static SINT8 SOCK_NetMakeNodewPort(const char *address, const char *port) static SINT8 SOCK_NetMakeNodewPort(const char *address, const char *port)
{ {
SINT8 newnode = -1; SINT8 newnode = -1;
@ -1223,17 +1172,13 @@ static SINT8 SOCK_NetMakeNodewPort(const char *address, const char *port)
I_freeaddrinfo(ai); I_freeaddrinfo(ai);
return newnode; return newnode;
} }
#endif
static boolean SOCK_OpenSocket(void) static boolean SOCK_OpenSocket(void)
{ {
#ifndef NONET
size_t i;
memset(clientaddress, 0, sizeof (clientaddress)); memset(clientaddress, 0, sizeof (clientaddress));
nodeconnected[0] = true; // always connected to self nodeconnected[0] = true; // always connected to self
for (i = 1; i < MAXNETNODES; i++) for (size_t i = 1; i < MAXNETNODES; i++)
nodeconnected[i] = false; nodeconnected[i] = false;
nodeconnected[BROADCASTADDR] = true; nodeconnected[BROADCASTADDR] = true;
I_NetSend = SOCK_Send; I_NetSend = SOCK_Send;
@ -1251,18 +1196,12 @@ static boolean SOCK_OpenSocket(void)
// build the socket but close it first // build the socket but close it first
SOCK_CloseSocket(); SOCK_CloseSocket();
return UDP_Socket(); return UDP_Socket();
#else
return false;
#endif
} }
static boolean SOCK_Ban(INT32 node) static boolean SOCK_Ban(INT32 node)
{ {
if (node > MAXNETNODES) if (node > MAXNETNODES)
return false; return false;
#ifdef NONET
return false;
#else
if (numbans == MAXBANS) if (numbans == MAXBANS)
return false; return false;
@ -1281,16 +1220,10 @@ static boolean SOCK_Ban(INT32 node)
#endif #endif
numbans++; numbans++;
return true; return true;
#endif
} }
static boolean SOCK_SetBanAddress(const char *address, const char *mask) static boolean SOCK_SetBanAddress(const char *address, const char *mask)
{ {
#ifdef NONET
(void)address;
(void)mask;
return false;
#else
struct my_addrinfo *ai, *runp, hints; struct my_addrinfo *ai, *runp, hints;
int gaie; int gaie;
@ -1335,7 +1268,6 @@ static boolean SOCK_SetBanAddress(const char *address, const char *mask)
I_freeaddrinfo(ai); I_freeaddrinfo(ai);
return true; return true;
#endif
} }
static void SOCK_ClearBans(void) static void SOCK_ClearBans(void)

View file

@ -15,13 +15,14 @@
#include <time.h> #include <time.h>
#endif #endif
#include "doomstat.h" #include "../doomstat.h"
#include "doomdef.h" #include "../doomdef.h"
#include "command.h" #include "../command.h"
#include "i_threads.h" #include "../i_threads.h"
#include "mserv.h" #include "mserv.h"
#include "m_menu.h" #include "client_connection.h"
#include "z_zone.h" #include "../m_menu.h"
#include "../z_zone.h"
#ifdef MASTERSERVER #ifdef MASTERSERVER
@ -45,9 +46,7 @@ static I_cond MSCond;
# define Unlock_state() # define Unlock_state()
#endif/*HAVE_THREADS*/ #endif/*HAVE_THREADS*/
#ifndef NONET
static void Command_Listserv_f(void); static void Command_Listserv_f(void);
#endif
#endif/*MASTERSERVER*/ #endif/*MASTERSERVER*/
@ -89,7 +88,6 @@ msg_rooms_t room_list[NUM_LIST_ROOMS+1]; // +1 for easy test
*/ */
void AddMServCommands(void) void AddMServCommands(void)
{ {
#ifndef NONET
CV_RegisterVar(&cv_masterserver); CV_RegisterVar(&cv_masterserver);
CV_RegisterVar(&cv_masterserver_update_rate); CV_RegisterVar(&cv_masterserver_update_rate);
CV_RegisterVar(&cv_masterserver_timeout); CV_RegisterVar(&cv_masterserver_timeout);
@ -100,7 +98,6 @@ void AddMServCommands(void)
COM_AddCommand("listserv", Command_Listserv_f, 0); COM_AddCommand("listserv", Command_Listserv_f, 0);
COM_AddCommand("masterserver_update", Update_parameters, COM_LUA); // allows people to updates manually in case you were delisted by accident COM_AddCommand("masterserver_update", Update_parameters, COM_LUA); // allows people to updates manually in case you were delisted by accident
#endif #endif
#endif
} }
#ifdef MASTERSERVER #ifdef MASTERSERVER
@ -189,7 +186,6 @@ void GetMODVersion_Console(void)
} }
#endif #endif
#ifndef NONET
/** Gets a list of game servers. Called from console. /** Gets a list of game servers. Called from console.
*/ */
static void Command_Listserv_f(void) static void Command_Listserv_f(void)
@ -200,7 +196,6 @@ static void Command_Listserv_f(void)
HMS_list_servers(); HMS_list_servers();
} }
} }
#endif
static void static void
Finish_registration (void) Finish_registration (void)

View file

@ -14,7 +14,7 @@
#ifndef _MSERV_H_ #ifndef _MSERV_H_
#define _MSERV_H_ #define _MSERV_H_
#include "i_threads.h" #include "../i_threads.h"
// lowered from 32 due to menu changes // lowered from 32 due to menu changes
#define NUM_LIST_ROOMS 16 #define NUM_LIST_ROOMS 16

382
src/netcode/net_command.c Normal file
View file

@ -0,0 +1,382 @@
// SONIC ROBO BLAST 2
//-----------------------------------------------------------------------------
// Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2022 by Sonic Team Junior.
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
// See the 'LICENSE' file for more details.
//-----------------------------------------------------------------------------
/// \file net_command.c
/// \brief Net command handling
#include "net_command.h"
#include "tic_command.h"
#include "gamestate.h"
#include "server_connection.h"
#include "d_clisrv.h"
#include "i_net.h"
#include "../byteptr.h"
#include "../g_game.h"
#include "../z_zone.h"
#include "../doomtype.h"
textcmdtic_t *textcmds[TEXTCMD_HASH_SIZE] = {NULL};
UINT8 localtextcmd[MAXTEXTCMD];
UINT8 localtextcmd2[MAXTEXTCMD]; // splitscreen
static void (*listnetxcmd[MAXNETXCMD])(UINT8 **p, INT32 playernum);
void RegisterNetXCmd(netxcmd_t id, void (*cmd_f)(UINT8 **p, INT32 playernum))
{
#ifdef PARANOIA
if (id >= MAXNETXCMD)
I_Error("Command id %d too big", id);
if (listnetxcmd[id] != 0)
I_Error("Command id %d already used", id);
#endif
listnetxcmd[id] = cmd_f;
}
void SendNetXCmd(netxcmd_t id, const void *param, size_t nparam)
{
if (localtextcmd[0]+2+nparam > MAXTEXTCMD)
{
// for future reference: if (cv_debug) != debug disabled.
CONS_Alert(CONS_ERROR, M_GetText("NetXCmd buffer full, cannot add netcmd %d! (size: %d, needed: %s)\n"), id, localtextcmd[0], sizeu1(nparam));
return;
}
localtextcmd[0]++;
localtextcmd[localtextcmd[0]] = (UINT8)id;
if (param && nparam)
{
M_Memcpy(&localtextcmd[localtextcmd[0]+1], param, nparam);
localtextcmd[0] = (UINT8)(localtextcmd[0] + (UINT8)nparam);
}
}
// splitscreen player
void SendNetXCmd2(netxcmd_t id, const void *param, size_t nparam)
{
if (localtextcmd2[0]+2+nparam > MAXTEXTCMD)
{
I_Error("No more place in the buffer for netcmd %d\n",id);
return;
}
localtextcmd2[0]++;
localtextcmd2[localtextcmd2[0]] = (UINT8)id;
if (param && nparam)
{
M_Memcpy(&localtextcmd2[localtextcmd2[0]+1], param, nparam);
localtextcmd2[0] = (UINT8)(localtextcmd2[0] + (UINT8)nparam);
}
}
UINT8 GetFreeXCmdSize(void)
{
// -1 for the size and another -1 for the ID.
return (UINT8)(localtextcmd[0] - 2);
}
// Frees all textcmd memory for the specified tic
void D_FreeTextcmd(tic_t tic)
{
textcmdtic_t **tctprev = &textcmds[tic & (TEXTCMD_HASH_SIZE - 1)];
textcmdtic_t *textcmdtic = *tctprev;
while (textcmdtic && textcmdtic->tic != tic)
{
tctprev = &textcmdtic->next;
textcmdtic = textcmdtic->next;
}
if (textcmdtic)
{
// Remove this tic from the list.
*tctprev = textcmdtic->next;
// Free all players.
for (INT32 i = 0; i < TEXTCMD_HASH_SIZE; i++)
{
textcmdplayer_t *textcmdplayer = textcmdtic->playercmds[i];
while (textcmdplayer)
{
textcmdplayer_t *tcpnext = textcmdplayer->next;
Z_Free(textcmdplayer);
textcmdplayer = tcpnext;
}
}
// Free this tic's own memory.
Z_Free(textcmdtic);
}
}
// Gets the buffer for the specified ticcmd, or NULL if there isn't one
UINT8* D_GetExistingTextcmd(tic_t tic, INT32 playernum)
{
textcmdtic_t *textcmdtic = textcmds[tic & (TEXTCMD_HASH_SIZE - 1)];
while (textcmdtic && textcmdtic->tic != tic) textcmdtic = textcmdtic->next;
// Do we have an entry for the tic? If so, look for player.
if (textcmdtic)
{
textcmdplayer_t *textcmdplayer = textcmdtic->playercmds[playernum & (TEXTCMD_HASH_SIZE - 1)];
while (textcmdplayer && textcmdplayer->playernum != playernum) textcmdplayer = textcmdplayer->next;
if (textcmdplayer) return textcmdplayer->cmd;
}
return NULL;
}
// Gets the buffer for the specified ticcmd, creating one if necessary
UINT8* D_GetTextcmd(tic_t tic, INT32 playernum)
{
textcmdtic_t *textcmdtic = textcmds[tic & (TEXTCMD_HASH_SIZE - 1)];
textcmdtic_t **tctprev = &textcmds[tic & (TEXTCMD_HASH_SIZE - 1)];
textcmdplayer_t *textcmdplayer, **tcpprev;
// Look for the tic.
while (textcmdtic && textcmdtic->tic != tic)
{
tctprev = &textcmdtic->next;
textcmdtic = textcmdtic->next;
}
// If we don't have an entry for the tic, make it.
if (!textcmdtic)
{
textcmdtic = *tctprev = Z_Calloc(sizeof (textcmdtic_t), PU_STATIC, NULL);
textcmdtic->tic = tic;
}
tcpprev = &textcmdtic->playercmds[playernum & (TEXTCMD_HASH_SIZE - 1)];
textcmdplayer = *tcpprev;
// Look for the player.
while (textcmdplayer && textcmdplayer->playernum != playernum)
{
tcpprev = &textcmdplayer->next;
textcmdplayer = textcmdplayer->next;
}
// If we don't have an entry for the player, make it.
if (!textcmdplayer)
{
textcmdplayer = *tcpprev = Z_Calloc(sizeof (textcmdplayer_t), PU_STATIC, NULL);
textcmdplayer->playernum = playernum;
}
return textcmdplayer->cmd;
}
void ExtraDataTicker(void)
{
for (INT32 i = 0; i < MAXPLAYERS; i++)
if (playeringame[i] || i == 0)
{
UINT8 *bufferstart = D_GetExistingTextcmd(gametic, i);
if (bufferstart)
{
UINT8 *curpos = bufferstart;
UINT8 *bufferend = &curpos[curpos[0]+1];
curpos++;
while (curpos < bufferend)
{
if (*curpos < MAXNETXCMD && listnetxcmd[*curpos])
{
const UINT8 id = *curpos;
curpos++;
DEBFILE(va("executing x_cmd %s ply %u ", netxcmdnames[id - 1], i));
(listnetxcmd[id])(&curpos, i);
DEBFILE("done\n");
}
else
{
if (server)
{
SendKick(i, KICK_MSG_CON_FAIL | KICK_MSG_KEEP_BODY);
DEBFILE(va("player %d kicked [gametic=%u] reason as follows:\n", i, gametic));
}
CONS_Alert(CONS_WARNING, M_GetText("Got unknown net command [%s]=%d (max %d)\n"), sizeu1(curpos - bufferstart), *curpos, bufferstart[0]);
break;
}
}
}
}
// If you are a client, you can safely forget the net commands for this tic
// If you are the server, you need to remember them until every client has been acknowledged,
// because if you need to resend a PT_SERVERTICS packet, you will need to put the commands in it
if (client)
D_FreeTextcmd(gametic);
}
// used at txtcmds received to check packetsize bound
size_t TotalTextCmdPerTic(tic_t tic)
{
size_t total = 1; // num of textcmds in the tic (ntextcmd byte)
for (INT32 i = 0; i < MAXPLAYERS; i++)
{
UINT8 *textcmd = D_GetExistingTextcmd(tic, i);
if ((!i || playeringame[i]) && textcmd)
total += 2 + textcmd[0]; // "+2" for size and playernum
}
return total;
}
void PT_TextCmd(SINT8 node, INT32 netconsole)
{
if (client)
return;
// splitscreen special
if (netbuffer->packettype == PT_TEXTCMD2)
netconsole = netnodes[node].player2;
if (netconsole < 0 || netconsole >= MAXPLAYERS)
Net_UnAcknowledgePacket(node);
else
{
size_t j;
tic_t tic = maketic;
UINT8 *textcmd;
// ignore if the textcmd has a reported size of zero
// this shouldn't be sent at all
if (!netbuffer->u.textcmd[0])
{
DEBFILE(va("GetPacket: Textcmd with size 0 detected! (node %u, player %d)\n",
node, netconsole));
Net_UnAcknowledgePacket(node);
return;
}
// ignore if the textcmd size var is actually larger than it should be
// BASEPACKETSIZE + 1 (for size) + textcmd[0] should == datalength
if (netbuffer->u.textcmd[0] > (size_t)doomcom->datalength-BASEPACKETSIZE-1)
{
DEBFILE(va("GetPacket: Bad Textcmd packet size! (expected %d, actual %s, node %u, player %d)\n",
netbuffer->u.textcmd[0], sizeu1((size_t)doomcom->datalength-BASEPACKETSIZE-1),
node, netconsole));
Net_UnAcknowledgePacket(node);
return;
}
// check if tic that we are making isn't too large else we cannot send it :(
// doomcom->numslots+1 "+1" since doomcom->numslots can change within this time and sent time
j = software_MAXPACKETLENGTH
- (netbuffer->u.textcmd[0]+2+BASESERVERTICSSIZE
+ (doomcom->numslots+1)*sizeof(ticcmd_t));
// search a tic that have enougth space in the ticcmd
while ((textcmd = D_GetExistingTextcmd(tic, netconsole)),
(TotalTextCmdPerTic(tic) > j || netbuffer->u.textcmd[0] + (textcmd ? textcmd[0] : 0) > MAXTEXTCMD)
&& tic < firstticstosend + BACKUPTICS)
tic++;
if (tic >= firstticstosend + BACKUPTICS)
{
DEBFILE(va("GetPacket: Textcmd too long (max %s, used %s, mak %d, "
"tosend %u, node %u, player %d)\n", sizeu1(j), sizeu2(TotalTextCmdPerTic(maketic)),
maketic, firstticstosend, node, netconsole));
Net_UnAcknowledgePacket(node);
return;
}
// Make sure we have a buffer
if (!textcmd) textcmd = D_GetTextcmd(tic, netconsole);
DEBFILE(va("textcmd put in tic %u at position %d (player %d) ftts %u mk %u\n",
tic, textcmd[0]+1, netconsole, firstticstosend, maketic));
M_Memcpy(&textcmd[textcmd[0]+1], netbuffer->u.textcmd+1, netbuffer->u.textcmd[0]);
textcmd[0] += (UINT8)netbuffer->u.textcmd[0];
}
}
void SV_WriteNetCommandsForTic(tic_t tic, UINT8 **buf)
{
UINT8 *numcmds;
numcmds = (*buf)++;
*numcmds = 0;
for (INT32 i = 0; i < MAXPLAYERS; i++)
{
UINT8 *cmd = D_GetExistingTextcmd(tic, i);
INT32 size = cmd ? cmd[0] : 0;
if ((!i || playeringame[i]) && size)
{
(*numcmds)++;
WRITEUINT8(*buf, i);
M_Memcpy(*buf, cmd, size + 1);
*buf += size + 1;
}
}
}
void CL_CopyNetCommandsFromServerPacket(tic_t tic, UINT8 **buf)
{
UINT8 numcmds = *(*buf)++;
for (UINT32 i = 0; i < numcmds; i++)
{
INT32 playernum = *(*buf)++; // playernum
size_t size = (*buf)[0]+1;
if (tic >= gametic) // Don't copy old net commands
M_Memcpy(D_GetTextcmd(tic, playernum), *buf, size);
*buf += size;
}
}
void CL_SendNetCommands(void)
{
// Send extra data if needed
if (localtextcmd[0])
{
netbuffer->packettype = PT_TEXTCMD;
M_Memcpy(netbuffer->u.textcmd,localtextcmd, localtextcmd[0]+1);
// All extra data have been sent
if (HSendPacket(servernode, true, 0, localtextcmd[0]+1)) // Send can fail...
localtextcmd[0] = 0;
}
// Send extra data if needed for player 2 (splitscreen)
if (localtextcmd2[0])
{
netbuffer->packettype = PT_TEXTCMD2;
M_Memcpy(netbuffer->u.textcmd, localtextcmd2, localtextcmd2[0]+1);
// All extra data have been sent
if (HSendPacket(servernode, true, 0, localtextcmd2[0]+1)) // Send can fail...
localtextcmd2[0] = 0;
}
}
void SendKick(UINT8 playernum, UINT8 msg)
{
UINT8 buf[2];
if (!(server && cv_rejointimeout.value))
msg &= ~KICK_MSG_KEEP_BODY;
buf[0] = playernum;
buf[1] = msg;
SendNetXCmd(XD_KICK, &buf, 2);
}
void SendKicksForNode(SINT8 node, UINT8 msg)
{
if (!netnodes[node].ingame)
return;
for (INT32 playernum = netnodes[node].player; playernum != -1; playernum = netnodes[node].player2)
if (playernum != -1 && playeringame[playernum])
SendKick(playernum, msg);
}

66
src/netcode/net_command.h Normal file
View file

@ -0,0 +1,66 @@
// SONIC ROBO BLAST 2
//-----------------------------------------------------------------------------
// Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2022 by Sonic Team Junior.
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
// See the 'LICENSE' file for more details.
//-----------------------------------------------------------------------------
/// \file net_command.h
/// \brief Net command handling
#ifndef __D_NET_COMMAND__
#define __D_NET_COMMAND__
#include "d_clisrv.h"
#include "../doomtype.h"
// Must be a power of two
#define TEXTCMD_HASH_SIZE 4
typedef struct textcmdplayer_s
{
INT32 playernum;
UINT8 cmd[MAXTEXTCMD];
struct textcmdplayer_s *next;
} textcmdplayer_t;
typedef struct textcmdtic_s
{
tic_t tic;
textcmdplayer_t *playercmds[TEXTCMD_HASH_SIZE];
struct textcmdtic_s *next;
} textcmdtic_t;
extern textcmdtic_t *textcmds[TEXTCMD_HASH_SIZE];
extern UINT8 localtextcmd[MAXTEXTCMD];
extern UINT8 localtextcmd2[MAXTEXTCMD]; // splitscreen
void RegisterNetXCmd(netxcmd_t id, void (*cmd_f)(UINT8 **p, INT32 playernum));
void SendNetXCmd(netxcmd_t id, const void *param, size_t nparam);
void SendNetXCmd2(netxcmd_t id, const void *param, size_t nparam); // splitsreen player
UINT8 GetFreeXCmdSize(void);
void D_FreeTextcmd(tic_t tic);
// Gets the buffer for the specified ticcmd, or NULL if there isn't one
UINT8* D_GetExistingTextcmd(tic_t tic, INT32 playernum);
// Gets the buffer for the specified ticcmd, creating one if necessary
UINT8* D_GetTextcmd(tic_t tic, INT32 playernum);
void ExtraDataTicker(void);
// used at txtcmds received to check packetsize bound
size_t TotalTextCmdPerTic(tic_t tic);
void PT_TextCmd(SINT8 node, INT32 netconsole);
void SV_WriteNetCommandsForTic(tic_t tic, UINT8 **buf);
void CL_CopyNetCommandsFromServerPacket(tic_t tic, UINT8 **buf);
void CL_SendNetCommands(void);
void SendKick(UINT8 playernum, UINT8 msg);
void SendKicksForNode(SINT8 node, UINT8 msg);
#endif

View file

@ -7,19 +7,15 @@
// terms of the GNU General Public License, version 2. // terms of the GNU General Public License, version 2.
// See the 'LICENSE' file for more details. // See the 'LICENSE' file for more details.
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
/// \file d_clisrv.h /// \file protocol.h
/// \brief high level networking stuff /// \brief Data exchanged through the network
#ifndef __D_CLISRV__ #ifndef __PROTOCOL__
#define __D_CLISRV__ #define __PROTOCOL__
#include "d_ticcmd.h"
#include "d_net.h" #include "d_net.h"
#include "d_netcmd.h" #include "../d_ticcmd.h"
#include "d_net.h" #include "../doomdef.h"
#include "tables.h"
#include "d_player.h"
#include "mserv.h"
/* /*
The 'packet version' is used to distinguish packet The 'packet version' is used to distinguish packet
@ -38,10 +34,9 @@ therein, increment this number.
// one that defines the actual packets to // one that defines the actual packets to
// be transmitted. // be transmitted.
// Networking and tick handling related.
#define BACKUPTICS 1024 #define BACKUPTICS 1024
#define CLIENTBACKUPTICS 32
#define MAXTEXTCMD 256 #define MAXTEXTCMD 256
// //
// Packet structure // Packet structure
// //
@ -77,7 +72,7 @@ typedef enum
PT_ASKLUAFILE, // Client telling the server they don't have the file PT_ASKLUAFILE, // Client telling the server they don't have the file
PT_HASLUAFILE, // Client telling the server they have the file PT_HASLUAFILE, // Client telling the server they have the file
PT_BASICKEEPALIVE,// Keep the network alive during wipes, as tics aren't advanced and NetUpdate isn't called PT_BASICKEEPALIVE, // Keep the network alive during wipes, as tics aren't advanced and NetUpdate isn't called
// Add non-PT_CANFAIL packet types here to avoid breaking MS compatibility. // Add non-PT_CANFAIL packet types here to avoid breaking MS compatibility.
@ -92,7 +87,6 @@ typedef enum
PT_TEXTCMD, // Extra text commands from the client. PT_TEXTCMD, // Extra text commands from the client.
PT_TEXTCMD2, // Splitscreen text commands. PT_TEXTCMD2, // Splitscreen text commands.
PT_CLIENTJOIN, // Client wants to join; used in start game. PT_CLIENTJOIN, // Client wants to join; used in start game.
PT_NODETIMEOUT, // Packet sent to self if the connection times out.
PT_LOGIN, // Login attempt from the client. PT_LOGIN, // Login attempt from the client.
@ -103,14 +97,6 @@ typedef enum
NUMPACKETTYPE NUMPACKETTYPE
} packettype_t; } packettype_t;
#ifdef PACKETDROP
void Command_Drop(void);
void Command_Droprate(void);
#endif
#ifdef _DEBUG
void Command_Numnodes(void);
#endif
#if defined(_MSC_VER) #if defined(_MSC_VER)
#pragma pack(1) #pragma pack(1)
#endif #endif
@ -139,13 +125,12 @@ typedef struct
#endif #endif
// Server to client packet // Server to client packet
// this packet is too large
typedef struct typedef struct
{ {
tic_t starttic; tic_t starttic;
UINT8 numtics; UINT8 numtics;
UINT8 numslots; // "Slots filled": Highest player number in use plus one. UINT8 numslots; // "Slots filled": Highest player number in use plus one.
ticcmd_t cmds[45]; // Normally [BACKUPTIC][MAXPLAYERS] but too large ticcmd_t cmds[45];
} ATTRPACK servertics_pak; } ATTRPACK servertics_pak;
typedef struct typedef struct
@ -215,6 +200,7 @@ enum {
#define MAXSERVERNAME 32 #define MAXSERVERNAME 32
#define MAXFILENEEDED 915 #define MAXFILENEEDED 915
// This packet is too large // This packet is too large
typedef struct typedef struct
{ {
@ -275,7 +261,7 @@ typedef struct
UINT8 data; // Color is first four bits, hasflag, isit and issuper have one bit each, the last is unused. UINT8 data; // Color is first four bits, hasflag, isit and issuper have one bit each, the last is unused.
UINT32 score; UINT32 score;
UINT16 timeinserver; // In seconds. UINT16 timeinserver; // In seconds.
} ATTRPACK plrinfo; } ATTRPACK plrinfo_pak;
// Shortest player information for join during intermission. // Shortest player information for join during intermission.
typedef struct typedef struct
@ -286,7 +272,7 @@ typedef struct
UINT32 pflags; UINT32 pflags;
UINT32 score; UINT32 score;
UINT8 ctfteam; UINT8 ctfteam;
} ATTRPACK plrconfig; } ATTRPACK plrconfig_pak;
typedef struct typedef struct
{ {
@ -309,25 +295,25 @@ typedef struct
UINT8 reserved; // Padding UINT8 reserved; // Padding
union union
{ {
clientcmd_pak clientpak; // 144 bytes clientcmd_pak clientpak;
client2cmd_pak client2pak; // 200 bytes client2cmd_pak client2pak;
servertics_pak serverpak; // 132495 bytes (more around 360, no?) servertics_pak serverpak;
serverconfig_pak servercfg; // 773 bytes serverconfig_pak servercfg;
UINT8 textcmd[MAXTEXTCMD+1]; // 66049 bytes (wut??? 64k??? More like 257 bytes...) UINT8 textcmd[MAXTEXTCMD+1];
filetx_pak filetxpak; // 139 bytes filetx_pak filetxpak;
fileack_pak fileack; fileack_pak fileack;
UINT8 filereceived; UINT8 filereceived;
clientconfig_pak clientcfg; // 136 bytes clientconfig_pak clientcfg;
UINT8 md5sum[16]; UINT8 md5sum[16];
serverinfo_pak serverinfo; // 1024 bytes serverinfo_pak serverinfo;
serverrefuse_pak serverrefuse; // 65025 bytes (somehow I feel like those values are garbage...) serverrefuse_pak serverrefuse;
askinfo_pak askinfo; // 61 bytes askinfo_pak askinfo;
msaskinfo_pak msaskinfo; // 22 bytes msaskinfo_pak msaskinfo;
plrinfo playerinfo[MAXPLAYERS]; // 576 bytes(?) plrinfo_pak playerinfo[MAXPLAYERS];
plrconfig playerconfig[MAXPLAYERS]; // (up to) 528 bytes(?) plrconfig_pak playerconfig[MAXPLAYERS];
INT32 filesneedednum; // 4 bytes INT32 filesneedednum;
filesneededconfig_pak filesneededcfg; // ??? bytes filesneededconfig_pak filesneededcfg;
UINT32 pingtable[MAXPLAYERS+1]; // 68 bytes UINT32 pingtable[MAXPLAYERS+1];
} u; // This is needed to pack diff packet types data together } u; // This is needed to pack diff packet types data together
} ATTRPACK doomdata_t; } ATTRPACK doomdata_t;
@ -335,26 +321,7 @@ typedef struct
#pragma pack() #pragma pack()
#endif #endif
#define MAXSERVERLIST (MAXNETNODES-1)
typedef struct
{
SINT8 node;
serverinfo_pak info;
} serverelem_t;
extern serverelem_t serverlist[MAXSERVERLIST];
extern UINT32 serverlistcount;
extern INT32 mapchangepending;
// Points inside doomcom
extern doomdata_t *netbuffer;
extern consvar_t cv_showjoinaddress;
extern consvar_t cv_playbackspeed;
#define BASEPACKETSIZE offsetof(doomdata_t, u)
#define FILETXHEADER offsetof(filetx_pak, data) #define FILETXHEADER offsetof(filetx_pak, data)
#define BASESERVERTICSSIZE offsetof(doomdata_t, u.serverpak.cmds[0])
#define KICK_MSG_GO_AWAY 1 #define KICK_MSG_GO_AWAY 1
#define KICK_MSG_CON_FAIL 2 #define KICK_MSG_CON_FAIL 2
@ -366,107 +333,4 @@ extern consvar_t cv_playbackspeed;
#define KICK_MSG_CUSTOM_BAN 8 #define KICK_MSG_CUSTOM_BAN 8
#define KICK_MSG_KEEP_BODY 0x80 #define KICK_MSG_KEEP_BODY 0x80
typedef enum
{
KR_KICK = 1, //Kicked by server
KR_PINGLIMIT = 2, //Broke Ping Limit
KR_SYNCH = 3, //Synch Failure
KR_TIMEOUT = 4, //Connection Timeout
KR_BAN = 5, //Banned by server
KR_LEAVE = 6, //Quit the game
} kickreason_t;
/* the max number of name changes in some time period */
#define MAXNAMECHANGES (5)
#define NAMECHANGERATE (60*TICRATE)
extern boolean server;
extern boolean serverrunning;
#define client (!server)
extern boolean dedicated; // For dedicated server
extern UINT16 software_MAXPACKETLENGTH;
extern boolean acceptnewnode;
extern SINT8 servernode;
void Command_Ping_f(void);
extern tic_t connectiontimeout;
extern tic_t jointimeout;
extern UINT16 pingmeasurecount;
extern UINT32 realpingtable[MAXPLAYERS];
extern UINT32 playerpingtable[MAXPLAYERS];
extern tic_t servermaxping;
extern consvar_t cv_netticbuffer, cv_allownewplayer, cv_joinnextround, cv_maxplayers, cv_joindelay, cv_rejointimeout;
extern consvar_t cv_resynchattempts, cv_blamecfail;
extern consvar_t cv_maxsend, cv_noticedownload, cv_downloadspeed;
extern consvar_t cv_dedicatedidletime;
// Used in d_net, the only dependence
tic_t ExpandTics(INT32 low, INT32 node);
void D_ClientServerInit(void);
// Initialise the other field
void RegisterNetXCmd(netxcmd_t id, void (*cmd_f)(UINT8 **p, INT32 playernum));
void SendNetXCmd(netxcmd_t id, const void *param, size_t nparam);
void SendNetXCmd2(netxcmd_t id, const void *param, size_t nparam); // splitsreen player
void SendKick(UINT8 playernum, UINT8 msg);
// Create any new ticcmds and broadcast to other players.
void NetUpdate(void);
// Maintain connections to nodes without timing them all out.
void NetKeepAlive(void);
void SV_StartSinglePlayerServer(void);
boolean SV_SpawnServer(void);
void SV_StopServer(void);
void SV_ResetServer(void);
void CL_AddSplitscreenPlayer(void);
void CL_RemoveSplitscreenPlayer(void);
void CL_Reset(void);
void CL_ClearPlayer(INT32 playernum);
void CL_QueryServerList(msg_server_t *list);
void CL_UpdateServerList(boolean internetsearch, INT32 room);
void CL_RemovePlayer(INT32 playernum, kickreason_t reason);
// Is there a game running
boolean Playing(void);
// Broadcasts special packets to other players
// to notify of game exit
void D_QuitNetGame(void);
//? How many ticks to run?
boolean TryRunTics(tic_t realtic);
// extra data for lmps
// these functions scare me. they contain magic.
/*boolean AddLmpExtradata(UINT8 **demo_p, INT32 playernum);
void ReadLmpExtraData(UINT8 **demo_pointer, INT32 playernum);*/
#ifndef NONET
// translate a playername in a player number return -1 if not found and
// print a error message in the console
SINT8 nametonum(const char *name);
#endif
extern char motd[254], server_context[8];
extern UINT8 playernode[MAXPLAYERS];
INT32 D_NumPlayers(void);
INT32 D_NumBots(void);
void D_ResetTiccmds(void);
tic_t GetLag(INT32 node);
UINT8 GetFreeXCmdSize(void);
void D_MD5PasswordPass(const UINT8 *buffer, size_t len, const char *salt, void *dest);
extern UINT8 hu_redownloadinggamestate;
extern UINT8 adminpassmd5[16];
extern boolean adminpasswordset;
extern boolean hu_stopped;
#endif #endif

View file

@ -0,0 +1,507 @@
// SONIC ROBO BLAST 2
//-----------------------------------------------------------------------------
// Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2023 by Sonic Team Junior.
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
// See the 'LICENSE' file for more details.
//-----------------------------------------------------------------------------
/// \file server_connection.c
/// \brief Server-side part of connection handling
#include "server_connection.h"
#include "i_net.h"
#include "d_clisrv.h"
#include "d_netfil.h"
#include "mserv.h"
#include "net_command.h"
#include "gamestate.h"
#include "../byteptr.h"
#include "../g_game.h"
#include "../g_state.h"
#include "../p_setup.h"
#include "../p_tick.h"
#include "../command.h"
#include "../doomstat.h"
// Minimum timeout for sending the savegame
// The actual timeout will be longer depending on the savegame length
tic_t jointimeout = (10*TICRATE);
// Incremented by cv_joindelay when a client joins, decremented each tic.
// If higher than cv_joindelay * 2 (3 joins in a short timespan), joins are temporarily disabled.
tic_t joindelay = 0;
// Minimum timeout for sending the savegame
// The actual timeout will be longer depending on the savegame length
char playeraddress[MAXPLAYERS][64];
consvar_t cv_showjoinaddress = CVAR_INIT ("showjoinaddress", "Off", CV_SAVE|CV_NETVAR, CV_OnOff, NULL);
consvar_t cv_allownewplayer = CVAR_INIT ("allowjoin", "On", CV_SAVE|CV_NETVAR|CV_ALLOWLUA, CV_OnOff, NULL);
static CV_PossibleValue_t maxplayers_cons_t[] = {{2, "MIN"}, {32, "MAX"}, {0, NULL}};
consvar_t cv_maxplayers = CVAR_INIT ("maxplayers", "8", CV_SAVE|CV_NETVAR|CV_ALLOWLUA, maxplayers_cons_t, NULL);
static CV_PossibleValue_t joindelay_cons_t[] = {{1, "MIN"}, {3600, "MAX"}, {0, "Off"}, {0, NULL}};
consvar_t cv_joindelay = CVAR_INIT ("joindelay", "10", CV_SAVE|CV_NETVAR, joindelay_cons_t, NULL);
static CV_PossibleValue_t rejointimeout_cons_t[] = {{1, "MIN"}, {60 * FRACUNIT, "MAX"}, {0, "Off"}, {0, NULL}};
consvar_t cv_rejointimeout = CVAR_INIT ("rejointimeout", "2", CV_SAVE|CV_NETVAR|CV_FLOAT, rejointimeout_cons_t, NULL);
static INT32 FindRejoinerNum(SINT8 node)
{
char addressbuffer[64];
const char *nodeaddress;
const char *strippednodeaddress;
// Make sure there is no dead dress before proceeding to the stripping
if (!I_GetNodeAddress)
return -1;
nodeaddress = I_GetNodeAddress(node);
if (!nodeaddress)
return -1;
// Strip the address of its port
strcpy(addressbuffer, nodeaddress);
strippednodeaddress = I_NetSplitAddress(addressbuffer, NULL);
// Check if any player matches the stripped address
for (INT32 i = 0; i < MAXPLAYERS; i++)
{
if (playeringame[i] && playeraddress[i][0] && playernode[i] == UINT8_MAX
&& !strcmp(playeraddress[i], strippednodeaddress))
return i;
}
return -1;
}
static UINT8
GetRefuseReason (INT32 node)
{
if (!node || FindRejoinerNum(node) != -1)
return 0;
else if (bannednode && bannednode[node])
return REFUSE_BANNED;
else if (!cv_allownewplayer.value)
return REFUSE_JOINS_DISABLED;
else if (D_NumPlayers() >= cv_maxplayers.value)
return REFUSE_SLOTS_FULL;
else
return 0;
}
static void SV_SendServerInfo(INT32 node, tic_t servertime)
{
UINT8 *p;
netbuffer->packettype = PT_SERVERINFO;
netbuffer->u.serverinfo._255 = 255;
netbuffer->u.serverinfo.packetversion = PACKETVERSION;
netbuffer->u.serverinfo.version = VERSION;
netbuffer->u.serverinfo.subversion = SUBVERSION;
strncpy(netbuffer->u.serverinfo.application, SRB2APPLICATION,
sizeof netbuffer->u.serverinfo.application);
// return back the time value so client can compute their ping
netbuffer->u.serverinfo.time = (tic_t)LONG(servertime);
netbuffer->u.serverinfo.leveltime = (tic_t)LONG(leveltime);
// Exclude bots from both counts
netbuffer->u.serverinfo.numberofplayer = (UINT8)(D_NumPlayers() - D_NumBots());
netbuffer->u.serverinfo.maxplayer = (UINT8)(cv_maxplayers.value - D_NumBots());
netbuffer->u.serverinfo.refusereason = GetRefuseReason(node);
strncpy(netbuffer->u.serverinfo.gametypename, Gametype_Names[gametype],
sizeof netbuffer->u.serverinfo.gametypename);
netbuffer->u.serverinfo.modifiedgame = (UINT8)modifiedgame;
netbuffer->u.serverinfo.cheatsenabled = CV_CheatsEnabled();
netbuffer->u.serverinfo.flags = (dedicated ? SV_DEDICATED : 0);
strncpy(netbuffer->u.serverinfo.servername, cv_servername.string,
MAXSERVERNAME);
strncpy(netbuffer->u.serverinfo.mapname, G_BuildMapName(gamemap), 7);
M_Memcpy(netbuffer->u.serverinfo.mapmd5, mapmd5, 16);
memset(netbuffer->u.serverinfo.maptitle, 0, sizeof netbuffer->u.serverinfo.maptitle);
if (mapheaderinfo[gamemap-1] && *mapheaderinfo[gamemap-1]->lvlttl)
{
char *read = mapheaderinfo[gamemap-1]->lvlttl, *writ = netbuffer->u.serverinfo.maptitle;
while (writ < (netbuffer->u.serverinfo.maptitle+32) && *read != '\0')
{
if (!(*read & 0x80))
{
*writ = toupper(*read);
writ++;
}
read++;
}
*writ = '\0';
//strncpy(netbuffer->u.serverinfo.maptitle, (char *)mapheaderinfo[gamemap-1]->lvlttl, 33);
}
else
strncpy(netbuffer->u.serverinfo.maptitle, "UNKNOWN", 32);
if (mapheaderinfo[gamemap-1] && !(mapheaderinfo[gamemap-1]->levelflags & LF_NOZONE))
netbuffer->u.serverinfo.iszone = 1;
else
netbuffer->u.serverinfo.iszone = 0;
if (mapheaderinfo[gamemap-1])
netbuffer->u.serverinfo.actnum = mapheaderinfo[gamemap-1]->actnum;
p = PutFileNeeded(0);
HSendPacket(node, false, 0, p - ((UINT8 *)&netbuffer->u));
}
static void SV_SendPlayerInfo(INT32 node)
{
netbuffer->packettype = PT_PLAYERINFO;
for (UINT8 i = 0; i < MAXPLAYERS; i++)
{
if (!playeringame[i])
{
netbuffer->u.playerinfo[i].num = 255; // This slot is empty.
continue;
}
netbuffer->u.playerinfo[i].num = i;
strncpy(netbuffer->u.playerinfo[i].name, (const char *)&player_names[i], MAXPLAYERNAME+1);
netbuffer->u.playerinfo[i].name[MAXPLAYERNAME] = '\0';
//fetch IP address
//No, don't do that, you fuckface.
memset(netbuffer->u.playerinfo[i].address, 0, 4);
if (G_GametypeHasTeams())
{
if (!players[i].ctfteam)
netbuffer->u.playerinfo[i].team = 255;
else
netbuffer->u.playerinfo[i].team = (UINT8)players[i].ctfteam;
}
else
{
if (players[i].spectator)
netbuffer->u.playerinfo[i].team = 255;
else
netbuffer->u.playerinfo[i].team = 0;
}
netbuffer->u.playerinfo[i].score = LONG(players[i].score);
netbuffer->u.playerinfo[i].timeinserver = SHORT((UINT16)(players[i].jointime / TICRATE));
netbuffer->u.playerinfo[i].skin = (UINT8)(players[i].skin
#ifdef DEVELOP // it's safe to do this only because PLAYERINFO isn't read by the game itself
% 3
#endif
);
// Extra data
netbuffer->u.playerinfo[i].data = 0; //players[i].skincolor;
if (players[i].pflags & PF_TAGIT)
netbuffer->u.playerinfo[i].data |= 0x20;
if (players[i].gotflag)
netbuffer->u.playerinfo[i].data |= 0x40;
if (players[i].powers[pw_super])
netbuffer->u.playerinfo[i].data |= 0x80;
}
HSendPacket(node, false, 0, sizeof(plrinfo_pak) * MAXPLAYERS);
}
/** Sends a PT_SERVERCFG packet
*
* \param node The destination
* \return True if the packet was successfully sent
*
*/
static boolean SV_SendServerConfig(INT32 node)
{
boolean waspacketsent;
netbuffer->packettype = PT_SERVERCFG;
netbuffer->u.servercfg.serverplayer = (UINT8)serverplayer;
netbuffer->u.servercfg.totalslotnum = (UINT8)(doomcom->numslots);
netbuffer->u.servercfg.gametic = (tic_t)LONG(gametic);
netbuffer->u.servercfg.clientnode = (UINT8)node;
netbuffer->u.servercfg.gamestate = (UINT8)gamestate;
netbuffer->u.servercfg.gametype = (UINT8)gametype;
netbuffer->u.servercfg.modifiedgame = (UINT8)modifiedgame;
netbuffer->u.servercfg.usedCheats = (UINT8)usedCheats;
memcpy(netbuffer->u.servercfg.server_context, server_context, 8);
{
const size_t len = sizeof (serverconfig_pak);
#ifdef DEBUGFILE
if (debugfile)
{
fprintf(debugfile, "ServerConfig Packet about to be sent, size of packet:%s to node:%d\n",
sizeu1(len), node);
}
#endif
waspacketsent = HSendPacket(node, true, 0, len);
}
#ifdef DEBUGFILE
if (debugfile)
{
if (waspacketsent)
{
fprintf(debugfile, "ServerConfig Packet was sent\n");
}
else
{
fprintf(debugfile, "ServerConfig Packet could not be sent right now\n");
}
}
#endif
return waspacketsent;
}
// Adds a node to the game (player will follow at map change or at savegame....)
static inline void SV_AddNode(INT32 node)
{
netnodes[node].tic = gametic;
netnodes[node].supposedtic = gametic;
// little hack because the server connects to itself and puts
// nodeingame when connected not here
if (node)
netnodes[node].ingame = true;
}
static void SV_AddPlayer(SINT8 node, const char *name)
{
INT32 n;
UINT8 buf[2 + MAXPLAYERNAME];
UINT8 *p;
INT32 newplayernum;
newplayernum = FindRejoinerNum(node);
if (newplayernum == -1)
{
// search for a free playernum
// we can't use playeringame since it is not updated here
for (newplayernum = dedicated ? 1 : 0; newplayernum < MAXPLAYERS; newplayernum++)
{
if (playeringame[newplayernum])
continue;
for (n = 0; n < MAXNETNODES; n++)
if (netnodes[n].player == newplayernum || netnodes[n].player2 == newplayernum)
break;
if (n == MAXNETNODES)
break;
}
}
// should never happen since we check the playernum
// before accepting the join
I_Assert(newplayernum < MAXPLAYERS);
playernode[newplayernum] = (UINT8)node;
p = buf + 2;
buf[0] = (UINT8)node;
buf[1] = newplayernum;
if (netnodes[node].numplayers < 1)
{
netnodes[node].player = newplayernum;
}
else
{
netnodes[node].player2 = newplayernum;
buf[1] |= 0x80;
}
WRITESTRINGN(p, name, MAXPLAYERNAME);
netnodes[node].numplayers++;
SendNetXCmd(XD_ADDPLAYER, &buf, p - buf);
DEBFILE(va("Server added player %d node %d\n", newplayernum, node));
}
static void SV_SendRefuse(INT32 node, const char *reason)
{
strcpy(netbuffer->u.serverrefuse.reason, reason);
netbuffer->packettype = PT_SERVERREFUSE;
HSendPacket(node, true, 0, strlen(netbuffer->u.serverrefuse.reason) + 1);
Net_CloseConnection(node);
}
static const char *
GetRefuseMessage (SINT8 node, INT32 rejoinernum)
{
clientconfig_pak *cc = &netbuffer->u.clientcfg;
boolean rejoining = (rejoinernum != -1);
if (!node)/* server connecting to itself */
return NULL;
if (
cc->modversion != MODVERSION ||
strncmp(cc->application, SRB2APPLICATION,
sizeof cc->application)
){
return/* this is probably client's fault */
"Incompatible.";
}
else if (bannednode && bannednode[node])
{
return
"You have been banned\n"
"from the server.";
}
else if (cc->localplayers != 1)
{
return
"Wrong player count.";
}
if (!rejoining)
{
if (!cv_allownewplayer.value)
{
return
"The server is not accepting\n"
"joins for the moment.";
}
else if (D_NumPlayers() >= cv_maxplayers.value)
{
return va(
"Maximum players reached: %d",
cv_maxplayers.value);
}
}
if (luafiletransfers)
{
return
"The serveris broadcasting a file\n"
"requested by a Lua script.\n"
"Please wait a bit and then\n"
"try rejoining.";
}
if (netgame)
{
const tic_t th = 2 * cv_joindelay.value * TICRATE;
if (joindelay > th)
{
return va(
"Too many people are connecting.\n"
"Please wait %d seconds and then\n"
"try rejoining.",
(joindelay - th) / TICRATE);
}
}
return NULL;
}
/** Called when a PT_CLIENTJOIN packet is received
*
* \param node The packet sender
*
*/
void PT_ClientJoin(SINT8 node)
{
char names[MAXSPLITSCREENPLAYERS][MAXPLAYERNAME + 1];
INT32 numplayers = netbuffer->u.clientcfg.localplayers;
INT32 rejoinernum;
// Ignore duplicate packets
if (client || netnodes[node].ingame)
return;
rejoinernum = FindRejoinerNum(node);
const char *refuse = GetRefuseMessage(node, rejoinernum);
if (refuse)
{
SV_SendRefuse(node, refuse);
return;
}
for (INT32 i = 0; i < numplayers; i++)
{
strlcpy(names[i], netbuffer->u.clientcfg.names[i], MAXPLAYERNAME + 1);
if (!EnsurePlayerNameIsGood(names[i], rejoinernum))
{
SV_SendRefuse(node, "Bad player name");
return;
}
}
SV_AddNode(node);
if (!SV_SendServerConfig(node))
{
/// \note Shouldn't SV_SendRefuse be called before ResetNode?
ResetNode(node);
SV_SendRefuse(node, M_GetText("Server couldn't send info, please try again"));
/// \todo fix this !!!
return;
}
DEBFILE("new node joined\n");
if (gamestate == GS_LEVEL || gamestate == GS_INTERMISSION)
{
SV_SendSaveGame(node, false); // send a complete game state
DEBFILE("send savegame\n");
}
// Splitscreen can allow 2 players in one node
for (INT32 i = 0; i < numplayers; i++)
SV_AddPlayer(node, names[i]);
joindelay += cv_joindelay.value * TICRATE;
}
void PT_AskInfoViaMS(SINT8 node)
{
Net_CloseConnection(node);
}
void PT_TellFilesNeeded(SINT8 node)
{
if (server && serverrunning)
{
UINT8 *p;
INT32 firstfile = netbuffer->u.filesneedednum;
netbuffer->packettype = PT_MOREFILESNEEDED;
netbuffer->u.filesneededcfg.first = firstfile;
netbuffer->u.filesneededcfg.more = 0;
p = PutFileNeeded(firstfile);
HSendPacket(node, false, 0, p - ((UINT8 *)&netbuffer->u));
}
else // Shouldn't get this if you aren't the server...?
Net_CloseConnection(node);
}
void PT_AskInfo(SINT8 node)
{
if (server && serverrunning)
{
SV_SendServerInfo(node, (tic_t)LONG(netbuffer->u.askinfo.time));
SV_SendPlayerInfo(node); // Send extra info
}
Net_CloseConnection(node);
}

View file

@ -0,0 +1,30 @@
// SONIC ROBO BLAST 2
//-----------------------------------------------------------------------------
// Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2023 by Sonic Team Junior.
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
// See the 'LICENSE' file for more details.
//-----------------------------------------------------------------------------
/// \file server_connection.h
/// \brief Server-side part of connection handling
#ifndef __D_SERVER_CONNECTION__
#define __D_SERVER_CONNECTION__
#include "../command.h"
#include "../doomdef.h"
#include "../doomtype.h"
void PT_ClientJoin(SINT8 node);
void PT_AskInfoViaMS(SINT8 node);
void PT_TellFilesNeeded(SINT8 node);
void PT_AskInfo(SINT8 node);
extern tic_t jointimeout;
extern tic_t joindelay;
extern char playeraddress[MAXPLAYERS][64];
extern consvar_t cv_showjoinaddress, cv_allownewplayer, cv_maxplayers, cv_joindelay, cv_rejointimeout;
#endif

471
src/netcode/tic_command.c Normal file
View file

@ -0,0 +1,471 @@
// SONIC ROBO BLAST 2
//-----------------------------------------------------------------------------
// Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2023 by Sonic Team Junior.
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
// See the 'LICENSE' file for more details.
//-----------------------------------------------------------------------------
/// \file tic_command.c
/// \brief Tic command handling
#include "tic_command.h"
#include "d_clisrv.h"
#include "net_command.h"
#include "client_connection.h"
#include "gamestate.h"
#include "i_net.h"
#include "../d_main.h"
#include "../g_game.h"
#include "../i_system.h"
#include "../i_time.h"
#include "../byteptr.h"
#include "../doomstat.h"
#include "../doomtype.h"
tic_t firstticstosend; // Smallest netnode.tic
tic_t tictoclear = 0; // Optimize D_ClearTiccmd
ticcmd_t localcmds;
ticcmd_t localcmds2;
boolean cl_packetmissed;
ticcmd_t netcmds[BACKUPTICS][MAXPLAYERS];
static inline void *G_DcpyTiccmd(void* dest, const ticcmd_t* src, const size_t n)
{
const size_t d = n / sizeof(ticcmd_t);
const size_t r = n % sizeof(ticcmd_t);
UINT8 *ret = dest;
if (r)
M_Memcpy(dest, src, n);
else if (d)
G_MoveTiccmd(dest, src, d);
return ret+n;
}
static inline void *G_ScpyTiccmd(ticcmd_t* dest, void* src, const size_t n)
{
const size_t d = n / sizeof(ticcmd_t);
const size_t r = n % sizeof(ticcmd_t);
UINT8 *ret = src;
if (r)
M_Memcpy(dest, src, n);
else if (d)
G_MoveTiccmd(dest, src, d);
return ret+n;
}
/** Guesses the full value of a tic from its lowest byte, for a specific node
*
* \param low The lowest byte of the tic value
* \param node The node to deduce the tic for
* \return The full tic value
*
*/
tic_t ExpandTics(INT32 low, INT32 node)
{
INT32 delta;
delta = low - (netnodes[node].tic & UINT8_MAX);
if (delta >= -64 && delta <= 64)
return (netnodes[node].tic & ~UINT8_MAX) + low;
else if (delta > 64)
return (netnodes[node].tic & ~UINT8_MAX) - 256 + low;
else //if (delta < -64)
return (netnodes[node].tic & ~UINT8_MAX) + 256 + low;
}
void D_Clearticcmd(tic_t tic)
{
D_FreeTextcmd(tic);
for (INT32 i = 0; i < MAXPLAYERS; i++)
netcmds[tic%BACKUPTICS][i].angleturn = 0;
DEBFILE(va("clear tic %5u (%2u)\n", tic, tic%BACKUPTICS));
}
void D_ResetTiccmds(void)
{
memset(&localcmds, 0, sizeof(ticcmd_t));
memset(&localcmds2, 0, sizeof(ticcmd_t));
// Reset the net command list
for (INT32 i = 0; i < TEXTCMD_HASH_SIZE; i++)
while (textcmds[i])
D_Clearticcmd(textcmds[i]->tic);
}
// Check ticcmd for "speed hacks"
static void CheckTiccmdHacks(INT32 playernum, tic_t tic)
{
ticcmd_t *cmd = &netcmds[tic%BACKUPTICS][playernum];
if (cmd->forwardmove > MAXPLMOVE || cmd->forwardmove < -MAXPLMOVE
|| cmd->sidemove > MAXPLMOVE || cmd->sidemove < -MAXPLMOVE)
{
CONS_Alert(CONS_WARNING, M_GetText("Illegal movement value received from node %d\n"), playernum);
SendKick(playernum, KICK_MSG_CON_FAIL);
}
}
// Check player consistancy during the level
static void CheckConsistancy(SINT8 nodenum, tic_t tic)
{
netnode_t *node = &netnodes[nodenum];
INT16 neededconsistancy = consistancy[tic%BACKUPTICS];
INT16 clientconsistancy = SHORT(netbuffer->u.clientpak.consistancy);
if (tic > gametic || tic + BACKUPTICS - 1 <= gametic || gamestate != GS_LEVEL
|| neededconsistancy == clientconsistancy || SV_ResendingSavegameToAnyone()
|| node->resendingsavegame || node->savegameresendcooldown > I_GetTime())
return;
if (cv_resynchattempts.value)
{
// Tell the client we are about to resend them the gamestate
netbuffer->packettype = PT_WILLRESENDGAMESTATE;
HSendPacket(nodenum, true, 0, 0);
node->resendingsavegame = true;
if (cv_blamecfail.value)
CONS_Printf(M_GetText("Synch failure for player %d (%s); expected %hd, got %hd\n"),
node->player+1, player_names[node->player],
neededconsistancy, clientconsistancy);
DEBFILE(va("Restoring player %d (synch failure) [%update] %d!=%d\n",
node->player, tic, neededconsistancy, clientconsistancy));
}
else
{
SendKick(node->player, KICK_MSG_CON_FAIL | KICK_MSG_KEEP_BODY);
DEBFILE(va("player %d kicked (synch failure) [%u] %d!=%d\n",
node->player, tic, neededconsistancy, clientconsistancy));
}
}
void PT_ClientCmd(SINT8 nodenum, INT32 netconsole)
{
netnode_t *node = &netnodes[nodenum];
tic_t realend, realstart;
if (client)
return;
// To save bytes, only the low byte of tic numbers are sent
// Use ExpandTics to figure out what the rest of the bytes are
realstart = ExpandTics(netbuffer->u.clientpak.client_tic, nodenum);
realend = ExpandTics(netbuffer->u.clientpak.resendfrom, nodenum);
if (netbuffer->packettype == PT_CLIENTMIS || netbuffer->packettype == PT_CLIENT2MIS
|| netbuffer->packettype == PT_NODEKEEPALIVEMIS
|| node->supposedtic < realend)
{
node->supposedtic = realend;
}
// Discard out of order packet
if (node->tic > realend)
{
DEBFILE(va("out of order ticcmd discarded nettics = %u\n", node->tic));
return;
}
// Update the nettics
node->tic = realend;
// This should probably still timeout though, as the node should always have a player 1 number
if (netconsole == -1)
return;
// As long as clients send valid ticcmds, the server can keep running, so reset the timeout
/// \todo Use a separate cvar for that kind of timeout?
node->freezetimeout = I_GetTime() + connectiontimeout;
// Don't do anything for packets of type NODEKEEPALIVE?
// Sryder 2018/07/01: Update the freezetimeout still!
if (netbuffer->packettype == PT_NODEKEEPALIVE
|| netbuffer->packettype == PT_NODEKEEPALIVEMIS)
return;
// If we've alredy received a ticcmd for this tic, just submit it for the next one.
tic_t faketic = maketic;
if ((!!(netcmds[maketic % BACKUPTICS][netconsole].angleturn & TICCMD_RECEIVED))
&& (maketic - firstticstosend < BACKUPTICS - 1))
faketic++;
// Copy ticcmd
G_MoveTiccmd(&netcmds[faketic%BACKUPTICS][netconsole], &netbuffer->u.clientpak.cmd, 1);
// Splitscreen cmd
if ((netbuffer->packettype == PT_CLIENT2CMD || netbuffer->packettype == PT_CLIENT2MIS)
&& node->player2 >= 0)
G_MoveTiccmd(&netcmds[faketic%BACKUPTICS][(UINT8)node->player2],
&netbuffer->u.client2pak.cmd2, 1);
CheckTiccmdHacks(netconsole, faketic);
CheckConsistancy(nodenum, realstart);
}
void PT_ServerTics(SINT8 node, INT32 netconsole)
{
tic_t realend, realstart;
servertics_pak *packet = &netbuffer->u.serverpak;
if (!netnodes[node].ingame)
{
// Do not remove my own server (we have just get a out of order packet)
if (node != servernode)
{
DEBFILE(va("unknown packet received (%d) from unknown host\n",netbuffer->packettype));
Net_CloseConnection(node);
}
return;
}
// Only accept PT_SERVERTICS from the server.
if (node != servernode)
{
CONS_Alert(CONS_WARNING, M_GetText("%s received from non-host %d\n"), "PT_SERVERTICS", node);
if (server)
SendKick(netconsole, KICK_MSG_CON_FAIL | KICK_MSG_KEEP_BODY);
return;
}
realstart = packet->starttic;
realend = realstart + packet->numtics;
realend = min(realend, gametic + CLIENTBACKUPTICS);
cl_packetmissed = realstart > neededtic;
if (realstart <= neededtic && realend > neededtic)
{
UINT8 *pak = (UINT8 *)&packet->cmds;
UINT8 *txtpak = (UINT8 *)&packet->cmds[packet->numslots * packet->numtics];
for (tic_t i = realstart; i < realend; i++)
{
// clear first
D_Clearticcmd(i);
// copy the tics
pak = G_ScpyTiccmd(netcmds[i%BACKUPTICS], pak,
packet->numslots*sizeof (ticcmd_t));
CL_CopyNetCommandsFromServerPacket(i, &txtpak);
}
neededtic = realend;
}
else
{
DEBFILE(va("frame not in bound: %u\n", neededtic));
}
}
// send the client packet to the server
void CL_SendClientCmd(void)
{
size_t packetsize = 0;
boolean mis = false;
netbuffer->packettype = PT_CLIENTCMD;
if (cl_packetmissed)
{
netbuffer->packettype = PT_CLIENTMIS;
mis = true;
}
netbuffer->u.clientpak.resendfrom = (UINT8)(neededtic & UINT8_MAX);
netbuffer->u.clientpak.client_tic = (UINT8)(gametic & UINT8_MAX);
if (gamestate == GS_WAITINGPLAYERS)
{
// Send PT_NODEKEEPALIVE packet
netbuffer->packettype = (mis ? PT_NODEKEEPALIVEMIS : PT_NODEKEEPALIVE);
packetsize = sizeof (clientcmd_pak) - sizeof (ticcmd_t) - sizeof (INT16);
HSendPacket(servernode, false, 0, packetsize);
}
else if (gamestate != GS_NULL && (addedtogame || dedicated))
{
packetsize = sizeof (clientcmd_pak);
G_MoveTiccmd(&netbuffer->u.clientpak.cmd, &localcmds, 1);
netbuffer->u.clientpak.consistancy = SHORT(consistancy[gametic%BACKUPTICS]);
// Send a special packet with 2 cmd for splitscreen
if (splitscreen || botingame)
{
netbuffer->packettype = (mis ? PT_CLIENT2MIS : PT_CLIENT2CMD);
packetsize = sizeof (client2cmd_pak);
G_MoveTiccmd(&netbuffer->u.client2pak.cmd2, &localcmds2, 1);
}
HSendPacket(servernode, false, 0, packetsize);
}
if (cl_mode == CL_CONNECTED || dedicated)
CL_SendNetCommands();
}
// PT_SERVERTICS packets can grow too large for a single UDP packet,
// So this checks how many tics worth of data can be sent in one packet.
// The rest can be sent later, usually the next tic.
static tic_t SV_CalculateNumTicsForPacket(SINT8 nodenum, tic_t firsttic, tic_t lasttic)
{
size_t size = BASESERVERTICSSIZE;
for (tic_t tic = firsttic; tic < lasttic; tic++)
{
size += sizeof (ticcmd_t) * doomcom->numslots;
size += TotalTextCmdPerTic(tic);
if (size > software_MAXPACKETLENGTH)
{
DEBFILE(va("packet too large (%s) at tic %d (should be from %d to %d)\n",
sizeu1(size), tic, firsttic, lasttic));
lasttic = tic;
// Too bad: too many players have sent extra data
// and there is too much data for a single tic.
// To avoid that, keep the data for the next tic (see PT_TEXTCMD).
if (lasttic == firsttic)
{
if (size > MAXPACKETLENGTH)
I_Error("Too many players: can't send %s data for %d players to node %d\n"
"Well sorry nobody is perfect....\n",
sizeu1(size), doomcom->numslots, nodenum);
else
{
lasttic++; // send it anyway!
DEBFILE("sending it anyway\n");
}
}
break;
}
}
return lasttic - firsttic;
}
// Sends the server packet
// Sends tic/net commands from firstticstosend to maketic-1
void SV_SendTics(void)
{
tic_t realfirsttic, lasttictosend;
// Send to all clients except yourself
// For each node, create a packet with x tics and send it
// x is computed using node.supposedtic, max packet size and maketic
for (INT32 n = 1; n < MAXNETNODES; n++)
if (netnodes[n].ingame)
{
netnode_t *node = &netnodes[n];
// assert node->supposedtic>=node->tic
realfirsttic = node->supposedtic;
lasttictosend = min(maketic, node->tic + CLIENTBACKUPTICS);
if (realfirsttic >= lasttictosend)
{
// Well, we have sent all the tics, so we will use extra bandwidth
// to resend packets that are supposed lost.
// This is necessary since lost packet detection
// works when we receive a packet with firsttic > neededtic (PT_SERVERTICS)
DEBFILE(va("Nothing to send node %u mak=%u sup=%u net=%u \n",
n, maketic, node->supposedtic, node->tic));
realfirsttic = node->tic;
if (realfirsttic >= lasttictosend || (I_GetTime() + n)&3)
// All tics are Ok
continue;
DEBFILE(va("Sent %d anyway\n", realfirsttic));
}
realfirsttic = max(realfirsttic, firstticstosend);
lasttictosend = realfirsttic + SV_CalculateNumTicsForPacket(n, realfirsttic, lasttictosend);
// Prepare the packet header
netbuffer->packettype = PT_SERVERTICS;
netbuffer->u.serverpak.starttic = realfirsttic;
netbuffer->u.serverpak.numtics = (UINT8)(lasttictosend - realfirsttic);
netbuffer->u.serverpak.numslots = (UINT8)SHORT(doomcom->numslots);
// Fill and send the packet
UINT8 *bufpos = (UINT8 *)&netbuffer->u.serverpak.cmds;
for (tic_t i = realfirsttic; i < lasttictosend; i++)
bufpos = G_DcpyTiccmd(bufpos, netcmds[i%BACKUPTICS], doomcom->numslots * sizeof (ticcmd_t));
for (tic_t i = realfirsttic; i < lasttictosend; i++)
SV_WriteNetCommandsForTic(i, &bufpos);
size_t packsize = bufpos - (UINT8 *)&(netbuffer->u);
HSendPacket(n, false, 0, packsize);
// When tics are too large, only one tic is sent so don't go backwards!
if (lasttictosend-doomcom->extratics > realfirsttic)
node->supposedtic = lasttictosend-doomcom->extratics;
else
node->supposedtic = lasttictosend;
node->supposedtic = max(node->supposedtic, node->tic);
}
// node 0 is me!
netnodes[0].supposedtic = maketic;
}
void Local_Maketic(INT32 realtics)
{
I_OsPolling(); // I_Getevent
D_ProcessEvents(); // menu responder, cons responder,
// game responder calls HU_Responder, AM_Responder,
// and G_MapEventsToControls
if (!dedicated)
rendergametic = gametic;
// translate inputs (keyboard/mouse/joystick) into game controls
G_BuildTiccmd(&localcmds, realtics, 1);
if (splitscreen || botingame)
G_BuildTiccmd(&localcmds2, realtics, 2);
localcmds.angleturn |= TICCMD_RECEIVED;
localcmds2.angleturn |= TICCMD_RECEIVED;
}
// create missed tic
void SV_Maketic(void)
{
for (INT32 i = 0; i < MAXPLAYERS; i++)
{
if (!playeringame[i])
continue;
// We didn't receive this tic
if ((netcmds[maketic % BACKUPTICS][i].angleturn & TICCMD_RECEIVED) == 0)
{
ticcmd_t * ticcmd = &netcmds[(maketic ) % BACKUPTICS][i];
ticcmd_t *prevticcmd = &netcmds[(maketic - 1) % BACKUPTICS][i];
if (players[i].quittime)
{
// Copy the angle/aiming from the previous tic
// and empty the other inputs
memset(ticcmd, 0, sizeof(netcmds[0][0]));
ticcmd->angleturn = prevticcmd->angleturn | TICCMD_RECEIVED;
ticcmd->aiming = prevticcmd->aiming;
}
else
{
DEBFILE(va("MISS tic%4d for player %d\n", maketic, i));
// Copy the input from the previous tic
*ticcmd = *prevticcmd;
ticcmd->angleturn &= ~TICCMD_RECEIVED;
}
}
}
// All tics have been processed, make the next
maketic++;
}

44
src/netcode/tic_command.h Normal file
View file

@ -0,0 +1,44 @@
// SONIC ROBO BLAST 2
//-----------------------------------------------------------------------------
// Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2023 by Sonic Team Junior.
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
// See the 'LICENSE' file for more details.
//-----------------------------------------------------------------------------
/// \file tic_command.h
/// \brief Tic command handling
#ifndef __D_TIC_COMMAND__
#define __D_TIC_COMMAND__
#include "d_clisrv.h"
#include "../d_ticcmd.h"
#include "../doomdef.h"
#include "../doomtype.h"
extern tic_t firstticstosend; // min of the nettics
extern tic_t tictoclear; // optimize d_clearticcmd
extern ticcmd_t localcmds;
extern ticcmd_t localcmds2;
extern boolean cl_packetmissed;
extern ticcmd_t netcmds[BACKUPTICS][MAXPLAYERS];
tic_t ExpandTics(INT32 low, INT32 node);
void D_Clearticcmd(tic_t tic);
void D_ResetTiccmds(void);
void PT_ClientCmd(SINT8 nodenum, INT32 netconsole);
void PT_ServerTics(SINT8 node, INT32 netconsole);
// send the client packet to the server
void CL_SendClientCmd(void);
void SV_SendTics(void);
void Local_Maketic(INT32 realtics);
void SV_Maketic(void);
#endif

View file

@ -17,7 +17,7 @@
#include "r_main.h" #include "r_main.h"
#include "s_sound.h" #include "s_sound.h"
#include "z_zone.h" #include "z_zone.h"
#include "d_netcmd.h" #include "netcode/d_netcmd.h"
// ========================================================================== // ==========================================================================
// CEILINGS // CEILINGS

View file

@ -28,6 +28,7 @@
#include "m_misc.h" #include "m_misc.h"
#include "v_video.h" // video flags for CEchos #include "v_video.h" // video flags for CEchos
#include "f_finale.h" #include "f_finale.h"
#include "netcode/net_command.h"
// CTF player names // CTF player names
#define CTFTEAMCODE(pl) pl->ctfteam ? (pl->ctfteam == 1 ? "\x85" : "\x84") : "" #define CTFTEAMCODE(pl) pl->ctfteam ? (pl->ctfteam == 1 ? "\x85" : "\x84") : ""

View file

@ -17,7 +17,7 @@
#include "r_state.h" #include "r_state.h"
#include "z_zone.h" #include "z_zone.h"
#include "m_random.h" #include "m_random.h"
#include "d_netcmd.h" #include "netcode/d_netcmd.h"
/** Removes any active lighting effects in a sector. /** Removes any active lighting effects in a sector.
* *

View file

@ -3730,7 +3730,9 @@ void P_SlideMove(mobj_t *mo)
boolean papercol = false; boolean papercol = false;
vertex_t v1, v2; // fake vertexes vertex_t v1, v2; // fake vertexes
line_t junk; // fake linedef static line_t junk; // fake linedef
memset(&junk, 0x00, sizeof(junk));
if (tmhitthing && mo->z + mo->height > tmhitthing->z && mo->z < tmhitthing->z + tmhitthing->height) if (tmhitthing && mo->z + mo->height > tmhitthing->z && mo->z < tmhitthing->z + tmhitthing->height)
{ {

View file

@ -36,6 +36,7 @@
#include "p_slopes.h" #include "p_slopes.h"
#include "f_finale.h" #include "f_finale.h"
#include "m_cond.h" #include "m_cond.h"
#include "netcode/net_command.h"
static CV_PossibleValue_t CV_BobSpeed[] = {{0, "MIN"}, {4*FRACUNIT, "MAX"}, {0, NULL}}; static CV_PossibleValue_t CV_BobSpeed[] = {{0, "MIN"}, {4*FRACUNIT, "MAX"}, {0, NULL}};
consvar_t cv_movebob = CVAR_INIT ("movebob", "1.0", CV_FLOAT|CV_SAVE, CV_BobSpeed, NULL); consvar_t cv_movebob = CVAR_INIT ("movebob", "1.0", CV_FLOAT|CV_SAVE, CV_BobSpeed, NULL);

View file

@ -88,6 +88,8 @@
#include "taglist.h" #include "taglist.h"
#include "netcode/net_command.h"
// //
// Map MD5, calculated on level load. // Map MD5, calculated on level load.
// Sent to clients in PT_SERVERINFO. // Sent to clients in PT_SERVERINFO.

View file

@ -26,6 +26,8 @@
#include "r_main.h" #include "r_main.h"
#include "r_fps.h" #include "r_fps.h"
#include "i_video.h" // rendermode #include "i_video.h" // rendermode
#include "netcode/net_command.h"
#include "netcode/server_connection.h"
// Object place // Object place
#include "m_cheat.h" #include "m_cheat.h"

View file

@ -17,7 +17,8 @@
#include "doomdef.h" #include "doomdef.h"
#include "i_system.h" #include "i_system.h"
#include "d_event.h" #include "d_event.h"
#include "d_net.h" #include "netcode/d_net.h"
#include "netcode/net_command.h"
#include "g_game.h" #include "g_game.h"
#include "p_local.h" #include "p_local.h"
#include "r_fps.h" #include "r_fps.h"
@ -11159,7 +11160,7 @@ static void P_MinecartThink(player_t *player)
detright->drawonlyforplayer = player; detright->drawonlyforplayer = player;
} }
else else
P_RemoveMobj(detleft); P_RemoveMobj(detright);
} }
} }
else else

View file

@ -249,7 +249,7 @@ static void FlipCam2_OnChange(void)
// //
// killough 5/2/98: reformatted // killough 5/2/98: reformatted
// //
INT32 R_PointOnSide(fixed_t x, fixed_t y, node_t *node) INT32 R_PointOnSide(fixed_t x, fixed_t y, node_t *restrict node)
{ {
if (!node->dx) if (!node->dx)
return x <= node->x ? node->dy > 0 : node->dy < 0; return x <= node->x ? node->dy > 0 : node->dy < 0;
@ -261,9 +261,10 @@ INT32 R_PointOnSide(fixed_t x, fixed_t y, node_t *node)
fixed_t dy = (y >> 1) - (node->y >> 1); fixed_t dy = (y >> 1) - (node->y >> 1);
// Try to quickly decide by looking at sign bits. // Try to quickly decide by looking at sign bits.
if ((node->dy ^ node->dx ^ dx ^ dy) < 0) // also use a mask to avoid branch prediction
return (node->dy ^ dx) < 0; // (left is negative) INT32 mask = (node->dy ^ node->dx ^ dx ^ dy) >> 31;
return FixedMul(dy, node->dx>>FRACBITS) >= FixedMul(node->dy>>FRACBITS, dx); return (mask & ((node->dy ^ dx) < 0)) | // (left is negative)
(~mask & (FixedMul(dy, node->dx>>FRACBITS) >= FixedMul(node->dy>>FRACBITS, dx)));
} }
// killough 5/2/98: reformatted // killough 5/2/98: reformatted

View file

@ -20,7 +20,7 @@
#include "w_wad.h" #include "w_wad.h"
#include "z_zone.h" #include "z_zone.h"
#include "d_netcmd.h" #include "netcode/d_netcmd.h"
#include "m_misc.h" #include "m_misc.h"
#include "p_local.h" // Camera... #include "p_local.h" // Camera...
#include "p_slopes.h" #include "p_slopes.h"

View file

@ -34,7 +34,7 @@
#include "p_tick.h" #include "p_tick.h"
#include "p_local.h" #include "p_local.h"
#include "p_slopes.h" #include "p_slopes.h"
#include "d_netfil.h" // blargh. for nameonly(). #include "netcode/d_netfil.h" // blargh. for nameonly().
#include "m_cheat.h" // objectplace #include "m_cheat.h" // objectplace
#ifdef HWRENDER #ifdef HWRENDER
#include "hardware/hw_md2.h" #include "hardware/hw_md2.h"

View file

@ -27,7 +27,7 @@
#include "hu_stuff.h" #include "hu_stuff.h"
#include "z_zone.h" #include "z_zone.h"
#include "d_main.h" #include "d_main.h"
#include "d_clisrv.h" #include "netcode/d_clisrv.h"
#include "f_finale.h" #include "f_finale.h"
#include "y_inter.h" // usebuffer #include "y_inter.h" // usebuffer
#include "i_sound.h" // closed captions #include "i_sound.h" // closed captions

View file

@ -262,7 +262,6 @@
<ClInclude Include="..\u_list.h" /> <ClInclude Include="..\u_list.h" />
<ClInclude Include="..\hu_stuff.h" /> <ClInclude Include="..\hu_stuff.h" />
<ClInclude Include="..\info.h" /> <ClInclude Include="..\info.h" />
<ClInclude Include="..\i_addrinfo.h" />
<ClInclude Include="..\i_joy.h" /> <ClInclude Include="..\i_joy.h" />
<ClInclude Include="..\i_net.h" /> <ClInclude Include="..\i_net.h" />
<ClInclude Include="..\i_sound.h" /> <ClInclude Include="..\i_sound.h" />
@ -297,6 +296,21 @@
<ClInclude Include="..\m_queue.h" /> <ClInclude Include="..\m_queue.h" />
<ClInclude Include="..\m_random.h" /> <ClInclude Include="..\m_random.h" />
<ClInclude Include="..\m_swap.h" /> <ClInclude Include="..\m_swap.h" />
<ClInclude Include="..\netcode\client_connection.h" />
<ClInclude Include="..\netcode\commands.h" />
<ClInclude Include="..\netcode\d_clisrv.h" />
<ClInclude Include="..\netcode\d_net.h" />
<ClInclude Include="..\netcode\d_netcmd.h" />
<ClInclude Include="..\netcode\d_netfil.h" />
<ClInclude Include="..\netcode\gamestate.h" />
<ClInclude Include="..\netcode\i_addrinfo.h" />
<ClInclude Include="..\netcode\i_net.h" />
<ClInclude Include="..\netcode\i_tcp.h" />
<ClInclude Include="..\netcode\mserv.h" />
<ClInclude Include="..\netcode\net_command.h" />
<ClInclude Include="..\netcode\protocol.h" />
<ClInclude Include="..\netcode\server_connection.h" />
<ClInclude Include="..\netcode\tic_command.h" />
<ClInclude Include="..\p5prof.h" /> <ClInclude Include="..\p5prof.h" />
<ClInclude Include="..\p_haptic.h" /> <ClInclude Include="..\p_haptic.h" />
<ClInclude Include="..\p_local.h" /> <ClInclude Include="..\p_local.h" />
@ -329,6 +343,7 @@
<ClInclude Include="..\r_textures.h" /> <ClInclude Include="..\r_textures.h" />
<ClInclude Include="..\r_things.h" /> <ClInclude Include="..\r_things.h" />
<ClInclude Include="..\screen.h" /> <ClInclude Include="..\screen.h" />
<ClInclude Include="..\snake.h" />
<ClInclude Include="..\sounds.h" /> <ClInclude Include="..\sounds.h" />
<ClInclude Include="..\st_stuff.h" /> <ClInclude Include="..\st_stuff.h" />
<ClInclude Include="..\s_sound.h" /> <ClInclude Include="..\s_sound.h" />
@ -400,11 +415,7 @@
<ClCompile Include="..\deh_soc.c" /> <ClCompile Include="..\deh_soc.c" />
<ClCompile Include="..\deh_lua.c" /> <ClCompile Include="..\deh_lua.c" />
<ClCompile Include="..\deh_tables.c" /> <ClCompile Include="..\deh_tables.c" />
<ClCompile Include="..\d_clisrv.c" />
<ClCompile Include="..\d_main.c" /> <ClCompile Include="..\d_main.c" />
<ClCompile Include="..\d_net.c" />
<ClCompile Include="..\d_netcmd.c" />
<ClCompile Include="..\d_netfil.c" />
<ClCompile Include="..\filesrch.c" /> <ClCompile Include="..\filesrch.c" />
<ClCompile Include="..\f_finale.c" /> <ClCompile Include="..\f_finale.c" />
<ClCompile Include="..\f_wipe.c" /> <ClCompile Include="..\f_wipe.c" />
@ -427,10 +438,6 @@
<ClCompile Include="..\u_list.c" /> <ClCompile Include="..\u_list.c" />
<ClCompile Include="..\hu_stuff.c" /> <ClCompile Include="..\hu_stuff.c" />
<ClCompile Include="..\info.c" /> <ClCompile Include="..\info.c" />
<ClCompile Include="..\i_addrinfo.c">
<ExcludedFromBuild>true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\i_tcp.c" />
<ClCompile Include="..\i_time.c" /> <ClCompile Include="..\i_time.c" />
<ClCompile Include="..\lua_baselib.c" /> <ClCompile Include="..\lua_baselib.c" />
<ClCompile Include="..\lua_blockmaplib.c" /> <ClCompile Include="..\lua_blockmaplib.c" />
@ -451,8 +458,6 @@
<ClCompile Include="..\lua_thinkerlib.c" /> <ClCompile Include="..\lua_thinkerlib.c" />
<ClCompile Include="..\lzf.c" /> <ClCompile Include="..\lzf.c" />
<ClCompile Include="..\md5.c" /> <ClCompile Include="..\md5.c" />
<ClCompile Include="..\mserv.c" />
<ClCompile Include="..\http-mserv.c" />
<ClCompile Include="..\m_aatree.c" /> <ClCompile Include="..\m_aatree.c" />
<ClCompile Include="..\m_anigif.c" /> <ClCompile Include="..\m_anigif.c" />
<ClCompile Include="..\m_argv.c" /> <ClCompile Include="..\m_argv.c" />
@ -466,6 +471,22 @@
<ClCompile Include="..\m_perfstats.c" /> <ClCompile Include="..\m_perfstats.c" />
<ClCompile Include="..\m_queue.c" /> <ClCompile Include="..\m_queue.c" />
<ClCompile Include="..\m_random.c" /> <ClCompile Include="..\m_random.c" />
<ClCompile Include="..\netcode\client_connection.c" />
<ClCompile Include="..\netcode\commands.c" />
<ClCompile Include="..\netcode\d_clisrv.c" />
<ClCompile Include="..\netcode\d_net.c" />
<ClCompile Include="..\netcode\d_netcmd.c" />
<ClCompile Include="..\netcode\d_netfil.c" />
<ClCompile Include="..\netcode\gamestate.c" />
<ClCompile Include="..\netcode\http-mserv.c" />
<ClCompile Include="..\netcode\i_addrinfo.c">
<ExcludedFromBuild>true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\netcode\i_tcp.c" />
<ClCompile Include="..\netcode\mserv.c" />
<ClCompile Include="..\netcode\net_command.c" />
<ClCompile Include="..\netcode\server_connection.c" />
<ClCompile Include="..\netcode\tic_command.c" />
<ClCompile Include="..\p_ceilng.c" /> <ClCompile Include="..\p_ceilng.c" />
<ClCompile Include="..\p_enemy.c" /> <ClCompile Include="..\p_enemy.c" />
<ClCompile Include="..\p_floor.c" /> <ClCompile Include="..\p_floor.c" />
@ -510,6 +531,7 @@
<ClCompile Include="..\r_textures.c" /> <ClCompile Include="..\r_textures.c" />
<ClCompile Include="..\r_things.c" /> <ClCompile Include="..\r_things.c" />
<ClCompile Include="..\screen.c" /> <ClCompile Include="..\screen.c" />
<ClCompile Include="..\snake.c" />
<ClCompile Include="..\sounds.c" /> <ClCompile Include="..\sounds.c" />
<ClCompile Include="..\string.c" /> <ClCompile Include="..\string.c" />
<ClCompile Include="..\st_stuff.c" /> <ClCompile Include="..\st_stuff.c" />

View file

@ -156,24 +156,12 @@
<ClInclude Include="..\doomtype.h"> <ClInclude Include="..\doomtype.h">
<Filter>D_Doom</Filter> <Filter>D_Doom</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="..\d_clisrv.h">
<Filter>D_Doom</Filter>
</ClInclude>
<ClInclude Include="..\d_event.h"> <ClInclude Include="..\d_event.h">
<Filter>D_Doom</Filter> <Filter>D_Doom</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="..\d_main.h"> <ClInclude Include="..\d_main.h">
<Filter>D_Doom</Filter> <Filter>D_Doom</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="..\d_net.h">
<Filter>D_Doom</Filter>
</ClInclude>
<ClInclude Include="..\d_netcmd.h">
<Filter>D_Doom</Filter>
</ClInclude>
<ClInclude Include="..\d_netfil.h">
<Filter>D_Doom</Filter>
</ClInclude>
<ClInclude Include="..\d_player.h"> <ClInclude Include="..\d_player.h">
<Filter>D_Doom</Filter> <Filter>D_Doom</Filter>
</ClInclude> </ClInclude>
@ -279,9 +267,6 @@
<ClInclude Include="..\filesrch.h"> <ClInclude Include="..\filesrch.h">
<Filter>I_Interface</Filter> <Filter>I_Interface</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="..\i_addrinfo.h">
<Filter>I_Interface</Filter>
</ClInclude>
<ClInclude Include="..\i_joy.h"> <ClInclude Include="..\i_joy.h">
<Filter>I_Interface</Filter> <Filter>I_Interface</Filter>
</ClInclude> </ClInclude>
@ -306,12 +291,6 @@
<ClInclude Include="..\keys.h"> <ClInclude Include="..\keys.h">
<Filter>I_Interface</Filter> <Filter>I_Interface</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="..\mserv.h">
<Filter>I_Interface</Filter>
</ClInclude>
<ClInclude Include="..\http-mserv.h">
<Filter>I_Interface</Filter>
</ClInclude>
<ClInclude Include="..\lua_hook.h"> <ClInclude Include="..\lua_hook.h">
<Filter>LUA</Filter> <Filter>LUA</Filter>
</ClInclude> </ClInclude>
@ -372,6 +351,54 @@
<ClInclude Include="..\m_swap.h"> <ClInclude Include="..\m_swap.h">
<Filter>M_Misc</Filter> <Filter>M_Misc</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="..\netcode\client_connection.h">
<Filter>D_Doom</Filter>
</ClInclude>
<ClInclude Include="..\netcode\commands.h">
<Filter>D_Doom</Filter>
</ClInclude>
<ClInclude Include="..\netcode\d_clisrv.h">
<Filter>D_Doom</Filter>
</ClInclude>
<ClInclude Include="..\netcode\d_net.h">
<Filter>D_Doom</Filter>
</ClInclude>
<ClInclude Include="..\netcode\d_netcmd.h">
<Filter>D_Doom</Filter>
</ClInclude>
<ClInclude Include="..\netcode\d_netfil.h">
<Filter>D_Doom</Filter>
</ClInclude>
<ClInclude Include="..\netcode\gamestate.h">
<Filter>D_Doom</Filter>
</ClInclude>
<ClInclude Include="..\netcode\http-mserv.h">
<Filter>I_Interface</Filter>
</ClInclude>
<ClInclude Include="..\netcode\i_addrinfo.h">
<Filter>I_Interface</Filter>
</ClInclude>
<ClInclude Include="..\netcode\i_net.h">
<Filter>I_Interface</Filter>
</ClInclude>
<ClInclude Include="..\netcode\i_tcp.h">
<Filter>I_Interface</Filter>
</ClInclude>
<ClInclude Include="..\netcode\mserv.h">
<Filter>I_Interface</Filter>
</ClInclude>
<ClInclude Include="..\netcode\net_command.h">
<Filter>D_Doom</Filter>
</ClInclude>
<ClInclude Include="..\netcode\protocol.h">
<Filter>D_Doom</Filter>
</ClInclude>
<ClInclude Include="..\netcode\server_connection.h">
<Filter>D_Doom</Filter>
</ClInclude>
<ClInclude Include="..\netcode\tic_command.h">
<Filter>D_Doom</Filter>
</ClInclude>
<ClInclude Include="..\comptime.h"> <ClInclude Include="..\comptime.h">
<Filter>O_Other</Filter> <Filter>O_Other</Filter>
</ClInclude> </ClInclude>
@ -465,6 +492,9 @@
<ClInclude Include="..\v_video.h"> <ClInclude Include="..\v_video.h">
<Filter>R_Rend</Filter> <Filter>R_Rend</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="..\snake.h">
<Filter>M_Misc</Filter>
</ClInclude>
<ClInclude Include="..\sounds.h"> <ClInclude Include="..\sounds.h">
<Filter>S_Sounds</Filter> <Filter>S_Sounds</Filter>
</ClInclude> </ClInclude>
@ -639,21 +669,9 @@
<ClCompile Include="..\deh_tables.c"> <ClCompile Include="..\deh_tables.c">
<Filter>D_Doom</Filter> <Filter>D_Doom</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="..\d_clisrv.c">
<Filter>D_Doom</Filter>
</ClCompile>
<ClCompile Include="..\d_main.c"> <ClCompile Include="..\d_main.c">
<Filter>D_Doom</Filter> <Filter>D_Doom</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="..\d_net.c">
<Filter>D_Doom</Filter>
</ClCompile>
<ClCompile Include="..\d_netcmd.c">
<Filter>D_Doom</Filter>
</ClCompile>
<ClCompile Include="..\d_netfil.c">
<Filter>D_Doom</Filter>
</ClCompile>
<ClCompile Include="..\z_zone.c"> <ClCompile Include="..\z_zone.c">
<Filter>D_Doom</Filter> <Filter>D_Doom</Filter>
</ClCompile> </ClCompile>
@ -732,18 +750,9 @@
<ClCompile Include="..\filesrch.c"> <ClCompile Include="..\filesrch.c">
<Filter>I_Interface</Filter> <Filter>I_Interface</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="..\i_addrinfo.c">
<Filter>I_Interface</Filter>
</ClCompile>
<ClCompile Include="..\i_tcp.c"> <ClCompile Include="..\i_tcp.c">
<Filter>I_Interface</Filter> <Filter>I_Interface</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="..\mserv.c">
<Filter>I_Interface</Filter>
</ClCompile>
<ClCompile Include="..\http-mserv.c">
<Filter>I_Interface</Filter>
</ClCompile>
<ClCompile Include="..\lua_baselib.c"> <ClCompile Include="..\lua_baselib.c">
<Filter>LUA</Filter> <Filter>LUA</Filter>
</ClCompile> </ClCompile>
@ -831,6 +840,48 @@
<ClCompile Include="..\m_random.c"> <ClCompile Include="..\m_random.c">
<Filter>M_Misc</Filter> <Filter>M_Misc</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="..\netcode\client_connection.c">
<Filter>D_Doom</Filter>
</ClCompile>
<ClCompile Include="..\netcode\commands.c">
<Filter>D_Doom</Filter>
</ClCompile>
<ClCompile Include="..\netcode\d_clisrv.c">
<Filter>D_Doom</Filter>
</ClCompile>
<ClCompile Include="..\netcode\d_net.c">
<Filter>D_Doom</Filter>
</ClCompile>
<ClCompile Include="..\netcode\d_netcmd.c">
<Filter>D_Doom</Filter>
</ClCompile>
<ClCompile Include="..\netcode\d_netfil.c">
<Filter>D_Doom</Filter>
</ClCompile>
<ClCompile Include="..\netcode\gamestate.c">
<Filter>D_Doom</Filter>
</ClCompile>
<ClCompile Include="..\netcode\http-mserv.c">
<Filter>I_Interface</Filter>
</ClCompile>
<ClCompile Include="..\netcode\i_addrinfo.c">
<Filter>I_Interface</Filter>
</ClCompile>
<ClCompile Include="..\netcode\i_tcp.c">
<Filter>I_Interface</Filter>
</ClCompile>
<ClCompile Include="..\netcode\mserv.c">
<Filter>I_Interface</Filter>
</ClCompile>
<ClCompile Include="..\netcode\net_command.c">
<Filter>D_Doom</Filter>
</ClCompile>
<ClCompile Include="..\netcode\server_connection.c">
<Filter>D_Doom</Filter>
</ClCompile>
<ClCompile Include="..\netcode\tic_command.c">
<Filter>D_Doom</Filter>
</ClCompile>
<ClCompile Include="..\string.c"> <ClCompile Include="..\string.c">
<Filter>M_Misc</Filter> <Filter>M_Misc</Filter>
</ClCompile> </ClCompile>
@ -954,6 +1005,9 @@
<ClCompile Include="..\v_video.c"> <ClCompile Include="..\v_video.c">
<Filter>R_Rend</Filter> <Filter>R_Rend</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="..\snake.c">
<Filter>M_Misc</Filter>
</ClCompile>
<ClCompile Include="..\sounds.c"> <ClCompile Include="..\sounds.c">
<Filter>S_Sounds</Filter> <Filter>S_Sounds</Filter>
</ClCompile> </ClCompile>

View file

@ -21,16 +21,16 @@
#include "../i_system.h" #include "../i_system.h"
#include "../d_event.h" #include "../d_event.h"
#include "../d_net.h" #include "../netcode/d_net.h"
#include "../m_argv.h" #include "../m_argv.h"
#include "../doomstat.h" #include "../doomstat.h"
#include "../i_net.h" #include "../netcode/i_net.h"
#include "../z_zone.h" #include "../z_zone.h"
#include "../i_tcp.h" #include "../netcode/i_tcp.h"
#ifdef HAVE_SDL #ifdef HAVE_SDL

View file

@ -187,7 +187,8 @@ static char returnWadPath[256];
#include "../i_system.h" #include "../i_system.h"
#include "../i_threads.h" #include "../i_threads.h"
#include "../screen.h" //vid.WndParent #include "../screen.h" //vid.WndParent
#include "../d_net.h" #include "../netcode/d_net.h"
#include "../netcode/commands.h"
#include "../g_game.h" #include "../g_game.h"
#include "../filesrch.h" #include "../filesrch.h"
#include "endtxt.h" #include "endtxt.h"
@ -208,7 +209,7 @@ static char returnWadPath[256];
#if !defined(NOMUMBLE) && defined(HAVE_MUMBLE) #if !defined(NOMUMBLE) && defined(HAVE_MUMBLE)
// Mumble context string // Mumble context string
#include "../d_clisrv.h" #include "../netcode/d_clisrv.h"
#include "../byteptr.h" #include "../byteptr.h"
#endif #endif
@ -2265,7 +2266,7 @@ void I_Sleep(UINT32 ms)
} }
#ifdef NEWSIGNALHANDLER #ifdef NEWSIGNALHANDLER
static void newsignalhandler_Warn(const char *pr) ATTRNORETURN static FUNCNORETURN void newsignalhandler_Warn(const char *pr)
{ {
char text[128]; char text[128];
@ -2387,9 +2388,7 @@ void I_Quit(void)
SDLforceUngrabMouse(); SDLforceUngrabMouse();
quiting = SDL_FALSE; quiting = SDL_FALSE;
M_SaveConfig(NULL); //save game config, cvars.. M_SaveConfig(NULL); //save game config, cvars..
#ifndef NONET
D_SaveBan(); // save the ban list D_SaveBan(); // save the ban list
#endif
G_SaveGameData(clientGamedata); // Tails 12-08-2002 G_SaveGameData(clientGamedata); // Tails 12-08-2002
//added:16-02-98: when recording a demo, should exit using 'q' key, //added:16-02-98: when recording a demo, should exit using 'q' key,
// but sometimes we forget and use 'F10'.. so save here too. // but sometimes we forget and use 'F10'.. so save here too.
@ -2504,9 +2503,7 @@ void I_Error(const char *error, ...)
// --- // ---
M_SaveConfig(NULL); // save game config, cvars.. M_SaveConfig(NULL); // save game config, cvars..
#ifndef NONET
D_SaveBan(); // save the ban list D_SaveBan(); // save the ban list
#endif
G_SaveGameData(clientGamedata); // Tails 12-08-2002 G_SaveGameData(clientGamedata); // Tails 12-08-2002
// Shutdown. Here might be other errors. // Shutdown. Here might be other errors.
@ -3038,11 +3035,11 @@ size_t I_GetFreeMem(size_t *total)
#ifdef FREEBSD #ifdef FREEBSD
u_int v_free_count, v_page_size, v_page_count; u_int v_free_count, v_page_size, v_page_count;
size_t size = sizeof(v_free_count); size_t size = sizeof(v_free_count);
sysctlbyname("vm.stat.vm.v_free_count", &v_free_count, &size, NULL, 0); sysctlbyname("vm.stats.vm.v_free_count", &v_free_count, &size, NULL, 0);
size_t size = sizeof(v_page_size); size = sizeof(v_page_size);
sysctlbyname("vm.stat.vm.v_page_size", &v_page_size, &size, NULL, 0); sysctlbyname("vm.stats.vm.v_page_size", &v_page_size, &size, NULL, 0);
size_t size = sizeof(v_page_count); size = sizeof(v_page_count);
sysctlbyname("vm.stat.vm.v_page_count", &v_page_count, &size, NULL, 0); sysctlbyname("vm.stats.vm.v_page_count", &v_page_count, &size, NULL, 0);
if (total) if (total)
*total = v_page_count * v_page_size; *total = v_page_count * v_page_size;

View file

@ -21,7 +21,7 @@
#include "SDL_ttf.h" #include "SDL_ttf.h"
#include "../doomdef.h" #include "../doomdef.h"
#include "../doomstat.h" #include "../doomstat.h"
#include "../d_netfil.h" #include "../netcode/d_netfil.h"
#include "../filesrch.h" #include "../filesrch.h"
#include "i_ttf.h" #include "i_ttf.h"

593
src/snake.c Normal file
View file

@ -0,0 +1,593 @@
// SONIC ROBO BLAST 2
//-----------------------------------------------------------------------------
// Copyright (C) 2023-2023 by Louis-Antoine de Moulins de Rochefort.
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
// See the 'LICENSE' file for more details.
//-----------------------------------------------------------------------------
/// \file snake.c
/// \brief Snake minigame for the download screen.
#include "snake.h"
#include "g_input.h"
#include "g_game.h"
#include "i_joy.h"
#include "m_random.h"
#include "s_sound.h"
#include "screen.h"
#include "v_video.h"
#include "w_wad.h"
#include "z_zone.h"
#define SPEED 5
#define NUM_BLOCKS_X 20
#define NUM_BLOCKS_Y 10
#define BLOCK_SIZE 12
#define BORDER_SIZE 12
#define MAP_WIDTH (NUM_BLOCKS_X * BLOCK_SIZE)
#define MAP_HEIGHT (NUM_BLOCKS_Y * BLOCK_SIZE)
#define LEFT_X ((BASEVIDWIDTH - MAP_WIDTH) / 2 - BORDER_SIZE)
#define RIGHT_X (LEFT_X + MAP_WIDTH + BORDER_SIZE * 2 - 1)
#define BOTTOM_Y (BASEVIDHEIGHT - 48)
#define TOP_Y (BOTTOM_Y - MAP_HEIGHT - BORDER_SIZE * 2 + 1)
enum bonustype_s {
BONUS_NONE = 0,
BONUS_SLOW,
BONUS_FAST,
BONUS_GHOST,
BONUS_NUKE,
BONUS_SCISSORS,
BONUS_REVERSE,
BONUS_EGGMAN,
NUM_BONUSES,
};
typedef struct snake_s
{
boolean paused;
boolean pausepressed;
tic_t time;
tic_t nextupdate;
boolean gameover;
UINT8 background;
UINT16 snakelength;
enum bonustype_s snakebonus;
tic_t snakebonustime;
UINT8 snakex[NUM_BLOCKS_X * NUM_BLOCKS_Y];
UINT8 snakey[NUM_BLOCKS_X * NUM_BLOCKS_Y];
UINT8 snakedir[NUM_BLOCKS_X * NUM_BLOCKS_Y];
UINT8 applex;
UINT8 appley;
enum bonustype_s bonustype;
UINT8 bonusx;
UINT8 bonusy;
event_t *joyevents[MAXEVENTS];
UINT16 joyeventcount;
} snake_t;
static const char *bonuspatches[] = {
NULL,
"DL_SLOW",
"TVSSC0",
"TVIVC0",
"TVARC0",
"DL_SCISSORS",
"TVRCC0",
"TVEGC0",
};
static const char *backgrounds[] = {
"RVPUMICF",
"FRSTRCKF",
"TAR",
"MMFLRB4",
"RVDARKF1",
"RVZWALF1",
"RVZWALF4",
"RVZWALF5",
"RVZGRS02",
"RVZGRS04",
};
static void Initialise(snake_t *snake)
{
snake->paused = false;
snake->pausepressed = false;
snake->time = 0;
snake->nextupdate = SPEED;
snake->gameover = false;
snake->background = M_RandomKey(sizeof(backgrounds) / sizeof(*backgrounds));
snake->snakelength = 1;
snake->snakebonus = BONUS_NONE;
snake->snakex[0] = M_RandomKey(NUM_BLOCKS_X);
snake->snakey[0] = M_RandomKey(NUM_BLOCKS_Y);
snake->snakedir[0] = 0;
snake->snakedir[1] = 0;
snake->applex = M_RandomKey(NUM_BLOCKS_X);
snake->appley = M_RandomKey(NUM_BLOCKS_Y);
snake->bonustype = BONUS_NONE;
snake->joyeventcount = 0;
}
static UINT8 GetOppositeDir(UINT8 dir)
{
if (dir == 1 || dir == 3)
return dir + 1;
else if (dir == 2 || dir == 4)
return dir - 1;
else
return 12 + 5 - dir;
}
static void FindFreeSlot(snake_t *snake, UINT8 *freex, UINT8 *freey, UINT8 headx, UINT8 heady)
{
UINT8 x, y;
UINT16 i;
do
{
x = M_RandomKey(NUM_BLOCKS_X);
y = M_RandomKey(NUM_BLOCKS_Y);
for (i = 0; i < snake->snakelength; i++)
if (x == snake->snakex[i] && y == snake->snakey[i])
break;
} while (i < snake->snakelength || (x == headx && y == heady)
|| (x == snake->applex && y == snake->appley)
|| (snake->bonustype != BONUS_NONE && x == snake->bonusx && y == snake->bonusy));
*freex = x;
*freey = y;
}
void Snake_Allocate(void **opaque)
{
if (*opaque)
Snake_Free(opaque);
*opaque = malloc(sizeof(snake_t));
Initialise(*opaque);
}
void Snake_Update(void *opaque)
{
UINT8 x, y;
UINT8 oldx, oldy;
UINT16 i;
UINT16 joystate = 0;
static INT32 pjoyx = 0, pjoyy = 0;
snake_t *snake = opaque;
// Handle retry
if (snake->gameover && (PLAYER1INPUTDOWN(GC_JUMP) || gamekeydown[KEY_ENTER]))
{
Initialise(snake);
snake->pausepressed = true; // Avoid accidental pause on respawn
}
// Handle pause
if (PLAYER1INPUTDOWN(GC_PAUSE) || gamekeydown[KEY_ENTER])
{
if (!snake->pausepressed)
snake->paused = !snake->paused;
snake->pausepressed = true;
}
else
snake->pausepressed = false;
if (snake->paused)
return;
snake->time++;
x = snake->snakex[0];
y = snake->snakey[0];
oldx = snake->snakex[1];
oldy = snake->snakey[1];
// Process the input events in here dear lord
for (UINT16 j = 0; j < snake->joyeventcount; j++)
{
event_t *ev = snake->joyevents[j];
const INT32 jdeadzone = (JOYAXISRANGE * cv_digitaldeadzone.value) / FRACUNIT;
if (ev->y != INT32_MAX)
{
if (Joystick.bGamepadStyle || abs(ev->y) > jdeadzone)
{
if (ev->y < 0 && pjoyy >= 0)
joystate = 1;
else if (ev->y > 0 && pjoyy <= 0)
joystate = 2;
pjoyy = ev->y;
}
else
pjoyy = 0;
}
if (ev->x != INT32_MAX)
{
if (Joystick.bGamepadStyle || abs(ev->x) > jdeadzone)
{
if (ev->x < 0 && pjoyx >= 0)
joystate = 3;
else if (ev->x > 0 && pjoyx <= 0)
joystate = 4;
pjoyx = ev->x;
}
else
pjoyx = 0;
}
}
snake->joyeventcount = 0;
// Update direction
if (PLAYER1INPUTDOWN(GC_STRAFELEFT) || gamekeydown[KEY_LEFTARROW] || joystate == 3)
{
if (snake->snakelength < 2 || x <= oldx)
snake->snakedir[0] = 1;
}
else if (PLAYER1INPUTDOWN(GC_STRAFERIGHT) || gamekeydown[KEY_RIGHTARROW] || joystate == 4)
{
if (snake->snakelength < 2 || x >= oldx)
snake->snakedir[0] = 2;
}
else if (PLAYER1INPUTDOWN(GC_FORWARD) || gamekeydown[KEY_UPARROW] || joystate == 1)
{
if (snake->snakelength < 2 || y <= oldy)
snake->snakedir[0] = 3;
}
else if (PLAYER1INPUTDOWN(GC_BACKWARD) || gamekeydown[KEY_DOWNARROW] || joystate == 2)
{
if (snake->snakelength < 2 || y >= oldy)
snake->snakedir[0] = 4;
}
if (snake->snakebonustime)
{
snake->snakebonustime--;
if (!snake->snakebonustime)
snake->snakebonus = BONUS_NONE;
}
snake->nextupdate--;
if (snake->nextupdate)
return;
if (snake->snakebonus == BONUS_SLOW)
snake->nextupdate = SPEED * 2;
else if (snake->snakebonus == BONUS_FAST)
snake->nextupdate = SPEED * 2 / 3;
else
snake->nextupdate = SPEED;
if (snake->gameover)
return;
// Find new position
switch (snake->snakedir[0])
{
case 1:
if (x > 0)
x--;
else
snake->gameover = true;
break;
case 2:
if (x < NUM_BLOCKS_X - 1)
x++;
else
snake->gameover = true;
break;
case 3:
if (y > 0)
y--;
else
snake->gameover = true;
break;
case 4:
if (y < NUM_BLOCKS_Y - 1)
y++;
else
snake->gameover = true;
break;
}
// Check collision with snake
if (snake->snakebonus != BONUS_GHOST)
for (i = 1; i < snake->snakelength - 1; i++)
if (x == snake->snakex[i] && y == snake->snakey[i])
{
if (snake->snakebonus == BONUS_SCISSORS)
{
snake->snakebonus = BONUS_NONE;
snake->snakelength = i;
S_StartSound(NULL, sfx_adderr);
}
else
snake->gameover = true;
}
if (snake->gameover)
{
S_StartSound(NULL, sfx_lose);
return;
}
// Check collision with apple
if (x == snake->applex && y == snake->appley)
{
if (snake->snakelength + 3 < NUM_BLOCKS_X * NUM_BLOCKS_Y)
{
snake->snakelength++;
snake->snakex [snake->snakelength - 1] = snake->snakex [snake->snakelength - 2];
snake->snakey [snake->snakelength - 1] = snake->snakey [snake->snakelength - 2];
snake->snakedir[snake->snakelength - 1] = snake->snakedir[snake->snakelength - 2];
}
// Spawn new apple
FindFreeSlot(snake, &snake->applex, &snake->appley, x, y);
// Spawn new bonus
if (!(snake->snakelength % 5))
{
do
{
snake->bonustype = M_RandomKey(NUM_BONUSES - 1) + 1;
} while (snake->snakelength > NUM_BLOCKS_X * NUM_BLOCKS_Y * 3 / 4
&& (snake->bonustype == BONUS_EGGMAN || snake->bonustype == BONUS_FAST || snake->bonustype == BONUS_REVERSE));
FindFreeSlot(snake, &snake->bonusx, &snake->bonusy, x, y);
}
S_StartSound(NULL, sfx_s3k6b);
}
if (snake->snakelength > 1 && snake->snakedir[0])
{
UINT8 dir = snake->snakedir[0];
oldx = snake->snakex[1];
oldy = snake->snakey[1];
// Move
for (i = snake->snakelength - 1; i > 0; i--)
{
snake->snakex[i] = snake->snakex[i - 1];
snake->snakey[i] = snake->snakey[i - 1];
snake->snakedir[i] = snake->snakedir[i - 1];
}
// Handle corners
if (x < oldx && dir == 3)
dir = 5;
else if (x > oldx && dir == 3)
dir = 6;
else if (x < oldx && dir == 4)
dir = 7;
else if (x > oldx && dir == 4)
dir = 8;
else if (y < oldy && dir == 1)
dir = 9;
else if (y < oldy && dir == 2)
dir = 10;
else if (y > oldy && dir == 1)
dir = 11;
else if (y > oldy && dir == 2)
dir = 12;
snake->snakedir[1] = dir;
}
snake->snakex[0] = x;
snake->snakey[0] = y;
// Check collision with bonus
if (snake->bonustype != BONUS_NONE && x == snake->bonusx && y == snake->bonusy)
{
S_StartSound(NULL, sfx_ncchip);
switch (snake->bonustype)
{
case BONUS_SLOW:
snake->snakebonus = BONUS_SLOW;
snake->snakebonustime = 20 * TICRATE;
break;
case BONUS_FAST:
snake->snakebonus = BONUS_FAST;
snake->snakebonustime = 20 * TICRATE;
break;
case BONUS_GHOST:
snake->snakebonus = BONUS_GHOST;
snake->snakebonustime = 10 * TICRATE;
break;
case BONUS_NUKE:
for (i = 0; i < snake->snakelength; i++)
{
snake->snakex [i] = snake->snakex [0];
snake->snakey [i] = snake->snakey [0];
snake->snakedir[i] = snake->snakedir[0];
}
S_StartSound(NULL, sfx_bkpoof);
break;
case BONUS_SCISSORS:
snake->snakebonus = BONUS_SCISSORS;
snake->snakebonustime = 60 * TICRATE;
break;
case BONUS_REVERSE:
for (i = 0; i < (snake->snakelength + 1) / 2; i++)
{
UINT16 i2 = snake->snakelength - 1 - i;
UINT8 tmpx = snake->snakex [i];
UINT8 tmpy = snake->snakey [i];
UINT8 tmpdir = snake->snakedir[i];
// Swap first segment with last segment
snake->snakex [i] = snake->snakex [i2];
snake->snakey [i] = snake->snakey [i2];
snake->snakedir[i] = GetOppositeDir(snake->snakedir[i2]);
snake->snakex [i2] = tmpx;
snake->snakey [i2] = tmpy;
snake->snakedir[i2] = GetOppositeDir(tmpdir);
}
snake->snakedir[0] = 0;
S_StartSound(NULL, sfx_gravch);
break;
default:
if (snake->snakebonus != BONUS_GHOST)
{
snake->gameover = true;
S_StartSound(NULL, sfx_lose);
}
}
snake->bonustype = BONUS_NONE;
}
}
void Snake_Draw(void *opaque)
{
INT16 i;
snake_t *snake = opaque;
// Background
V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 31);
V_DrawFlatFill(
LEFT_X + BORDER_SIZE,
TOP_Y + BORDER_SIZE,
MAP_WIDTH,
MAP_HEIGHT,
W_GetNumForName(backgrounds[snake->background])
);
// Borders
V_DrawFill(LEFT_X, TOP_Y, BORDER_SIZE + MAP_WIDTH, BORDER_SIZE, 242); // Top
V_DrawFill(LEFT_X + BORDER_SIZE + MAP_WIDTH, TOP_Y, BORDER_SIZE, BORDER_SIZE + MAP_HEIGHT, 242); // Right
V_DrawFill(LEFT_X + BORDER_SIZE, TOP_Y + BORDER_SIZE + MAP_HEIGHT, BORDER_SIZE + MAP_WIDTH, BORDER_SIZE, 242); // Bottom
V_DrawFill(LEFT_X, TOP_Y + BORDER_SIZE, BORDER_SIZE, BORDER_SIZE + MAP_HEIGHT, 242); // Left
// Apple
V_DrawFixedPatch(
(LEFT_X + BORDER_SIZE + snake->applex * BLOCK_SIZE + BLOCK_SIZE / 2) * FRACUNIT,
(TOP_Y + BORDER_SIZE + snake->appley * BLOCK_SIZE + BLOCK_SIZE / 2) * FRACUNIT,
FRACUNIT / 4,
0,
W_CachePatchLongName("DL_APPLE", PU_HUDGFX),
NULL
);
// Bonus
if (snake->bonustype != BONUS_NONE)
V_DrawFixedPatch(
(LEFT_X + BORDER_SIZE + snake->bonusx * BLOCK_SIZE + BLOCK_SIZE / 2 ) * FRACUNIT,
(TOP_Y + BORDER_SIZE + snake->bonusy * BLOCK_SIZE + BLOCK_SIZE / 2 + 4) * FRACUNIT,
FRACUNIT / 2,
0,
W_CachePatchLongName(bonuspatches[snake->bonustype], PU_HUDGFX),
NULL
);
// Snake
if (!snake->gameover || snake->time % 8 < 8 / 2) // Blink if game over
{
for (i = snake->snakelength - 1; i >= 0; i--)
{
const char *patchname;
UINT8 dir = snake->snakedir[i];
if (i == 0) // Head
{
switch (dir)
{
case 1: patchname = "DL_SNAKEHEAD_L"; break;
case 2: patchname = "DL_SNAKEHEAD_R"; break;
case 3: patchname = "DL_SNAKEHEAD_T"; break;
case 4: patchname = "DL_SNAKEHEAD_B"; break;
default: patchname = "DL_SNAKEHEAD_M";
}
}
else // Body
{
switch (dir)
{
case 1: patchname = "DL_SNAKEBODY_L"; break;
case 2: patchname = "DL_SNAKEBODY_R"; break;
case 3: patchname = "DL_SNAKEBODY_T"; break;
case 4: patchname = "DL_SNAKEBODY_B"; break;
case 5: patchname = "DL_SNAKEBODY_LT"; break;
case 6: patchname = "DL_SNAKEBODY_RT"; break;
case 7: patchname = "DL_SNAKEBODY_LB"; break;
case 8: patchname = "DL_SNAKEBODY_RB"; break;
case 9: patchname = "DL_SNAKEBODY_TL"; break;
case 10: patchname = "DL_SNAKEBODY_TR"; break;
case 11: patchname = "DL_SNAKEBODY_BL"; break;
case 12: patchname = "DL_SNAKEBODY_BR"; break;
default: patchname = "DL_SNAKEBODY_B";
}
}
V_DrawFixedPatch(
(LEFT_X + BORDER_SIZE + snake->snakex[i] * BLOCK_SIZE + BLOCK_SIZE / 2) * FRACUNIT,
(TOP_Y + BORDER_SIZE + snake->snakey[i] * BLOCK_SIZE + BLOCK_SIZE / 2) * FRACUNIT,
i == 0 && dir == 0 ? FRACUNIT / 5 : FRACUNIT / 2,
snake->snakebonus == BONUS_GHOST ? V_TRANSLUCENT : 0,
W_CachePatchLongName(patchname, PU_HUDGFX),
NULL
);
}
}
// Length
V_DrawString(RIGHT_X + 4, TOP_Y, V_MONOSPACE, va("%u", snake->snakelength));
// Bonus
if (snake->snakebonus != BONUS_NONE
&& (snake->snakebonustime >= 3 * TICRATE || snake->time % 4 < 4 / 2))
V_DrawFixedPatch(
(RIGHT_X + 10) * FRACUNIT,
(TOP_Y + 24) * FRACUNIT,
FRACUNIT / 2,
0,
W_CachePatchLongName(bonuspatches[snake->snakebonus], PU_HUDGFX),
NULL
);
}
void Snake_Free(void **opaque)
{
if (*opaque)
{
free(*opaque);
*opaque = NULL;
}
}
// I'm screaming the hack is clean - ashi
boolean Snake_JoyGrabber(void *opaque, event_t *ev)
{
snake_t *snake = opaque;
if (ev->type == ev_joystick && ev->key == 0)
{
snake->joyevents[snake->joyeventcount] = ev;
snake->joyeventcount++;
return true;
}
else
return false;
}

23
src/snake.h Normal file
View file

@ -0,0 +1,23 @@
// SONIC ROBO BLAST 2
//-----------------------------------------------------------------------------
// Copyright (C) 2023-2023 by Louis-Antoine de Moulins de Rochefort.
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
// See the 'LICENSE' file for more details.
//-----------------------------------------------------------------------------
/// \file snake.h
/// \brief Snake minigame for the download screen.
#ifndef __SNAKE__
#define __SNAKE__
#include "d_event.h"
void Snake_Allocate(void **opaque);
void Snake_Update(void *opaque);
void Snake_Draw(void *opaque);
void Snake_Free(void **opaque);
boolean Snake_JoyGrabber(void *opaque, event_t *ev);
#endif

View file

@ -51,8 +51,8 @@
#include "filesrch.h" #include "filesrch.h"
#include "d_main.h" #include "d_main.h"
#include "d_netfil.h" #include "netcode/d_netfil.h"
#include "d_clisrv.h" #include "netcode/d_clisrv.h"
#include "dehacked.h" #include "dehacked.h"
#include "r_defs.h" #include "r_defs.h"
#include "r_data.h" #include "r_data.h"

View file

@ -15,7 +15,7 @@
#include "f_finale.h" #include "f_finale.h"
#include "g_game.h" #include "g_game.h"
#include "hu_stuff.h" #include "hu_stuff.h"
#include "i_net.h" #include "netcode/i_net.h"
#include "i_video.h" #include "i_video.h"
#include "p_tick.h" #include "p_tick.h"
#include "r_defs.h" #include "r_defs.h"