Merge branch SRB2:next into fix-opengl-saturation

This commit is contained in:
Alam Ed Arias 2023-10-23 18:37:40 +00:00
commit 5a12d65150
94 changed files with 7279 additions and 6848 deletions

4
.gitattributes vendored
View file

@ -1,15 +1,17 @@
#Source code
/Makefile text=auto
/src/*.c text=auto
/src/*.h text=auto
/src/*.s text=auto
/src/*.m text=auto
/src/*.xpm text=auto
/src/Makefile text=auto
/tools/Makefile text=auto
/src/Make*.cfg text=auto
/src/CMakeLists.txt text=auto
*.mk -whitespace text=auto
# Windows EOL
*.cs -crlf -whitespace
*.mk -crlf -whitespace
*.bat -crlf -whitespace
*.dev -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)
endif
ifdef COMSPEC
OBJCOPY=objcopy.exe
OBJDUMP=objdump.exe
OBJCOPY?=objcopy.exe
OBJDUMP?=objdump.exe
GZIP?=gzip.exe
else
OBJCOPY=objcopy
OBJDUMP=objdump
OBJCOPY?=objcopy
OBJDUMP?=objdump
GZIP?=gzip
endif
DBGNAME=$(BIN).debug

View file

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

View file

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

View file

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

View file

@ -56,15 +56,18 @@ endif
# This must have high to low order.
gcc_versions:=\
102 101\
93 92 91\
84 83 82 81\
75 74 73 72 71\
64 63 62 61\
55 54 53 52 51\
132 131 130\
123 122 121 120\
114 113 112 111 110\
105 104 103 102 101 100\
95 94 93 92 91 90\
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
latest_gcc_version:=10.2
latest_gcc_version:=13.2
# Automatically set version flag, but not if one was
# 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
# also gcc outputs the information to stderr, so I had to do 2>&1
# 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
ifneq (,$(findstring gcc version,$(version)))
# 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
v:=$(subst ., ,$(version))

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -28,11 +28,12 @@
#include "byteptr.h"
#include "p_saveg.h"
#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 "p_setup.h"
#include "lua_script.h"
#include "d_netfil.h" // findfile
#include "netcode/d_netfil.h" // findfile
#include "r_data.h" // Color_cons_t
#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 "am_map.h"
#include "console.h"
#include "d_net.h"
#include "netcode/d_net.h"
#include "f_finale.h"
#include "g_game.h"
#include "hu_stuff.h"
@ -56,11 +56,11 @@
#include "w_wad.h"
#include "z_zone.h"
#include "d_main.h"
#include "d_netfil.h"
#include "netcode/d_netfil.h"
#include "m_cheat.h"
#include "y_inter.h"
#include "p_local.h" // chasecam
#include "mserv.h" // ms_RoomId
#include "netcode/mserv.h" // ms_RoomId
#include "m_misc.h" // screenshot functionality
#include "deh_tables.h" // Dehacked list test
#include "m_cond.h" // condition initialization

View file

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

View file

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

View file

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

View file

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

View file

@ -634,7 +634,7 @@ extern boolean singletics;
// Netgame stuff
// =============
#include "d_clisrv.h"
#include "netcode/d_clisrv.h"
extern consvar_t cv_timetic; // display high resolution timer
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)
{

View file

@ -14,13 +14,18 @@ size_t I_GetFreeMem(size_t *total)
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;
}
UINT64 I_GetPrecisePrecision(void) {
UINT64 I_GetPrecisePrecision(void)
{
return 1000000;
}
@ -182,10 +187,12 @@ const char *I_ClipboardPaste(void)
size_t I_GetRandomBytes(char *destination, size_t amount)
{
(void)destination;
(void)amount;
return 0;
}
void I_RegisterSysCommands(void) {}
void I_RegisterSysCommands(void){}
void I_GetCursorPosition(INT32 *x, INT32 *y)
{

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -42,10 +42,10 @@ int unsortedVertexArrayAllocSize = 65536;
// Call HWR_RenderBatches to render all the collected geometry.
void HWR_StartBatching(void)
{
if (currently_batching)
I_Error("Repeat call to HWR_StartBatching without HWR_RenderBatches");
if (currently_batching)
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)
{
finalVertexArray = malloc(finalVertexArrayAllocSize * sizeof(FOutVector));
@ -55,7 +55,7 @@ void HWR_StartBatching(void)
unsortedVertexArray = malloc(unsortedVertexArrayAllocSize * sizeof(FOutVector));
}
currently_batching = true;
currently_batching = true;
}
// 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_picformats.h"
#include "../r_bsp.h"
#include "../d_clisrv.h"
#include "../netcode/d_clisrv.h"
#include "../w_wad.h"
#include "../z_zone.h"
#include "../r_splats.h"
@ -4143,14 +4143,11 @@ static void HWR_DrawSprite(gl_vissprite_t *spr)
float xscale, yscale;
float xoffset, yoffset;
float leftoffset, topoffset;
float scale = spr->scale;
float zoffset = (P_MobjFlip(spr->mobj) * 0.05f);
pslope_t *splatslope = NULL;
INT32 i;
renderflags_t renderflags = spr->renderflags;
if (renderflags & RF_SHADOWEFFECTS)
scale *= spr->shadowscale;
if (spr->rotateflags & SRF_3D || renderflags & RF_NOSPLATBILLBOARD)
angle = spr->mobj->angle;

View file

@ -486,7 +486,7 @@ void HWR_InitModels(void)
size_t i;
INT32 s;
FILE *f;
char name[24], filename[32];
char name[26], filename[32];
float scale, offset;
size_t prefixlen;
@ -585,7 +585,7 @@ modelfound:
void HWR_AddPlayerModel(int skin) // For skins that were added after startup
{
FILE *f;
char name[24], filename[32];
char name[26], filename[32];
float scale, offset;
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
// 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
char name[24], filename[32];
char name[26], filename[32];
float scale, offset;
if (nomd2s)

View file

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

View file

@ -19,7 +19,9 @@
#include "m_cond.h" // emblems
#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_input.h"
@ -175,14 +177,12 @@ static huddrawlist_h luahuddrawlist_scores;
static tic_t resynch_ticker = 0;
#ifndef NONET
// just after
static void Command_Say_f(void);
static void Command_Sayto_f(void);
static void Command_Sayteam_f(void);
static void Command_CSay_f(void);
static void Got_Saycmd(UINT8 **p, INT32 playernum);
#endif
void HU_LoadGraphics(void)
{
@ -327,13 +327,11 @@ void HU_LoadGraphics(void)
//
void HU_Init(void)
{
#ifndef NONET
COM_AddCommand("say", Command_Say_f, COM_LUA);
COM_AddCommand("sayto", Command_Sayto_f, COM_LUA);
COM_AddCommand("sayteam", Command_Sayteam_f, COM_LUA);
COM_AddCommand("csay", Command_CSay_f, COM_LUA);
RegisterNetXCmd(XD_SAY, Got_Saycmd);
#endif
// set shift translation table
shiftxform = english_shiftxform;
@ -363,8 +361,6 @@ void HU_Start(void)
// EXECUTION
//======================================================================
#ifndef NONET
// EVERY CHANGE IN THIS SCRIPT IS LOL XD! BY VINCYTM
static UINT32 chat_nummsg_log = 0;
@ -412,11 +408,9 @@ static void HU_removeChatText_Log(void)
}
chat_nummsg_log--; // lost 1 msg.
}
#endif
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.
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.
@ -438,14 +432,8 @@ void HU_AddChatText(const char *text, boolean playsound)
CONS_Printf("%s\n", text);
else // if we aren't, still save the message to log.txt
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.
* A say command consists of a signed 8-bit integer for the target, an
* unsigned 8-bit flag variable, and then the message itself.
@ -865,8 +853,6 @@ static void Got_Saycmd(UINT8 **p, INT32 playernum)
#endif
}
#endif
//
//
void HU_Ticker(void)
@ -882,7 +868,6 @@ void HU_Ticker(void)
else
hu_showscores = false;
#ifndef NONET
if (chat_on)
{
// count down the scroll timer.
@ -910,7 +895,6 @@ void HU_Ticker(void)
HU_removeChatText_Mini();
}
}
#endif
if (cechotimer > 0) --cechotimer;
@ -918,8 +902,6 @@ void HU_Ticker(void)
resynch_ticker++;
}
#ifndef NONET
static boolean teamtalk = false;
static boolean justscrolleddown;
static boolean justscrolledup;
@ -1027,8 +1009,6 @@ static void HU_sendChatMessage(void)
}
}
#endif
void HU_clearChatChars(void)
{
memset(w_chat, '\0', sizeof(w_chat));
@ -1043,9 +1023,7 @@ void HU_clearChatChars(void)
//
boolean HU_Responder(event_t *ev)
{
#ifndef NONET
INT32 c=0;
#endif
if (ev->type != ev_keydown)
return false;
@ -1072,7 +1050,6 @@ boolean HU_Responder(event_t *ev)
return false;
}*/ //We don't actually care about that unless we get splitscreen netgames. :V
#ifndef NONET
c = (INT32)ev->key;
if (!chat_on)
@ -1222,7 +1199,6 @@ boolean HU_Responder(event_t *ev)
return true;
}
#endif
return false;
}
@ -1232,8 +1208,6 @@ boolean HU_Responder(event_t *ev)
// HEADS UP DRAWING
//======================================================================
#ifndef NONET
// Precompile a wordwrapped string to any given width.
// 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.
@ -1813,7 +1787,6 @@ static void HU_DrawChat_Old(void)
if (hu_tick < 4)
V_DrawCharacter(HU_INPUTX + c, y, '_' | cv_constextsize.value |V_NOSCALESTART|t, true);
}
#endif
// Draw crosshairs at the exact center of the view.
// 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)
{
#ifndef NONET
// draw chat string plus cursor
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)
HU_drawMiniChat(); // draw messages in a cool fashion.
}
#endif
if (cechotimer)
HU_DrawCEcho();

View file

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

View file

@ -26,11 +26,11 @@
#include "y_inter.h"
#include "hu_stuff.h" // HU_AddChatText
#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_misc.h" // M_MapNumber
#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 "lua_script.h"
@ -3544,7 +3544,7 @@ static int lib_gAddGametype(lua_State *L)
// Partly lifted from Got_AddPlayer
static int lib_gAddPlayer(lua_State *L)
{
INT16 i, newplayernum, botcount = 1;
INT16 i, newplayernum;
player_t *newplayer;
SINT8 skinnum = 0, bot;
@ -3552,10 +3552,8 @@ static int lib_gAddPlayer(lua_State *L)
{
if (!playeringame[i])
break;
if (players[i].bot)
botcount++; // How many of us are there already?
}
if (i >= MAXPLAYERS)
{
lua_pushnil(L);

View file

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

View file

@ -24,7 +24,7 @@
#include "lua_hud.h" // hud_running errors
#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
/* =========================================================================

View file

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

View file

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

View file

@ -20,7 +20,7 @@
#include "doomdef.h"
#include "d_main.h"
#include "d_netcmd.h"
#include "netcode/d_netcmd.h"
#include "console.h"
#include "r_fps.h"
#include "r_local.h"
@ -53,8 +53,10 @@
#include "hardware/hw_main.h"
#endif
#include "d_net.h"
#include "mserv.h"
#include "netcode/d_net.h"
#include "netcode/mserv.h"
#include "netcode/server_connection.h"
#include "netcode/client_connection.h"
#include "m_misc.h"
#include "m_anigif.h"
#include "byteptr.h"
@ -149,9 +151,7 @@ levellist_mode_t levellistmode = LLM_CREATESERVER;
UINT8 maplistoption = 0;
static char joystickInfo[MAX_JOYSTICKS+1][29];
#ifndef NONET
static UINT32 serverlistpage;
#endif
static UINT8 numsaves = 0;
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 boolean stopstopmessage = false;
#ifndef NONET
static void M_HandleServerPage(INT32 choice);
static void M_RoomMenu(INT32 choice);
#endif
// Prototyping is fun, innit?
// ==========================================================================
@ -296,7 +294,6 @@ static void M_SetupMultiPlayer2(INT32 choice);
static void M_StartSplitServerMenu(INT32 choice);
static void M_StartServer(INT32 choice);
static void M_ServerOptions(INT32 choice);
#ifndef NONET
static void M_StartServerMenu(INT32 choice);
static void M_ConnectMenu(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_ChooseRoom(INT32 choice);
menu_t MP_MainDef;
#endif
// Options
// Split into multiple parts due to size
@ -382,11 +378,9 @@ static void M_DrawVideoMode(void);
static void M_DrawColorMenu(void);
static void M_DrawScreenshotMenu(void);
static void M_DrawMonitorToggles(void);
#ifndef NONET
static void M_DrawConnectMenu(void);
static void M_DrawMPMainMenu(void);
static void M_DrawRoomMenu(void);
#endif
static void M_DrawJoystick(void);
static void M_DrawSetupMultiPlayerMenu(void);
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_HandleLevelStats(INT32 choice);
static void M_HandlePlaystyleMenu(INT32 choice);
#ifndef NONET
static boolean M_CancelConnect(void);
static void M_HandleConnectIP(INT32 choice);
#endif
static void M_HandleSetupMultiPlayer(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[] =
{
{IT_STRING|IT_CALL, NULL, "1 Player", M_SinglePlayerMenu, 76},
#ifndef NONET
{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_CALL |IT_STRING, NULL, "Addons", M_Addons, 100},
{IT_STRING|IT_CALL, NULL, "Options", M_Options, 108},
@ -930,16 +918,10 @@ static menuitem_t SP_PlayerMenu[] =
static menuitem_t MP_SplitServerMenu[] =
{
{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_WHITESTRING|IT_CALL, NULL, "Start", M_StartServer, 140},
};
#ifndef NONET
static menuitem_t MP_MainMenu[] =
{
{IT_HEADER, NULL, "Join a game", NULL, 0},
@ -1026,8 +1008,6 @@ menuitem_t MP_RoomMenu[] =
{IT_DISABLED, NULL, "", M_ChooseRoom, 162},
};
#endif
static menuitem_t MP_PlayerSetupMenu[] =
{
{IT_KEYHANDLER, NULL, "", M_HandleSetupMultiPlayer, 0}, // name
@ -1586,14 +1566,12 @@ enum
static menuitem_t OP_ServerOptionsMenu[] =
{
{IT_HEADER, NULL, "General", NULL, 0},
#ifndef NONET
{IT_STRING | IT_CVAR | IT_CV_STRING,
NULL, "Server name", &cv_servername, 7},
{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 players to join", &cv_allownewplayer, 31},
{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, "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, "Scramble on Map Change", &cv_scrambleonchange, 221},
#ifndef NONET
{IT_HEADER, NULL, "Advanced", NULL, 230},
{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, "Show IP Address of Joiners", &cv_showjoinaddress, 261},
#endif
};
static menuitem_t OP_MonitorToggleMenu[] =
@ -1954,11 +1930,7 @@ menu_t MP_SplitServerDef =
MTREE2(MN_MP_MAIN, MN_MP_SPLITSCREEN),
"M_MULTI",
sizeof (MP_SplitServerMenu)/sizeof (menuitem_t),
#ifndef NONET
&MP_MainDef,
#else
&MainDef,
#endif
MP_SplitServerMenu,
M_DrawServerMenu,
27, 30 - 50,
@ -1966,8 +1938,6 @@ menu_t MP_SplitServerDef =
NULL
};
#ifndef NONET
menu_t MP_MainDef =
{
MN_MP_MAIN,
@ -2019,15 +1989,10 @@ menu_t MP_RoomDef =
0,
NULL
};
#endif
menu_t MP_PlayerSetupDef =
{
#ifdef NONET
MTREE2(MN_MP_MAIN, MN_MP_PLAYERSETUP),
#else
MTREE3(MN_MP_MAIN, MN_MP_SPLITSCREEN, MN_MP_PLAYERSETUP),
#endif
"M_SPLAYR",
sizeof (MP_PlayerSetupMenu)/sizeof (menuitem_t),
&MainDef, // doesn't matter
@ -2787,6 +2752,7 @@ void M_SetMenuCurBackground(const char *defaultname)
{
char name[9];
strncpy(name, defaultname, 8);
name[8] = '\0';
M_IterateMenuTree(MIT_SetCurBackground, &name);
}
@ -3956,9 +3922,7 @@ void M_Init(void)
OP_JoystickSetMenu[i].itemaction = M_AssignJoystick;
}
#ifndef NONET
CV_RegisterVar(&cv_serversort);
#endif
}
void M_InitCharacterTables(void)
@ -11108,7 +11072,6 @@ static void M_EndGame(INT32 choice)
#define S_LINEY(n) currentMenu->y + SERVERHEADERHEIGHT + (n * SERVERLINEHEIGHT)
#ifndef NONET
static UINT32 localservercount;
static void M_HandleServerPage(INT32 choice)
@ -11380,11 +11343,9 @@ static int ServerListEntryComparator_modified(const void *entry1, const void *en
// Default to strcmp.
return strcmp(sa->info.servername, sb->info.servername);
}
#endif
void M_SortServerList(void)
{
#ifndef NONET
switch(cv_serversort.value)
{
case 0: // Ping.
@ -11406,10 +11367,8 @@ void M_SortServerList(void)
qsort(serverlist, serverlistcount, sizeof(serverelem_t), ServerListEntryComparator_gametypename);
break;
}
#endif
}
#ifndef NONET
#ifdef UPDATE_ALERT
static boolean M_CheckMODVersion(int id)
{
@ -11608,7 +11567,6 @@ static void M_ChooseRoom(INT32 choice)
if (currentMenu == &MP_ConnectDef)
M_Refresh(0);
}
#endif //NONET
//===========================================================================
// Start Server Menu
@ -11656,7 +11614,6 @@ static void M_DrawServerMenu(void)
{
M_DrawGenericMenu();
#ifndef NONET
// Room name
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_YELLOWMAP, room_list[menuRoomIndex].name);
}
#endif
if (cv_nextmap.value)
{
#ifndef NONET
#define imgheight MP_ServerMenu[mp_server_levelgt].alphaKey
#else
#define imgheight 100
#endif
patch_t *PictureOfLevel;
lumpnum_t lumpnum;
char headerstr[40];
@ -11728,7 +11680,6 @@ static void M_ServerOptions(INT32 choice)
{
(void)choice;
#ifndef NONET
if ((splitscreen && !netgame) || currentMenu == &MP_SplitServerDef)
{
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[38].status = IT_STRING | IT_CVAR;
}
#endif
/* Disable fading because of different menu head. */
if (currentMenu == &OP_MainDef)/* from Options menu */
@ -11761,7 +11711,6 @@ static void M_ServerOptions(INT32 choice)
M_SetupNextMenu(&OP_ServerOptionsDef);
}
#ifndef NONET
static void M_StartServerMenu(INT32 choice)
{
(void)choice;
@ -12028,7 +11977,6 @@ static void M_HandleConnectIP(INT32 choice)
M_ClearMenus(true);
}
}
#endif //!NONET
// ========================
// MULTIPLAYER PLAYER SETUP
@ -12705,7 +12653,7 @@ static void M_SetupMultiPlayer2(INT32 choice)
multi_frame = 0;
multi_tics = 4*FRACUNIT;
strcpy (setupm_name, cv_playername2.string);
// set for splitscreen secondary player

View file

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

View file

@ -12,7 +12,7 @@
#include "m_perfstats.h"
#include "v_video.h"
#include "i_video.h"
#include "d_netcmd.h"
#include "netcode/d_netcmd.h"
#include "r_main.h"
#include "i_system.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
/// The NOTHING packet is sent when connection is idle to acknowledge packets
#include "doomdef.h"
#include "g_game.h"
#include "i_time.h"
#include "../doomdef.h"
#include "../g_game.h"
#include "../i_time.h"
#include "i_net.h"
#include "i_system.h"
#include "m_argv.h"
#include "../i_system.h"
#include "../m_argv.h"
#include "d_net.h"
#include "w_wad.h"
#include "../w_wad.h"
#include "d_netfil.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 "d_main.h" // srb2home
#include "../d_main.h" // srb2home
//
// NETWORKING
@ -138,7 +140,6 @@ boolean Net_GetNetStat(void)
#define URGENTFREESLOTNUM 10
#define ACKTOSENDTIMEOUT (TICRATE/11)
#ifndef NONET
typedef struct
{
UINT8 acknum;
@ -152,7 +153,6 @@ typedef struct
doomdata_t data;
} pak;
} ackpak_t;
#endif
typedef enum
{
@ -160,10 +160,8 @@ typedef enum
NF_TIMEOUT = 2, // Flag is set when the node got a timeout
} node_flags_t;
#ifndef NONET
// Table of packets that were not acknowleged can be resent (the sender window)
static ackpak_t ackpak[MAXACKPACKETS];
#endif
typedef struct
{
@ -191,7 +189,6 @@ typedef struct
static node_t nodes[MAXNETNODES];
#define NODETIMEOUT 14
#ifndef NONET
// return <0 if a < b (mod 256)
// 0 if a = n (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)
{
node_t *node = &nodes[doomcom->remotenode];
INT32 i, numfreeslot = 0;
INT32 numfreeslot = 0;
if (cmpack((UINT8)((node->remotefirstack + MAXACKTOSEND) % 256), node->nextacknum) < 0)
{
@ -222,7 +219,7 @@ static boolean GetFreeAcknum(UINT8 *freeack, boolean lowtimer)
return false;
}
for (i = 0; i < MAXACKPACKETS; i++)
for (INT32 i = 0; i < MAXACKPACKETS; i++)
if (!ackpak[i].acknum)
{
// 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 i, numfreeslot = 0;
INT32 numfreeslot = 0;
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)
{
// 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
static boolean Processackpak(void)
{
INT32 i;
boolean goodpacket = true;
node_t *node = &nodes[doomcom->remotenode];
@ -327,7 +323,7 @@ static boolean Processackpak(void)
{
node->remotefirstack = netbuffer->ackreturn;
// 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
&& cmpack(ackpak[i].acknum, netbuffer->ackreturn) <= 0)
{
@ -349,7 +345,7 @@ static boolean Processackpak(void)
else
{
// 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)
{
DEBFILE(va("Discard(2) ack %d (duplicated)\n", ack));
@ -377,7 +373,7 @@ static boolean Processackpak(void)
while (change)
{
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)
{
if (cmpack(node->acktosend[i], nextfirstack) <= 0)
@ -426,28 +422,20 @@ static boolean Processackpak(void)
}
return goodpacket;
}
#endif
// send special packet with only ack on it
void Net_SendAcks(INT32 node)
{
#ifdef NONET
(void)node;
#else
netbuffer->packettype = PT_NOTHING;
M_Memcpy(netbuffer->u.textcmd, nodes[node].acktosend, MAXACKTOSEND);
HSendPacket(node, false, 0, MAXACKTOSEND);
#endif
}
#ifndef NONET
static void GotAcks(void)
{
INT32 i, j;
for (j = 0; j < MAXACKTOSEND; j++)
for (INT32 j = 0; j < MAXACKTOSEND; 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 == netbuffer->u.textcmd[j])
@ -463,7 +451,6 @@ static void GotAcks(void)
}
}
}
#endif
void Net_ConnectionTimeout(INT32 node)
{
@ -472,14 +459,10 @@ void Net_ConnectionTimeout(INT32 node)
return;
nodes[node].flags |= NF_TIMEOUT;
// Send a very special packet to self (hack the reboundstore queue)
// Main code will handle it
reboundstore[rebound_head].packettype = PT_NODETIMEOUT;
reboundstore[rebound_head].ack = 0;
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;
if (server)
SendKicksForNode(node, KICK_MSG_TIMEOUT | KICK_MSG_KEEP_BODY);
else
CL_HandleTimeout();
// Do not redo it quickly (if we do not close connection it is
// for a good reason!)
@ -489,10 +472,8 @@ void Net_ConnectionTimeout(INT32 node)
// Resend the data if needed
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;
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
if (nodes[i].firstacktosend)
@ -536,16 +517,12 @@ void Net_AckTicker(void)
}
}
}
#endif
}
// Remove last packet received ack before resending the ackreturn
// (the higher layer doesn't have room, or something else ....)
void Net_UnAcknowledgePacket(INT32 node)
{
#ifdef NONET
(void)node;
#else
INT32 hm1 = (nodes[node].acktosend_head-1+MAXACKTOSEND) % MAXACKTOSEND;
DEBFILE(va("UnAcknowledge node %d\n", node));
if (!node)
@ -577,10 +554,8 @@ void Net_UnAcknowledgePacket(INT32 node)
if (!nodes[node].firstacktosend)
nodes[node].firstacktosend = 1;
}
#endif
}
#ifndef NONET
/** Checks 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)
{
INT32 i;
for (i = 0; i < MAXACKPACKETS; i++)
for (INT32 i = 0; i < MAXACKPACKETS; i++)
if (ackpak[i].acknum)
return false;
return true;
}
#endif
/** Waits for all ackreturns
*
@ -605,9 +577,6 @@ static boolean Net_AllAcksReceived(void)
*/
void Net_WaitAllAckReceived(UINT32 timeout)
{
#ifdef NONET
(void)timeout;
#else
tic_t tictac = I_GetTime();
timeout = tictac + timeout*NEWTICRATE;
@ -623,7 +592,6 @@ void Net_WaitAllAckReceived(UINT32 timeout)
HGetPacket();
Net_AckTicker();
}
#endif
}
static void InitNode(node_t *node)
@ -637,14 +605,10 @@ static void InitNode(node_t *node)
static void InitAck(void)
{
INT32 i;
#ifndef NONET
for (i = 0; i < MAXACKPACKETS; i++)
for (INT32 i = 0; i < MAXACKPACKETS; i++)
ackpak[i].acknum = 0;
#endif
for (i = 0; i < MAXNETNODES; i++)
for (INT32 i = 0; i < MAXNETNODES; i++)
InitNode(&nodes[i]);
}
@ -655,17 +619,12 @@ static void InitAck(void)
*/
void Net_AbortPacketType(UINT8 packettype)
{
#ifdef NONET
(void)packettype;
#else
INT32 i;
for (i = 0; i < MAXACKPACKETS; i++)
for (INT32 i = 0; i < MAXACKPACKETS; i++)
if (ackpak[i].acknum && (ackpak[i].pak.data.packettype == packettype
|| packettype == UINT8_MAX))
{
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
void Net_CloseConnection(INT32 node)
{
#ifdef NONET
(void)node;
#else
INT32 i;
boolean forceclose = (node & FORCECLOSE) != 0;
if (node == -1)
@ -708,7 +663,7 @@ void Net_CloseConnection(INT32 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 (!forceclose)
@ -722,10 +677,8 @@ void Net_CloseConnection(INT32 node)
if (server)
SV_AbortLuaFileTransfer(node);
I_NetFreeNodenum(node);
#endif
}
#ifndef NONET
//
// Checksum
//
@ -734,23 +687,20 @@ static UINT32 NetbufferChecksum(void)
UINT32 c = 0x1234567;
const INT32 l = doomcom->datalength - 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);
return LONG(c);
}
#endif
#ifdef DEBUGFILE
static void fprintfstring(char *s, size_t len)
{
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 (!mode)
@ -810,6 +760,8 @@ static const char *packettypename[NUMPACKETTYPE] =
"ASKLUAFILE",
"HASLUAFILE",
"PT_BASICKEEPALIVE",
"FILEFRAGMENT",
"FILEACK",
"FILERECEIVED",
@ -817,7 +769,6 @@ static const char *packettypename[NUMPACKETTYPE] =
"TEXTCMD",
"TEXTCMD2",
"CLIENTJOIN",
"NODETIMEOUT",
"LOGIN",
"TELLFILESNEEDED",
"MOREFILESNEEDED",
@ -921,7 +872,6 @@ void Command_Drop(void)
{
INT32 packetquantity;
const char *packetname;
size_t i;
if (COM_Argc() < 2)
{
@ -951,11 +901,11 @@ void Command_Drop(void)
packetname = COM_Argv(1);
if (!(stricmp(packetname, "all") && stricmp(packetname, "any")))
for (i = 0; i < NUMPACKETTYPE; i++)
for (size_t i = 0; i < NUMPACKETTYPE; i++)
packetdropquantity[i] = packetquantity;
else
{
for (i = 0; i < NUMPACKETTYPE; i++)
for (size_t i = 0; i < NUMPACKETTYPE; i++)
if (!stricmp(packetname, packettypename[i]))
{
packetdropquantity[i] = packetquantity;
@ -986,14 +936,12 @@ void Command_Droprate(void)
packetdroprate = droprate;
}
#ifndef NONET
static boolean ShouldDropPacket(void)
{
return (packetdropquantity[netbuffer->packettype])
|| (packetdroprate != 0 && rand() < (RAND_MAX * (packetdroprate / 100.f))) || packetdroprate == 100;
}
#endif
#endif
//
// HSendPacket
@ -1028,11 +976,6 @@ boolean HSendPacket(INT32 node, boolean reliable, UINT8 acknum, size_t packetlen
if (!netgame)
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
// the current packet
doomcom->remotenode = (INT16)node;
@ -1093,8 +1036,6 @@ boolean HSendPacket(INT32 node, boolean reliable, UINT8 acknum, size_t packetlen
}
#endif
#endif // ndef NONET
return true;
}
@ -1112,10 +1053,7 @@ boolean HGetPacket(void)
{
M_Memcpy(netbuffer, &reboundstore[rebound_tail], reboundsize[rebound_tail]);
doomcom->datalength = reboundsize[rebound_tail];
if (netbuffer->packettype == PT_NODETIMEOUT)
doomcom->remotenode = netbuffer->u.textcmd[0];
else
doomcom->remotenode = 0;
doomcom->remotenode = 0;
rebound_tail = (rebound_tail+1) % MAXREBOUND;
#ifdef DEBUGFILE
@ -1128,8 +1066,6 @@ boolean HGetPacket(void)
if (!netgame)
return false;
#ifndef NONET
while(true)
{
//nodejustjoined = I_NetGet();
@ -1189,7 +1125,6 @@ boolean HGetPacket(void)
}
break;
}
#endif // ndef NONET
return true;
}
@ -1399,13 +1334,12 @@ void Command_Ping_f(void)
int name_width = 0;
int ms_width = 0;
int n;
INT32 i;
pingc = 0;
for (i = 1; i < MAXPLAYERS; ++i)
for (INT32 i = 1; i < MAXPLAYERS; ++i)
if (playeringame[i])
{
int n;
n = strlen(player_names[i]);
if (n > name_width)
name_width = n;
@ -1425,7 +1359,7 @@ void Command_Ping_f(void)
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",
pingv[i].num,
@ -1441,15 +1375,13 @@ void Command_Ping_f(void)
void D_CloseConnection(void)
{
INT32 i;
if (netgame)
{
// wait the ackreturn with timout of 5 Sec
Net_WaitAllAckReceived(5);
// close all connection
for (i = 0; i < MAXNETNODES; i++)
for (INT32 i = 0; i < MAXNETNODES; i++)
Net_CloseConnection(i|FORCECLOSE);
InitAck();

View file

@ -18,6 +18,8 @@
#ifndef __D_NET__
#define __D_NET__
#include "../doomtype.h"
// Max computers in a game
// 127 is probably as high as this can go, because
// SINT8 is used for nodes sometimes >:(
@ -37,10 +39,24 @@ boolean Net_GetNetStat(void);
extern INT32 getbytes;
extern INT64 sendbytes; // Realtime updated
extern SINT8 nodetoplayer[MAXNETNODES];
extern SINT8 nodetoplayer2[MAXNETNODES]; // Say the numplayer for this node if any (splitscreen)
extern UINT8 playerpernode[MAXNETNODES]; // Used specially for splitscreen
extern boolean nodeingame[MAXNETNODES]; // Set false as nodes leave game
typedef struct netnode_s
{
boolean ingame; // 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;
@ -52,9 +68,6 @@ boolean HSendPacket(INT32 node, boolean reliable, UINT8 acknum,
size_t packetlength);
boolean HGetPacket(void);
void D_SetDoomcom(void);
#ifndef NONET
void D_SaveBan(void);
#endif
boolean D_CheckNetGame(void);
void D_CloseConnection(void);
void Net_UnAcknowledgePacket(INT32 node);

View file

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

View file

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

View file

@ -31,24 +31,25 @@
#include <sys/utime.h>
#endif
#include "doomdef.h"
#include "doomstat.h"
#include "d_main.h"
#include "g_game.h"
#include "i_time.h"
#include "../doomdef.h"
#include "../doomstat.h"
#include "../d_main.h"
#include "../g_game.h"
#include "../i_time.h"
#include "i_net.h"
#include "i_system.h"
#include "m_argv.h"
#include "../i_system.h"
#include "../m_argv.h"
#include "d_net.h"
#include "w_wad.h"
#include "../w_wad.h"
#include "d_netfil.h"
#include "z_zone.h"
#include "byteptr.h"
#include "p_setup.h"
#include "m_misc.h"
#include "m_menu.h"
#include "md5.h"
#include "filesrch.h"
#include "net_command.h"
#include "../z_zone.h"
#include "../byteptr.h"
#include "../p_setup.h"
#include "../m_misc.h"
#include "../m_menu.h"
#include "../md5.h"
#include "../filesrch.h"
#include <errno.h>
@ -103,26 +104,31 @@ typedef struct
} pauseddownload_t;
static pauseddownload_t *pauseddownload = NULL;
#ifndef NONET
// for cl loading screen
INT32 lastfilenum = -1;
INT32 downloadcompletednum = 0;
UINT32 downloadcompletedsize = 0;
INT32 totalfilesrequestednum = 0;
UINT32 totalfilesrequestedsize = 0;
#endif
luafiletransfer_t *luafiletransfers = NULL;
boolean waitingforluafiletransfer = false;
boolean waitingforluafilecommand = false;
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)
{
UINT16 wadnum;
for (wadnum = mainwads; wadnum < numwadfiles; wadnum++)
for (UINT16 wadnum = mainwads; wadnum < numwadfiles; wadnum++)
{
if (!wadfiles[wadnum]->important)
continue;
@ -142,14 +148,13 @@ static UINT16 GetWadNumFromFileNeededId(UINT8 id)
*/
UINT8 *PutFileNeeded(UINT16 firstfile)
{
size_t i;
UINT8 count = 0;
UINT8 *p_start = netbuffer->packettype == PT_MOREFILESNEEDED ? netbuffer->u.filesneededcfg.files : netbuffer->u.serverinfo.fileneeded;
UINT8 *p = p_start;
char wadfilename[MAX_WADPATH] = "";
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 (!wadfiles[i]->important)
@ -224,7 +229,6 @@ void FreeFileNeeded(void)
*/
void D_ParseFileneeded(INT32 fileneedednum_parm, UINT8 *fileneededstr, UINT16 firstfile)
{
INT32 i;
UINT8 *p;
UINT8 filestatus;
@ -233,7 +237,7 @@ void D_ParseFileneeded(INT32 fileneedednum_parm, UINT8 *fileneededstr, UINT16 fi
AllocFileNeeded(fileneedednum);
for (i = firstfile; i < fileneedednum; i++)
for (INT32 i = firstfile; i < fileneedednum; i++)
{
fileneeded[i].type = FILENEEDED_WAD;
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)
{
#ifndef NONET
lastfilenum = -1;
#endif
FreeFileNeeded();
AllocFileNeeded(1);
@ -275,9 +277,9 @@ void CL_PrepareDownloadSaveGame(const char *tmpsave)
*/
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].willsend == 1)
@ -298,7 +300,7 @@ boolean CL_CheckDownloadable(void)
// not downloadable, put reason in console
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)
{
CONS_Printf(" * \"%s\" (%dK)", fileneeded[i].filename, fileneeded[i].totalsize >> 10);
@ -368,14 +370,13 @@ void CL_AbortDownloadResume(void)
boolean CL_SendFileRequest(void)
{
char *p;
INT32 i;
INT64 totalfreespaceneeded = 0, availablefreespace;
#ifdef PARANOIA
if (M_CheckParm("-nodownload"))
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
&& (fileneeded[i].willsend == 0 || fileneeded[i].willsend == 2))
{
@ -385,7 +386,7 @@ boolean CL_SendFileRequest(void)
netbuffer->packettype = PT_REQUESTFILE;
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))
{
totalfreespaceneeded += fileneeded[i].totalsize;
@ -413,26 +414,31 @@ boolean CL_SendFileRequest(void)
}
// get request filepak and put it on the send queue
// returns false if a requested file was not found or cannot be sent
boolean PT_RequestFile(INT32 node)
void PT_RequestFile(SINT8 node)
{
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
{
id = READUINT8(p);
UINT8 id = READUINT8(p);
if (id == 0xFF)
break;
if (!AddFileToSendQueue(node, id))
{
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
@ -531,9 +537,7 @@ INT32 CL_CheckFiles(void)
// Load it now
boolean CL_LoadServerFiles(void)
{
INT32 i;
for (i = 0; i < fileneedednum; i++)
for (INT32 i = 0; i < fileneedednum; i++)
{
if (fileneeded[i].status == FS_OPEN)
continue; // Already loaded
@ -629,11 +633,10 @@ void AddLuaFileTransfer(const char *filename, const char *mode)
static void SV_PrepareSendLuaFileToNextNode(void)
{
INT32 i;
UINT8 success = 1;
// 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
{
// Tell the client we're about to send them the file
@ -655,13 +658,12 @@ static void SV_PrepareSendLuaFileToNextNode(void)
void SV_PrepareSendLuaFile(void)
{
char *binfilename;
INT32 i;
luafiletransfers->ongoing = true;
// Set status to "waiting" for everyone
for (i = 0; i < MAXNETNODES; i++)
luafiletransfers->nodestatus[i] = (nodeingame[i] ? LFTNS_WAITING : LFTNS_NONE);
for (INT32 i = 0; i < MAXNETNODES; i++)
luafiletransfers->nodestatus[i] = (netnodes[i].ingame ? LFTNS_WAITING : LFTNS_NONE);
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;
INT32 node = doomcom->remotenode;
filetran_t *trans = &transfer[node];
INT32 i, j;
if (client)
return;
// Wrong file id? Ignore it, it's probably a late packet
if (!(trans->txlist && packet->fileid == trans->txlist->fileid))
@ -1161,11 +1164,11 @@ void PT_FileAck(void)
trans->dontsenduntil = 0;
}
for (i = 0; i < packet->numsegments; i++)
for (INT32 i = 0; i < packet->numsegments; 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->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)
SV_EndFileSend(doomcom->remotenode);
if (server && trans && netbuffer->u.filereceived == trans->fileid)
SV_EndFileSend(node);
}
static void SendAckPacket(fileack_pak *packet, UINT8 fileid)
{
size_t packetsize;
INT32 i;
packetsize = sizeof(*packet) + packet->numsegments * sizeof(*packet->segments);
// Finalise the packet
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].acks = LONG(packet->segments[i].acks);
@ -1247,9 +1249,7 @@ static void AddFragmentToAckPacket(fileack_pak *packet, UINT8 iteration, UINT32
void FileReceiveTicker(void)
{
INT32 i;
for (i = 0; i < fileneedednum; i++)
for (INT32 i = 0; i < fileneedednum; i++)
{
fileneeded_t *file = &fileneeded[i];
@ -1263,8 +1263,7 @@ void FileReceiveTicker(void)
if (file->ackresendposition != UINT32_MAX && file->status == FS_DOWNLOADING)
{
// Acknowledge ~70 MB/s, whichs means the client sends ~18 KB/s
INT32 j;
for (j = 0; j < 2048; j++)
for (INT32 j = 0; j < 2048; j++)
{
if (file->receivedfragments[file->ackresendposition])
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;
fileneeded_t *file = &fileneeded[filenum];
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);
}
#ifndef NONET
lastfilenum = filenum;
#endif
}
/** \brief Checks if a node is downloading a file
@ -1469,15 +1485,14 @@ void SV_AbortSendFiles(INT32 node)
void CloseNetFile(void)
{
INT32 i;
// Is sending?
for (i = 0; i < MAXNETNODES; i++)
for (INT32 i = 0; i < MAXNETNODES; i++)
SV_AbortSendFiles(i);
// Receiving a file?
if (fileneeded)
{
for (i = 0; i < fileneedednum; i++)
for (INT32 i = 0; i < fileneedednum; i++)
if (fileneeded[i].status == FS_DOWNLOADING && fileneeded[i].file)
{
fclose(fileneeded[i].file);
@ -1510,9 +1525,7 @@ void CloseNetFile(void)
void Command_Downloads_f(void)
{
INT32 node;
for (node = 0; node < MAXNETNODES; node++)
for (INT32 node = 0; node < MAXNETNODES; node++)
if (transfer[node].txlist
&& transfer[node].txlist->ram == SF_FILE) // Node is downloading a file?
{
@ -1546,14 +1559,11 @@ void Command_Downloads_f(void)
void nameonly(char *s)
{
size_t j, len;
void *ns;
for (j = strlen(s); j != (size_t)-1; j--)
for (size_t j = strlen(s); j != (size_t)-1; j--)
if ((s[j] == '\\') || (s[j] == ':') || (s[j] == '/'))
{
ns = &(s[j+1]);
len = strlen(ns);
void *ns = &(s[j+1]);
size_t len = strlen(ns);
#if 0
M_Memcpy(s, ns, len+1);
#else
@ -1566,9 +1576,9 @@ void nameonly(char *s)
// Returns the length in characters of the last element of a path.
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] == '/'))
return len - j - 1;

View file

@ -15,7 +15,7 @@
#include "d_net.h"
#include "d_clisrv.h"
#include "w_wad.h"
#include "../w_wad.h"
typedef enum
{
@ -70,13 +70,13 @@ extern INT32 fileneedednum;
extern fileneeded_t *fileneeded;
extern char downloaddir[512];
#ifndef NONET
extern INT32 lastfilenum;
extern INT32 downloadcompletednum;
extern UINT32 downloadcompletedsize;
extern INT32 totalfilesrequestednum;
extern UINT32 totalfilesrequestedsize;
#endif
extern consvar_t cv_maxsend, cv_noticedownload, cv_downloadspeed;
void AllocFileNeeded(INT32 size);
void FreeFileNeeded(void);
@ -90,16 +90,16 @@ void AddRamToSendQueue(INT32 node, void *data, size_t size, freemethod_t freemet
UINT8 fileid);
void FileSendTicker(void);
void PT_FileAck(void);
void PT_FileReceived(void);
void PT_FileAck(SINT8 node);
void PT_FileReceived(SINT8 node);
boolean SendingFile(INT32 node);
void FileReceiveTicker(void);
void PT_FileFragment(void);
void PT_FileFragment(SINT8 node, INT32 netconsole);
boolean CL_CheckDownloadable(void);
boolean CL_SendFileRequest(void);
boolean PT_RequestFile(INT32 node);
void PT_RequestFile(SINT8 node);
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>
#endif
#include "doomdef.h"
#include "../doomdef.h"
#include "d_clisrv.h"
#include "command.h"
#include "m_argv.h"
#include "m_menu.h"
#include "client_connection.h"
#include "../command.h"
#include "../m_argv.h"
#include "../m_menu.h"
#include "mserv.h"
#include "i_tcp.h"/* for current_port */
#include "i_threads.h"
#include "../i_threads.h"
/* reasonable default I guess?? */
#define DEFAULT_BUFFER_SIZE (4096)
@ -95,7 +96,7 @@ init_user_agent_once(void)
{
if (hms_useragent[0] != '\0')
return;
get_user_agent(hms_useragent, 512);
}

View file

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

View file

@ -36,109 +36,100 @@
#include <ws2tcpip.h>
#endif
#include "doomdef.h"
#include "../doomdef.h"
#if defined (NOMD5) && !defined (NONET)
//#define NONET
#ifdef USE_WINSOCK1
#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
#ifdef NONET
#undef HAVE_MINIUPNPC
#else
#ifdef USE_WINSOCK1
#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
#ifdef USE_WINSOCK
// some undefined under win32
#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
#ifdef USE_WINSOCK
// some undefined under win32
#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;
#define EWOULDBLOCK WSAEWOULDBLOCK
#ifdef EMSGSIZE
#undef EMSGSIZE
#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
#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
typedef union
{
struct sockaddr any;
struct sockaddr_in ip4;
#ifdef HAVE_IPV6
struct sockaddr_in6 ip6;
#endif
} mysockaddr_t;
#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
#include "i_system.h"
#include "../i_system.h"
#include "i_net.h"
#include "d_net.h"
#include "d_netfil.h"
#include "i_tcp.h"
#include "m_argv.h"
#include "../m_argv.h"
#include "doomstat.h"
#include "../doomstat.h"
// win32
#ifdef USE_WINSOCK
@ -151,7 +142,7 @@
#define SELECTTEST
#define DEFAULTPORT "5029"
#if defined (USE_WINSOCK) && !defined (NONET)
#ifdef USE_WINSOCK
typedef SOCKET SOCKET_TYPE;
#define ERRSOCKET (SOCKET_ERROR)
#else
@ -163,22 +154,20 @@
#define ERRSOCKET (-1)
#endif
#ifndef NONET
// define socklen_t in DOS/Windows if it is not already defined
#ifdef USE_WINSOCK1
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];
// define socklen_t in DOS/Windows if it is not already defined
#ifdef USE_WINSOCK1
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];
static size_t numbans = 0;
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 *clientport_name;/* any port */
#ifndef NONET
#ifdef USE_WINSOCK
// stupid microsoft makes things complicated
static char *get_WSAErrorStr(int e)
@ -387,47 +375,33 @@ static const char *SOCK_AddrToStr(mysockaddr_t *sk)
#endif
return s;
}
#endif
static const char *SOCK_GetNodeAddress(INT32 node)
{
if (node == 0)
return "self";
#ifdef NONET
return NULL;
#else
if (!nodeconnected[node])
return NULL;
return SOCK_AddrToStr(&clientaddress[node]);
#endif
}
static const char *SOCK_GetBanAddress(size_t ban)
{
if (ban >= numbans)
return NULL;
#ifdef NONET
return NULL;
#else
return SOCK_AddrToStr(&banned[ban]);
#endif
}
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
if (ban >= numbans)
return NULL;
if (sprintf(s,"%d",bannedmask[ban]) > 0)
return s;
#endif
return NULL;
}
#ifndef NONET
static boolean SOCK_cmpaddr(mysockaddr_t *a, mysockaddr_t *b, UINT8 mask)
{
UINT32 bitmask = INADDR_NONE;
@ -455,24 +429,20 @@ static boolean SOCK_cmpaddr(mysockaddr_t *a, mysockaddr_t *b, UINT8 mask)
*/
static void cleanupnodes(void)
{
SINT8 j;
if (!Playing())
return;
// Why can't I start at zero?
for (j = 1; j < MAXNETNODES; j++)
if (!(nodeingame[j] || SendingFile(j)))
for (SINT8 j = 1; j < MAXNETNODES; j++)
if (!(netnodes[j].ingame || SendingFile(j)))
nodeconnected[j] = false;
}
static SINT8 getfreenode(void)
{
SINT8 j;
cleanupnodes();
for (j = 0; j < MAXNETNODES; j++)
for (SINT8 j = 0; j < MAXNETNODES; j++)
if (!nodeconnected[j])
{
nodeconnected[j] = true;
@ -485,8 +455,8 @@ static SINT8 getfreenode(void)
* downloading a needed wad, but it's better than not letting anyone join...
*/
/*I_Error("No more free nodes!!1!11!11!!1111\n");
for (j = 1; j < MAXNETNODES; j++)
if (!nodeingame[j])
for (SINT8 j = 1; j < MAXNETNODES; j++)
if (!netnodes[j].ingame)
return j;*/
return -1;
@ -497,28 +467,27 @@ void Command_Numnodes(void)
{
INT32 connected = 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;
if (nodeconnected[i])
connected++;
if (nodeingame[i])
if (netnodes[i].ingame)
ingame++;
CONS_Printf("%2d - ", i);
if (nodetoplayer[i] != -1)
CONS_Printf("player %.2d", nodetoplayer[i]);
if (netnodes[i].player != -1)
CONS_Printf("player %.2d", netnodes[i].player);
else
CONS_Printf(" ");
if (nodeconnected[i])
CONS_Printf(" - connected");
else
CONS_Printf(" - ");
if (nodeingame[i])
if (netnodes[i].ingame)
CONS_Printf(" - ingame");
else
CONS_Printf(" - ");
@ -531,19 +500,17 @@ void Command_Numnodes(void)
connected, ingame);
}
#endif
#endif
#ifndef NONET
// Returns true if a packet was received from a new node, false in all other cases
static boolean SOCK_Get(void)
{
size_t i, n;
size_t i;
int j;
ssize_t c;
mysockaddr_t fromaddress;
socklen_t fromlen;
for (n = 0; n < mysocketses; n++)
for (size_t n = 0; n < mysocketses; n++)
{
fromlen = (socklen_t)sizeof(fromaddress);
c = recvfrom(mysockets[n], (char *)&doomcom->data, MAXPACKETLENGTH, 0,
@ -596,20 +563,17 @@ static boolean SOCK_Get(void)
doomcom->remotenode = -1; // no packet
return false;
}
#endif
// check if we can send (do not go over the buffer)
#ifndef NONET
static fd_set masterset;
#ifdef SELECTTEST
static boolean FD_CPY(fd_set *src, fd_set *dst, SOCKET_TYPE *fd, size_t len)
{
size_t i;
boolean testset = false;
FD_ZERO(dst);
for (i = 0; i < len;i++)
for (size_t i = 0; i < len;i++)
{
if(fd[i] != (SOCKET_TYPE)ERRSOCKET &&
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;
}
#endif
#endif
#ifndef NONET
static inline ssize_t SOCK_SendToAddr(SOCKET_TYPE socket, mysockaddr_t *sockaddr)
{
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)
{
ssize_t c = ERRSOCKET;
size_t i, j;
if (!nodeconnected[doomcom->remotenode])
return;
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)
SOCK_SendToAddr(mysockets[i], &broadcastaddress[j]);
@ -694,7 +655,7 @@ static void SOCK_Send(void)
}
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)
SOCK_SendToAddr(mysockets[i], &clientaddress[doomcom->remotenode]);
@ -714,9 +675,7 @@ static void SOCK_Send(void)
SOCK_GetNodeAddress(doomcom->remotenode), e, strerror(e));
}
}
#endif
#ifndef NONET
static void SOCK_FreeNodenum(INT32 numnode)
{
// can't disconnect from self :)
@ -731,12 +690,10 @@ static void SOCK_FreeNodenum(INT32 numnode)
// put invalid address
memset(&clientaddress[numnode], 0, sizeof (clientaddress[numnode]));
}
#endif
//
// UDPsocket
//
#ifndef NONET
// allocate a socket
static SOCKET_TYPE UDP_Bind(int family, struct sockaddr *addr, socklen_t addrlen)
@ -1061,12 +1018,10 @@ static boolean UDP_Socket(void)
return true;
}
#endif
boolean I_InitTcpDriver(void)
{
boolean tcp_was_up = init_tcp_driver;
#ifndef NONET
if (!init_tcp_driver)
{
#ifdef USE_WINSOCK
@ -1121,7 +1076,7 @@ boolean I_InitTcpDriver(void)
#endif
init_tcp_driver = true;
}
#endif
if (!tcp_was_up && init_tcp_driver)
{
I_AddExitFunc(I_ShutdownTcpDriver);
@ -1135,11 +1090,9 @@ boolean I_InitTcpDriver(void)
return init_tcp_driver;
}
#ifndef NONET
static void SOCK_CloseSocket(void)
{
size_t i;
for (i=0; i < MAXNETNODES+1; i++)
for (size_t i=0; i < MAXNETNODES+1; i++)
{
if (mysockets[i] != (SOCKET_TYPE)ERRSOCKET
&& FD_ISSET(mysockets[i], &masterset))
@ -1150,11 +1103,9 @@ static void SOCK_CloseSocket(void)
mysockets[i] = ERRSOCKET;
}
}
#endif
void I_ShutdownTcpDriver(void)
{
#ifndef NONET
SOCK_CloseSocket();
CONS_Printf("I_ShutdownTcpDriver: ");
@ -1164,10 +1115,8 @@ void I_ShutdownTcpDriver(void)
#endif
CONS_Printf("shut down\n");
init_tcp_driver = false;
#endif
}
#ifndef NONET
static SINT8 SOCK_NetMakeNodewPort(const char *address, const char *port)
{
SINT8 newnode = -1;
@ -1223,17 +1172,13 @@ static SINT8 SOCK_NetMakeNodewPort(const char *address, const char *port)
I_freeaddrinfo(ai);
return newnode;
}
#endif
static boolean SOCK_OpenSocket(void)
{
#ifndef NONET
size_t i;
memset(clientaddress, 0, sizeof (clientaddress));
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[BROADCASTADDR] = true;
I_NetSend = SOCK_Send;
@ -1251,18 +1196,12 @@ static boolean SOCK_OpenSocket(void)
// build the socket but close it first
SOCK_CloseSocket();
return UDP_Socket();
#else
return false;
#endif
}
static boolean SOCK_Ban(INT32 node)
{
if (node > MAXNETNODES)
return false;
#ifdef NONET
return false;
#else
if (numbans == MAXBANS)
return false;
@ -1281,16 +1220,10 @@ static boolean SOCK_Ban(INT32 node)
#endif
numbans++;
return true;
#endif
}
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;
int gaie;
@ -1335,7 +1268,6 @@ static boolean SOCK_SetBanAddress(const char *address, const char *mask)
I_freeaddrinfo(ai);
return true;
#endif
}
static void SOCK_ClearBans(void)

View file

@ -15,13 +15,14 @@
#include <time.h>
#endif
#include "doomstat.h"
#include "doomdef.h"
#include "command.h"
#include "i_threads.h"
#include "../doomstat.h"
#include "../doomdef.h"
#include "../command.h"
#include "../i_threads.h"
#include "mserv.h"
#include "m_menu.h"
#include "z_zone.h"
#include "client_connection.h"
#include "../m_menu.h"
#include "../z_zone.h"
#ifdef MASTERSERVER
@ -45,9 +46,7 @@ static I_cond MSCond;
# define Unlock_state()
#endif/*HAVE_THREADS*/
#ifndef NONET
static void Command_Listserv_f(void);
#endif
#endif/*MASTERSERVER*/
@ -89,7 +88,6 @@ msg_rooms_t room_list[NUM_LIST_ROOMS+1]; // +1 for easy test
*/
void AddMServCommands(void)
{
#ifndef NONET
CV_RegisterVar(&cv_masterserver);
CV_RegisterVar(&cv_masterserver_update_rate);
CV_RegisterVar(&cv_masterserver_timeout);
@ -100,7 +98,6 @@ void AddMServCommands(void)
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
#endif
#endif
}
#ifdef MASTERSERVER
@ -189,7 +186,6 @@ void GetMODVersion_Console(void)
}
#endif
#ifndef NONET
/** Gets a list of game servers. Called from console.
*/
static void Command_Listserv_f(void)
@ -200,7 +196,6 @@ static void Command_Listserv_f(void)
HMS_list_servers();
}
}
#endif
static void
Finish_registration (void)

View file

@ -14,7 +14,7 @@
#ifndef _MSERV_H_
#define _MSERV_H_
#include "i_threads.h"
#include "../i_threads.h"
// lowered from 32 due to menu changes
#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.
// See the 'LICENSE' file for more details.
//-----------------------------------------------------------------------------
/// \file d_clisrv.h
/// \brief high level networking stuff
/// \file protocol.h
/// \brief Data exchanged through the network
#ifndef __D_CLISRV__
#define __D_CLISRV__
#ifndef __PROTOCOL__
#define __PROTOCOL__
#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"
#include "../d_ticcmd.h"
#include "../doomdef.h"
/*
The 'packet version' is used to distinguish packet
@ -38,10 +34,9 @@ therein, increment this number.
// one that defines the actual packets to
// be transmitted.
// Networking and tick handling related.
#define BACKUPTICS 1024
#define CLIENTBACKUPTICS 32
#define MAXTEXTCMD 256
//
// Packet structure
//
@ -77,7 +72,7 @@ typedef enum
PT_ASKLUAFILE, // Client telling the server they don't 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.
@ -92,7 +87,6 @@ typedef enum
PT_TEXTCMD, // Extra text commands from the client.
PT_TEXTCMD2, // Splitscreen text commands.
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.
@ -103,14 +97,6 @@ typedef enum
NUMPACKETTYPE
} packettype_t;
#ifdef PACKETDROP
void Command_Drop(void);
void Command_Droprate(void);
#endif
#ifdef _DEBUG
void Command_Numnodes(void);
#endif
#if defined(_MSC_VER)
#pragma pack(1)
#endif
@ -139,13 +125,12 @@ typedef struct
#endif
// Server to client packet
// this packet is too large
typedef struct
{
tic_t starttic;
UINT8 numtics;
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;
typedef struct
@ -215,6 +200,7 @@ enum {
#define MAXSERVERNAME 32
#define MAXFILENEEDED 915
// This packet is too large
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.
UINT32 score;
UINT16 timeinserver; // In seconds.
} ATTRPACK plrinfo;
} ATTRPACK plrinfo_pak;
// Shortest player information for join during intermission.
typedef struct
@ -286,7 +272,7 @@ typedef struct
UINT32 pflags;
UINT32 score;
UINT8 ctfteam;
} ATTRPACK plrconfig;
} ATTRPACK plrconfig_pak;
typedef struct
{
@ -309,25 +295,25 @@ typedef struct
UINT8 reserved; // Padding
union
{
clientcmd_pak clientpak; // 144 bytes
client2cmd_pak client2pak; // 200 bytes
servertics_pak serverpak; // 132495 bytes (more around 360, no?)
serverconfig_pak servercfg; // 773 bytes
UINT8 textcmd[MAXTEXTCMD+1]; // 66049 bytes (wut??? 64k??? More like 257 bytes...)
filetx_pak filetxpak; // 139 bytes
clientcmd_pak clientpak;
client2cmd_pak client2pak;
servertics_pak serverpak;
serverconfig_pak servercfg;
UINT8 textcmd[MAXTEXTCMD+1];
filetx_pak filetxpak;
fileack_pak fileack;
UINT8 filereceived;
clientconfig_pak clientcfg; // 136 bytes
clientconfig_pak clientcfg;
UINT8 md5sum[16];
serverinfo_pak serverinfo; // 1024 bytes
serverrefuse_pak serverrefuse; // 65025 bytes (somehow I feel like those values are garbage...)
askinfo_pak askinfo; // 61 bytes
msaskinfo_pak msaskinfo; // 22 bytes
plrinfo playerinfo[MAXPLAYERS]; // 576 bytes(?)
plrconfig playerconfig[MAXPLAYERS]; // (up to) 528 bytes(?)
INT32 filesneedednum; // 4 bytes
filesneededconfig_pak filesneededcfg; // ??? bytes
UINT32 pingtable[MAXPLAYERS+1]; // 68 bytes
serverinfo_pak serverinfo;
serverrefuse_pak serverrefuse;
askinfo_pak askinfo;
msaskinfo_pak msaskinfo;
plrinfo_pak playerinfo[MAXPLAYERS];
plrconfig_pak playerconfig[MAXPLAYERS];
INT32 filesneedednum;
filesneededconfig_pak filesneededcfg;
UINT32 pingtable[MAXPLAYERS+1];
} u; // This is needed to pack diff packet types data together
} ATTRPACK doomdata_t;
@ -335,26 +321,7 @@ typedef struct
#pragma pack()
#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 BASESERVERTICSSIZE offsetof(doomdata_t, u.serverpak.cmds[0])
#define KICK_MSG_GO_AWAY 1
#define KICK_MSG_CON_FAIL 2
@ -366,107 +333,4 @@ extern consvar_t cv_playbackspeed;
#define KICK_MSG_CUSTOM_BAN 8
#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

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 "s_sound.h"
#include "z_zone.h"
#include "d_netcmd.h"
#include "netcode/d_netcmd.h"
// ==========================================================================
// CEILINGS

View file

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

View file

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

View file

@ -3730,7 +3730,9 @@ void P_SlideMove(mobj_t *mo)
boolean papercol = false;
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)
{

View file

@ -36,6 +36,7 @@
#include "p_slopes.h"
#include "f_finale.h"
#include "m_cond.h"
#include "netcode/net_command.h"
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);

View file

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

View file

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

View file

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

View file

@ -249,7 +249,7 @@ static void FlipCam2_OnChange(void)
//
// 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)
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);
// Try to quickly decide by looking at sign bits.
if ((node->dy ^ node->dx ^ dx ^ dy) < 0)
return (node->dy ^ dx) < 0; // (left is negative)
return FixedMul(dy, node->dx>>FRACBITS) >= FixedMul(node->dy>>FRACBITS, dx);
// also use a mask to avoid branch prediction
INT32 mask = (node->dy ^ node->dx ^ dx ^ dy) >> 31;
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

View file

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

View file

@ -34,7 +34,7 @@
#include "p_tick.h"
#include "p_local.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
#ifdef HWRENDER
#include "hardware/hw_md2.h"

View file

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

View file

@ -262,7 +262,6 @@
<ClInclude Include="..\u_list.h" />
<ClInclude Include="..\hu_stuff.h" />
<ClInclude Include="..\info.h" />
<ClInclude Include="..\i_addrinfo.h" />
<ClInclude Include="..\i_joy.h" />
<ClInclude Include="..\i_net.h" />
<ClInclude Include="..\i_sound.h" />
@ -297,6 +296,21 @@
<ClInclude Include="..\m_queue.h" />
<ClInclude Include="..\m_random.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="..\p_haptic.h" />
<ClInclude Include="..\p_local.h" />
@ -329,6 +343,7 @@
<ClInclude Include="..\r_textures.h" />
<ClInclude Include="..\r_things.h" />
<ClInclude Include="..\screen.h" />
<ClInclude Include="..\snake.h" />
<ClInclude Include="..\sounds.h" />
<ClInclude Include="..\st_stuff.h" />
<ClInclude Include="..\s_sound.h" />
@ -400,11 +415,7 @@
<ClCompile Include="..\deh_soc.c" />
<ClCompile Include="..\deh_lua.c" />
<ClCompile Include="..\deh_tables.c" />
<ClCompile Include="..\d_clisrv.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="..\f_finale.c" />
<ClCompile Include="..\f_wipe.c" />
@ -427,10 +438,6 @@
<ClCompile Include="..\u_list.c" />
<ClCompile Include="..\hu_stuff.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="..\lua_baselib.c" />
<ClCompile Include="..\lua_blockmaplib.c" />
@ -451,8 +458,6 @@
<ClCompile Include="..\lua_thinkerlib.c" />
<ClCompile Include="..\lzf.c" />
<ClCompile Include="..\md5.c" />
<ClCompile Include="..\mserv.c" />
<ClCompile Include="..\http-mserv.c" />
<ClCompile Include="..\m_aatree.c" />
<ClCompile Include="..\m_anigif.c" />
<ClCompile Include="..\m_argv.c" />
@ -466,6 +471,22 @@
<ClCompile Include="..\m_perfstats.c" />
<ClCompile Include="..\m_queue.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_enemy.c" />
<ClCompile Include="..\p_floor.c" />
@ -510,6 +531,7 @@
<ClCompile Include="..\r_textures.c" />
<ClCompile Include="..\r_things.c" />
<ClCompile Include="..\screen.c" />
<ClCompile Include="..\snake.c" />
<ClCompile Include="..\sounds.c" />
<ClCompile Include="..\string.c" />
<ClCompile Include="..\st_stuff.c" />

View file

@ -156,24 +156,12 @@
<ClInclude Include="..\doomtype.h">
<Filter>D_Doom</Filter>
</ClInclude>
<ClInclude Include="..\d_clisrv.h">
<Filter>D_Doom</Filter>
</ClInclude>
<ClInclude Include="..\d_event.h">
<Filter>D_Doom</Filter>
</ClInclude>
<ClInclude Include="..\d_main.h">
<Filter>D_Doom</Filter>
</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">
<Filter>D_Doom</Filter>
</ClInclude>
@ -279,9 +267,6 @@
<ClInclude Include="..\filesrch.h">
<Filter>I_Interface</Filter>
</ClInclude>
<ClInclude Include="..\i_addrinfo.h">
<Filter>I_Interface</Filter>
</ClInclude>
<ClInclude Include="..\i_joy.h">
<Filter>I_Interface</Filter>
</ClInclude>
@ -306,12 +291,6 @@
<ClInclude Include="..\keys.h">
<Filter>I_Interface</Filter>
</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">
<Filter>LUA</Filter>
</ClInclude>
@ -372,6 +351,54 @@
<ClInclude Include="..\m_swap.h">
<Filter>M_Misc</Filter>
</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">
<Filter>O_Other</Filter>
</ClInclude>
@ -465,6 +492,9 @@
<ClInclude Include="..\v_video.h">
<Filter>R_Rend</Filter>
</ClInclude>
<ClInclude Include="..\snake.h">
<Filter>M_Misc</Filter>
</ClInclude>
<ClInclude Include="..\sounds.h">
<Filter>S_Sounds</Filter>
</ClInclude>
@ -639,21 +669,9 @@
<ClCompile Include="..\deh_tables.c">
<Filter>D_Doom</Filter>
</ClCompile>
<ClCompile Include="..\d_clisrv.c">
<Filter>D_Doom</Filter>
</ClCompile>
<ClCompile Include="..\d_main.c">
<Filter>D_Doom</Filter>
</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">
<Filter>D_Doom</Filter>
</ClCompile>
@ -732,18 +750,9 @@
<ClCompile Include="..\filesrch.c">
<Filter>I_Interface</Filter>
</ClCompile>
<ClCompile Include="..\i_addrinfo.c">
<Filter>I_Interface</Filter>
</ClCompile>
<ClCompile Include="..\i_tcp.c">
<Filter>I_Interface</Filter>
</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">
<Filter>LUA</Filter>
</ClCompile>
@ -831,6 +840,48 @@
<ClCompile Include="..\m_random.c">
<Filter>M_Misc</Filter>
</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">
<Filter>M_Misc</Filter>
</ClCompile>
@ -954,6 +1005,9 @@
<ClCompile Include="..\v_video.c">
<Filter>R_Rend</Filter>
</ClCompile>
<ClCompile Include="..\snake.c">
<Filter>M_Misc</Filter>
</ClCompile>
<ClCompile Include="..\sounds.c">
<Filter>S_Sounds</Filter>
</ClCompile>

View file

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

View file

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

View file

@ -21,7 +21,7 @@
#include "SDL_ttf.h"
#include "../doomdef.h"
#include "../doomstat.h"
#include "../d_netfil.h"
#include "../netcode/d_netfil.h"
#include "../filesrch.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 "d_main.h"
#include "d_netfil.h"
#include "d_clisrv.h"
#include "netcode/d_netfil.h"
#include "netcode/d_clisrv.h"
#include "dehacked.h"
#include "r_defs.h"
#include "r_data.h"

View file

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